Presence處理是IM Server的核心,也是一個IM Server最複雜的部分。一個使用者的狀態發生變化,需要通過伺服器自動投遞給他所有線上的好友,因此Presence模組實際上等同一個訊息處理伺服器,可參看以前Message Service器相關文章ActiveMQ效能研究及與memcacheq比較。
Presence的複雜性體現在:
1. 由於每個使用者都有1到多個好友,伺服器的處理量被放大。
2. 分散式處理的複雜度,你的好友可能同時分布在n個伺服器上,而且同時上線的好友沒有規律。
3. 請求量不均衡,可能瞬時非常大。比如你伺服器剛重啟所有的客戶幾乎同時自動重連過來。比如Twitter宕機都是在一些熱時間點事件時,大家活躍度突然同時增大。所以系統必須按峰值的處理量設計。
4. 緩衝cache設計困難。每個使用者的線上好友都不同,而且隨時在變。
5. 隱藏同黑名單的商務邏輯很難高效處理。
Openfire Server處理presence的流程如下,以3.6.0為準。
1. ConnectionHandler.messageReceived();
mina 層面處理。
2. StanzaHander.process() => processPresence
xmpp 層面。處理所有xmpp包的方法,實際上只有login相關包在這裡處理。其他類型的包交由相關邏輯類來處理。 由於是個presence包,交由下面presence邏輯處理模組進行。(also add from to packet)
3. PacketRouteImpl.route() // route presence
4. PresenceRoute.route() => handle() // route presence
由於presence是一個需要路由的包,路由主要區分目標是本機還是遠程,是component/server還是普通使用者。
5. PresenceUpdateHandler.process() => broadcastUpdate
// process() update db and update cache,
calls PresenceManager.userAvaliable(); session.setPresence()...
6. Roster.boradcastPresence();
檢查privacy list(隱藏及黑名單使用者)然後路由給所有線上好友。
7. RoutingTable.routePacket, routeTable.getRoutes()
真正的工作在這裡,較慢。
8. session.process(), session.deliver
已經分發到相關使用者了,調用該使用者的session投遞給此使用者
9. nioconnection().deliver, deliver to the end users
再回到MINA
因此Presence投遞工作的核心是在6~7,不過其他的步驟也有不少細節的處理。Openfire中6~7的實現比較精簡和優雅,但如果想作為一個大型的高效訊息投遞系統還是有改進的空間。