Erlang 语言的很多特性,决定了它开发服务器端(Server)的程序极其地方便,故此,基于 Erlang 的各种服务应用正雨后春笋般涌现。这里我们就大家最熟悉的 Web 开发展开话题。考虑到 Erlang 并不广为人知,这里以脱盲为主,如果某个话题引起你的兴趣,建议你参考相关文档继续深入下去。有任何希望讨论的地方,可以在 erlang-china 或 ecug 这两个 google groups 中讨论。本文重点介绍的是 Yaws 和 MochiWeb,其他内容做概要介绍。
Erlang
编译与安装
- 下载 Erlang
wget http://erlang.org/download/otp_src_R12B-2.tar.gz
- 安装 bison, flex, openssl, ncurses
sudo apt-get install bison sudo apt-get install flex sudo apt-get install libssl-dev sudo apt-get install ncurses-dev
- 编译 erlang/otp
tar zxvf otp_src_R12B-2.tar.gz cd otp_src_R12B-2 ./configure sudo make install
Inets httpd
之所以首先介绍 Inets httpd 服务器,是因为这是 Erlang OTP 自带的 Web Server。我们知道 Erlang OTP 是一个平台,而不止是一个语言。它带有很多管理用的小工具,多数情况下这些工具以 Web 方式提供。而这些工具通常是基于 Inets httpd 的。
用Inets httpd你会觉得和Apache有点象。确实如此。我曾经写了一篇文章介绍 Inets httpd,这里不在重复,欲了解请参阅:http://erlana.googlecode.com/svn/trunk/doc/Erlang%20Inets/。
Yaws
Yaws(http://yaws.hyber.org/)是目前通 用 Erlang Web Server 中最为名声显赫的一个,也是文档最为丰富的一个。Yaws 本身带的文档和样例都很详细,我这里另辟蹊径,将 Yaws 和我们通常所说的 LAMP (Linux + Apache + MySQL + PHP)作为比照,来一个 LYMP (Linux + Yaws + MySQL + PHP)开发。
需要说明的是,LYMP 并不是 Yaws 最为推崇的开发模式,只是因为它是大家最为熟悉的一条路子。其实 Yaws 本身和 Inets httpd 一样的思路,它倾向于一切都使用 Erlang 语言,即 LYME(Linux + Yaws + Mnesia + ErlScript)开发:用 Yaws 做 Web Server,用 Erlang Script(*.yaws)写页面,用 Mnesia 来做数据存储。LYME 虽然和 LYMP 只差一个字母,但是此 M 非彼 M,两者大相径庭。
编译与安装
- 下载 yaws, openpam
wget http://yaws.hyber.org/download/yaws-1.77.tar.gz wget http://nchc.dl.sourceforge.net/sourceforge/openpam/openpam-20071221.tar.gz
- 编译/安装 openpam
tar zxvf openpam-20071221.tar.gz cd openpam-20071221 ./configure sudo make install
- 编译/安装 yaws
tar zxvf yaws-1.77.tar.gz cd yaws-1.77 vi c_src/epam.c,修改其中的 #include <pam_appl.h> 为 #include <security/pam_appl.h> ./configure sudo make install
Yaws + PHP
- 安装php cgi
sudo apt-get install php5-cgi
- 修改Yaws配置(sudo vi /usr/local/etc/yaws.conf)
php_exe_path = /usr/bin/php-cgi #加入这行,为了让yaws找到php ... <server xxxx> port = 80 listen = 0.0.0.0 allowed_scripts = php yaws cgi #加入这行,以便在该虚拟主机(server)中启用php cgi .... </server>
- 测试PHP支持:在 /usr/local/var/yaws/www 目录下,创建 test.php,内容如下:
echo"Hello, PHP!/n";
- 启动Yaws(命令行:sudo yaws -i),然后在浏览器地址栏输入 http://127.0.0.1/test.php,如果显示"Hello,PHP",那么恭喜你,你已经可以在 Yaws 这个Web服务器下写 PHP 了。
LYMP: Linux + Yaws + MySQL + PHP
有了PHP的支持,剩下来的问题可能是数据库(Database)了。但其实这个问题和Yaws关系不大。只要你安装了MySQL,并且PHP安装了MySQL扩展,就可以用 LYMP 进行 Web 开发了。
LYME v.s. LYMP
LYMP 优势:和大家熟悉的 LAMP 最接近,而且可以无缝切换。Web Server 是 Yaws,还是 Apache,或者是甚至是 IIS? 基本不会对我们的开发产生太多的影响。而劣势是,Erlang 的优势在这里的体现并不明朗。因为一般 Web 服务器的瓶颈主要在数据库(Database)上,前端的 Web Server 就算有瓶颈,一般也用负载均衡(LB)搞定,看起来不需要动用 Erlang。
LYME优势:压力最重的数据库使用 Mnesia 这个分布式数据库来降低成为热点的可能性(当然具体还是会取决于你的设计)。而劣势是,对传统的 Web 开发人员而言,所有的东西都是新的,学习的成本过高。
ErlyWeb
ErlyWeb(http://code.google.com/p/erlyweb/) 基于 Yaws,但是它倾向于 Linux + Yaws + MySQL + ErlTL 开发。也就是说,数据库用传统的 MySQL,其他用 Erlang 进行开发。ErlyWeb 的作者对 Erlang 的兴致很高,主导了多个 Erlang 开源项目。而最引入瞩目的一个,可能要算 twoorl (http://code.google.com/p/twoorl/): 它是一个开源的仿 Twitter 程序,并且是一个很好的基于 ErlyWeb 的样例。
MochiWeb
MochiWeb 是 MochiBot.com 公司的 Bob Ippolito 贡献的开源项目。 MochiBot.com 提供 Flash 内容的访问统计和用户跟踪服务(你可以理解为这是针对 Flash 的 Google Analytics 服务),它们在 MochiWeb 之上构建了一个定制化的 Web Server,并通过这个 Web Server 获取用户的访问数据(在这一点上有点象我发起的 Erlana 项目)。由于 Analytics 服务的特殊性,你可以想象,这个 Web Server 需要很高的并发支持。 MochiWeb 因此应运而生。 它针对的不是大家普遍意义上理解的 Web 开发。和传统的 LAMP 很不一样,你甚至可以不把它看作一个 Web Server,因为它几乎没有任何 Web 开发所有常用的基础设施。
但是 MochiWeb 最大卖点是非常轻量(高并发)而灵巧(易于定制),在特殊的场景下非常有用。目前 MochiWeb 已知的或者可以预见的应用包括:
- Facebook 的 Web Chat(http://yoan.dosimple.ch/blog/2008/05/15/)
- CouchDB(http://www.javaeye.com/news/459)
- Erlana: Web Analytics服务(http://code.google.com/p/erlana/)
- XXX Open Web API(RESTful): 为了提供Web API,你没有必要为此搭建一个通常意义的 Web Server。
Comet Programming: Web Chat
Comet 是一项很时髦的技术。其目的很简单:由于历史原因,目前 HTTP 协议信息都是客户端向服务器要(Poll),服务器没有办法推送信息给客户端(Sever Push)。这在实现某些应用的时候就会遇到麻烦。例如:
- 当邮件服务器收到新的邮件时,及时报告给用户,如果他在线的话(GMail 这样做了)
- 当 Web Chat 服务器收到新的信息时,及时发送信息到相应的在线用户(Web Chat 的基本需求)。
- 聊天时提示你对方正在输入(时下 IM 客户端很时髦的一个功能)。
这里让我们假想要做一个 Web Chat。一个最笨的方法,就是客户端隔一段时间就向服务器请求(Request)一次,看看有没有新的信息,如果有则取回新信息,没有那么这次的请求就浪费了。这个方法无端增加了网络流量和服务器的负荷,显然并不可取。
那么 Comet 是如何做的呢? 有两种实现方式,一种叫 Streaming,一种叫 Long Polling。这里我们介绍后者。简单来说,Long Polling 就是客户在初始化的时候向服务器发送一个请求(建立连接),该请求到服务器那里后被阻塞,直到有事件发生后才返回,客户端在获得事件并处理后,再重新建立 一个新连接,如此反复。由于请求在没有事件的时候并不马上返回,这就大大减少了网络流量。当然这里有个细节,就是超时处理。因为现在路由器和防火墙都会自 动断开时间比较长的连接。关于 Comet 技术更多的消息,可以参阅 http://cometdaily.com/。
Comet 技术对服务端的要求还是很高的,Long Polling减少了网络流量,但是服务端的连接数并没有减少。因此基于 Comet 的应用,很容易在 Scale(伸缩性)上出现问题。使用 Erlang + MochiWeb,还是很好的利用了 Erlang 可以轻松建立大量连接这个特性。需要指出的是,很可能 Comet 应用的时髦,将会很大程度上促进了业界对 Erlang 的关注。
基于 Erlang 的 Web Chat,Facebook 做了一个。这里有网上某人对 Facebook 之 Web Chat 的“模仿版”。研究这个 Web Chat,你将更清晰如何进行 Comet 编程:
下载并编译MochiWeb
svn co http://mochiweb.googlecode.com/svn/trunk mochiweb #取得mochiweb源码 cd mochiweb make MOCHIWEB=`pwd`
Minimal Web Chat
wget http://yoan.dosimple.ch/blog/2008/05/15/chat.tgz tar zxvf chat.tgz cd chat/deps ln -s -f $MOCHIWEB mochiweb-src cd .. make ./start.sh
这样,在 http://localhost:8000/ 就启动了一个 WebChat Server。你可以从多台机器连接该 Server进行聊天。
Template Engine for Erlang
虽然 Erlang 和传统的 Web 开发模式是可以结合的(如上面的 LYMP),但是多数基于 Erlang 的开发似乎并不打算这样做。既然已经用了 Erlang,一个纯的 Erlang 应用也许是个更不错的主意。但是既然倾向于用 Erlang 取代 PHP/JSP 来作为脚本引擎,那么基于 Erlang 的 Template Engine(模板引擎)就少不了了。目前基于 Erlang 的主要 Template Engine 如下:
- ErlTL(http://code.google.com/p/erlyweb/):是 ErlyWeb 作者专门为 Erlang Web 开发制作的模板引擎。
- ErlyDTL(http://code.google.com/p/erlydtl/):基于著名的 Django Template Language(Python)的 Erlang 移植版。
- sgte(http://code.google.com/p/sgte/):基于 StringTemplate(Java)的 Erlang 移植版。
- Yaws ErlScript(http://yaws.hyber.org/):该模板引擎没有正式命名,姑且称之为Yaws ErlScript。类似 PHP,一个正常的 HTML 页面是一个合法的 Yaws ErlScript 文件。它通过在正常 HTML 中接入特殊标签,然后插 Erlang 脚本代码实现动态页面。