标签:
一、协议
选则什么样的协议主要从以下几点考虑。
1.跨平台通用性
如果追求高通用性,比如自己的im服务器可以与msn、gtalk等实现互通那么可以使用xmpp协议。
2.性能
基于xml、json等格式的文本协议,协议本身臃肿。因为需要有描述性的信息来标识每个字段的含义,
但是这种协议扩展性好。
例如 A给B发消息可以定义成下面这样
{ "type": "chat", //代表是一条聊天消息 "from": "A", "to": "B", "message": "hello" }
如果换成自定义的二进制协议,服务器与客户端通过约定每个字段出现的先后顺序,顺序解析每个字段的内容,
就不再需要每个字段的描述信息,协议本身就会轻盈很多。特别是对于移动端的应用,对流量很敏感,这种协
议就会有较明显的优势。
二、分布式(集群)
无论是出于承载上限考虑还是出于容灾、健壮性考虑,最有效的方法莫过于建立集群。
一旦建立了集群,用户就会分散到不同的节点,不同节点上的用户如何定位到对方从而互发消息?这里有两种方式。
第一种,所有节点数据同步。
大型im系统一般都会有自己的缓存系统,很多nosql数据库(redis、mongo、mnesia等)都可以用来实现这个缓存。
可以把在线用户及其所在的节点等信息保存在缓存中。当一个用户A登陆时,会把这个用户及其所登录的节点信息同步
到所有的节点。有了这个数据,任何节点上的用户都知道如何找到A用户,从而给其发消息。最外面可以使用一个负载
均衡设备,将用户分散到不同节点。这种方式的缺点是,数据同步消耗性能,同时数据冗余也使得内存占用高一些。
第二种,使用hash把用户分散到不同的节点。
这种方法不需要数据同步,每个节点只保存登陆到本节点上的用户数据。用户每次登陆可以根据自己的uid进行hash,
计算出属于自己的节点。当用户给其他用户发送消息时,服务器根据目标用户uid使用相同的hash算法计算出目标用户
所在节点。为了在增减节点数量时对整个系统的影响降低,可以使用一致性哈希。
这种方式的缺点是当出现单点故障,故障节点用户数据需要在其它节点重新构建,瞬间可能会给其它节点带来较大压力,
同时可能也会造成某些数据永久性丢失。
三、避免消息丢失
im系统核心业务是处理消息的转发,丢消息是无法容忍的。保证不丢消息的关键是,服务器如何判断一条消息是否被客户端所收到了。
这个判断标准是关键。
不能根据用户在线状态进行判断,因为服务器所感知的用户在线状态是不准确的无论采用什么办法。唯一确定客户端已经
收到消息的办法就是要求客户端在收到一条消息后给服务器发送一个ack,服务器接收到ack时可以确定该条消息客户端收到了。
那么用户A给用户B发消息的处理逻辑应该这个样子:
A发送消息到服务器,服务器存储该消息同时转发该消息给B,当收到B的ack时,把消息删除或转移到消息备份表。
如果B不在线,那就等到B上线时推送所有属于B的消息给B,B客户端受到消息后,向服务器发送ack。服务器接收到ack删除或转移消息。
四、webim
实现webim有几种方式,这几种方式的不同主要体现在服务器如何把消息推送给浏览器客户端。
我知道的方式有轮询拉取、websocket、bosh等。
轮询拉取顾名思义,客户端启动定时器,定时向服务器发送http请求来获取消息,性能不好。
websocket与cs结构的处理方式差不多。但不是所有浏览器都支持websocket。
我更喜欢的是bosh这种方式。简单理解bosh的原理就是,浏览器客户端向服务器发送http请求,服务器接到请求后并
不马上返回,而是在服务器内部等待消息到来,当有消息了就返回body为消息内容的response,或者达到超时时间
仍没有发送给该用户的消息到达也,服务器会返回一个body为空的response。客户端在收到response后再次发起request,
服务器再次hold住这个请求等待消息到来,如此这般。这种方式我是从xmpp当中学来的。
想要深入了解可以看 这里
五、快速搭建
如果你想要快速搭建起来,那当然是找开源了。
我推荐ejabberd,理由有
1.并发性能良好。
我在16G内存的服务器上跑到30W并发量无掉线的情况,用了多台机器跑客户端,最后机器不够用就只能压到30W了。
根据内存上涨趋势看,大概1G内存能承载5万在线用户(其中我们自己的代码有很大可优化余地)。
2.较成熟,配套齐全。
我曾在github上找了个js开发xmpp客户端,拿来就可以直接用。就是一个基于bosh的xmpp客户端。
如果把这个网页版的客户端嵌入到ios、andriod等应用和pc客户端上,再部署一个ejabberd,那么可
能本来需要好几个小组开发半年的产品,被一个人花一个星期就搞了个大概。
还有原生erlang开发的压力测试工具tsung,直接拿过来压一压。
3.好扩展,ejabberd内部提供了很多hook,为扩展开发ejabberd插件提供了方便。另外插件(模块)可通过配置文件定制,动态加载,选择自己需要的加载。
4.除了上面这些,erlang语言本身的容错等特性就不多说了。
附:
https://github.com/processone/ejabberd ejabberd
https://github.com/erlang-synrc/xmpp.js xmpp客户端
https://github.com/processone/tsung tsung 压力测试工具
标签:
原文地址:http://www.cnblogs.com/bohai/p/4315786.html