Web应用中实时消息技术总结

在互联网应用中,很多时候我们需要在客户端和服务端之间进行实时的消息交互,比如下面这些常见的应用场景:

  • SNS网站用户互动消息通知(weibo/twitter/qzone)
  • 门户网站实时滚动新闻(突发事件)、文字直播(体育赛事)
  • 在线聊天室(在线客服)
  • 实时数据展示(实时股价,实时商品价格,服务器实时监控等)

接下来的内容里,我罗列了在web开发中常见的实时消息的实现技术方案,每种方案都各有优缺点,在不同的应用场景下有不同的选择。(声明:附图来源于网络,http://stackoverflow.com/questions/11077857/what-are-long-polling-websockets-server-sent-events-sse-and-comet,我上传到百度图库了:D)

###1. 客户端轮询模式(polling) 客户端定时请求服务器来询问是否有新的消息产生,这种情况下客户端每次请求都要建立一次http连接,服务器都要产生一个响应信息。

优点:实现简单,使用方便,开发成本很低,适合刚起步的小型应用或是其它方案的备用方案。
缺点:消息有延迟,网络通信消耗大(特别是移动网络下),服务器容易产生峰值请求。
实现:浏览器里用js定时请求,或是移动设备上native app里定时发http请求。

polling

###2. 长轮询模式(long polling)

客户端与服务器建立连接后,服务器并不马上返回消息,而是不断去查询后台(如:数据库)是否有新消息产生,直到有新消息产生时,服务器才返回。客户端接收响应信息处理完后关闭当前链接,并马上发起一个新的请求,继续等待服务返回新的消息,如此循环下去。所以,这个long polling也可以叫做服务端的轮询。

跟上面的polling模式相比:
优点:消息到达客户端更及时;减少了http请求不停地创建、关闭造成的不必要浪费。
缺点:服务端需要保持大量连接,http连接的维护开销较大;每次产生消息后都需要重新创建连接。
实现:客户端只要简单的发送请求,等待响应即可。服务器端需要做两方面的工作:一是保持大量的连接(Non-Blocking I/O);二是读取后台的消息更新(异步定时轮询或由事件触发)。

long polling

###3. 基于流的模式(http streaming) 在这种情况下,客户端与服务器端保持一个持久的连接,服务器端有新消息产生时通过这个持久连接不断地返回给客户端。这种模式与上面的long polling差不多,差别就是只需要创建一次连接就可以了。另外,要注意http header中需要设置Connection: keep-alive和Transfer-Encoding: chunked这两个属性。

跟上面long polling模式相比:
优点:消息可以实时到达客户端;客户端与服务端之间只需要建立一次连接。
缺点:服务器端也要维持大量连接,开销很大。
实现:客户端一般有两种方式:一是隐藏iframe的src指向服务器端url,不断地进行dom渲染;二是使用ajax里的XMLHttpRequest对象来实现。对于服务端来说,和long polling一样,要保持大量连接和处理后台的消息更新。

streaming

###4. WebSocket WebSocket是HTML5开始提供的一种浏览器与服务器间进行全双工通讯的网络技术,浏览器和服务器只需要要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。

优点:实时通讯,双向交互,节省服务器资源和带宽。
缺点:浏览器支持不足。
实现:客户端需要html5来实现,服务器端一般的web服务器都有支持。

socket

那在我们实际的应用中,上面几种方案应该怎么选择呢?

  • polling轮询机制很简单,使用方便,都是http短连接,在应用架构上跟普通接口api一致,非常适合小型应用和刚起步的应用,可以节省很多开发成本。

  • 当我们的用户量上升到一定程度后(比如日活跃百万级),产品做得越来越受欢迎了,我们对消息到达的及时性也就有更高的要求了,而且这种轮询机制对服务器压力也是一种考验,这时候我们就可以考虑long polling或http streaming的方式了,这两种方式其实在服务端实现上差不多,主要是保持大量长连接和异步(或事件触发)获取消息。在保持连接方面,在java的nio出现后,为我们提供了便利,主流的应用服务器像tomcat和jetty都有支持,但是,工作在jvm上的服务器保持大量socket连接时gc是个很严重的问题。所以,这里我要介绍一下借助nginx的push模块来实现保持连接以及消息实时推送。

    这两个模块工作在nginx上,可以维持大量的http连接,实现了pub/sub协议来支持消息发送,基本流程是下图这样的,发送者(publisher)把消息推送到nginx服务器上,然后push模块负责把消息发送给订阅者(client):

    pub/sub

    借助nginx的这个push模块,我们可以省去大量的工作,应用程序只需要关注业务逻辑(也就是publisher做的事),简化了应用架构,同时nginx的高性能也有不错的表现。

  • 当我们的产品发展到千万级的日活跃时,我们可能就要考虑更好的方案了,比如上面的提到的WebSocket,但是因为浏览器兼容的问题,这个方案并不是主流的解决方案。一般这种情况下,我们就要考虑基于tcp的socket长连接模式了,通过某种消息推送协议(xmpp/mqtt/自定议协议等)来实现客户端和服务器端的实时交互。

实时消息技术在互联网应用中很广泛,涉及的内容也很多,我这里只是做了一些概括性的总结。其实每一种业务场景都有好多细节要考虑,比如消息的传播方式(广播、单播)就对业务逻辑的处理有很大的影响。在这里,欢迎各位路过的朋友指点,分享!

参考文章:
http://zh.wikipedia.org/zh/Comet_(web%E6%8A%80%E6%9C%AF)
http://zh.wikipedia.org/wiki/WebSocket

推荐阅读: HTTP协议理解与应用总结

转载于:https://my.oschina.net/u/142836/blog/173744

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值