阿赞 2012-03-26
Presence处理是IM Server的核心,也是一个IM Server最复杂的部分。一个用户的状态发生变化,需要通过服务器自动投递给他所有在线的好友,因此Presence模块实际上等同一个消息处理服务器,可参看以前消息服务器相关文章ActiveMQ性能研究及与memcacheq比较。
Presence的复杂性体现在:
1.由于每个用户都有1到多个好友,服务器的处理量被放大。
2.分布式处理的复杂度,你的好友可能同时分布在n个服务器上,而且同时上线的好友没有规律。
3.请求量不均衡,可能瞬时非常大。比如你服务器刚重启所有的客户几乎同时自动重连过来。比如Twitter宕机都是在一些热点事件时,大家活跃度突然同时增大。所以系统必须按峰值的处理量设计。
4.缓存cache设计困难。每个用户的在线好友都不同,而且随时在变。
5.隐身同黑名单的业务逻辑很难高效处理。
OpenfireServer处理presence的流程如下,以3.6.0为准。
1.ConnectionHandler.messageReceived();
mina层面处理。
2.StanzaHander.process()=>processPresence
xmpp层面。处理所有xmpp包的方法,实际上只有login相关包在这里处理。其他类型的包交由相关逻辑类来处理。由于是个presence包,交由下面presence逻辑处理模块进行。(alsoaddfromtopacket)
3.PacketRouteImpl.route()//routepresence
4.PresenceRoute.route()=>handle()//routepresence
由于presence是一个需要路由的包,路由主要区分目标是本机还是远程,是component/server还是普通用户。
5.PresenceUpdateHandler.process()=>broadcastUpdate
//process()updatedbandupdatecache,
callsPresenceManager.userAvaliable();session.setPresence()...
6.Roster.broadcastPresence();
检查privacylist(隐身及黑名单用户)然后路由给所有在线好友。
7.RoutingTable.routePacket,routeTable.getRoutes()
真正的工作在这里,较慢。
8.session.process(),session.deliver
已经分发到相关用户了,调用该用户的session投递给此用户
9.nioconnection().deliver,delivertotheendusers
再回到MINA
因此Presence投递工作的核心是在6~7,不过其他的步骤也有不少细节的处理。Openfire中6~7的实现比较精简和优雅,但如果想作为一个大型的高效消息投递系统还是有改进的空间