在团队协同工具worktile的使用过程中,你会发现无论是右上角的消息通知,还是在任务面板中拖动任务,还有用户的在线状态,都是实时刷新。Worktile中的推送服务是采用的是基于xmpp协议、erlang语言实现的ejabberd,并在其源码基础上,结合我们的业务,对源码作了修改以适配我们自身的需求。另外,基于amqp协议也可以作为实时消息推送的一种选择,踢踢网就是采用rabbitmq+stomp协议实现的消息推送服务。本文将结合我在worktile和踢踢网的项目实践,介绍下消息推送服务的具体实现。
实时推送的几种实现方式
相较于手机端的消息推送(一般都是以socket方式实现),web端是基于http协议,很难像tcp一样保持长连接。但随着技术的发展,出现了websocket, comet等新的技术可以达到类似长连接的效果,这些技术大体可分为以下几类:
-
短轮询。页面端通过js定时异步刷新,这种方式实时效果较差。
-
长轮询。页面端通过js异步请求服务端,服务端在接收到请求后,如果该次请求没有数据,则挂起这次请求,直到有数据到达或时间片(服务端设定)到,则返回本次请求,客户端接着下一次请求。示例如下:
- Websocket。浏览器通过websocket协议连接服务端,实现了浏览器和服务器端的全双工通信。需要服务端和浏览器都支持websocket协议。
以上几种方式中,方式1实现较简单,但效率和实时效果较差。方式2对服务端实现的要求比较高,尤其是并发量大的情况下,对服务端的压力很大。方式3效率较高,但对较低版本的浏览器不支持,另外服务端也需要有支持websocket的实现。Worktile的web端实时消息推送,采用的是xmpp扩展协议xep-0124 BOSH(http://xmpp.org/extensions/xep-0124.html),本质是采用方式2长轮询的方式。踢踢网则采用了websocket连接rabbitmq的方式实现,下面我会具体介绍如何用这两种方式实现Server Push。
运行时环境准备
服务端的实现中,无论采用ejabberd还是rabbitmq,都是基于erlang语言开发的,所以必须安装erlang运行时环境。Erlang是一种函数式语言,具有容错、高并发的特点,借助OTP的函数库,很容易构建一个健壮的分布式系统。目前,基于erlang开发的产品有,数据库方面:Riak(Dynamo实现)、CouchDB, Webserver方面:Cowboy、Mochiweb, 消息中间件有rabbitmq等。对于服务端程序员来说,erlang提供的高并发、容错、热部署等特性是其他语言无法达到的。无论在实时通信还是在游戏程序中,用erlang可以很容易为每一个上线用户创建一个对应的process,对一台4核8个G的服务器来说,承载上百万个这样的process是非常轻松的事。下图是erlang程序发起process的一般性示意图:
如图所示,Session manager(or gateway)负责为每个用户(uid)创建相对应的process, 并把这个对应关系(map)存放到数据表中。每个process则对应用户数据,并且他们之间可以相互发送消息。Erlang的优势就是在内存足够的情况下创建上百万个这样的process,而且它的创建和销毁比java的thread要轻量的多,两者不是一个数量级的。
好了,我们现在开始着手erlang环境的搭建(实验的系统为ubuntu12.04, 4核8个G内存):
1、依赖库安装
sudo apt-get install build-essential
sudo apt-get install libncurses5-dev
sudo apt-get install libssl-dev libyaml-dev
sudo apt-get install m4
sudo apt-get install unixodbc unixodbc-dev
sudo apt-get install freeglut3-dev libwxgtk2.8-dev
sudo apt-get install xsltproc
sudo apt-get install fop tk8.5 libxml2-utils
2、官网下载otp源码包(http://www.erlang.org/download.html), 解压并安装:
\>\> tar zxvf otpsrcR16B01.tar.gz
\>\> cd otpsrcR16B01
\>\> configure
\>\> make & make install
至此,erlang运行环境就完成了。下面将分别介绍rabbitmq和ejabberd构建实时消息服务。
基于RabbitMQ的实时消息服务
RabbitMQ是在业界广泛应用的消息中间件,也是对AMQP协议实现最好的一