有過幾款IM系統開發經歷,目前有一款還在線上跑著。準備簡單地介紹一下大型商業應用的IM系統的架構。設計這種架構比較重要的一點是低耦合,把整個系統設計成多個相互分離的子系統。我把整個系統分成下面幾個部分:(1)狀態消息系統 ? (2)好友系統 ? (3)P2P系統??? (4)其他擴展業務系統
先看狀態消息系統
?????????????????????
connd?
???????? client接入服務器,可以支持UDP,也可以支持TCP,一般建議優先選擇TCP。connd可以布置多臺,client接入時,可以用簡單的DNS輪詢的方式實現負載均衡。connd功能是維護連接和轉發消息包。
pconnd
????????? proxy connd, 代理接入服務器,是connd的擴展,除了有connd的功能外,支持服務器的接入,比如web server。
msgd
?????????? 消息處理服務器,主要功能是用戶狀態管理,消息轉發(包括合理性驗證)以及離線消息保存。
說一個用戶登錄成功后,對所有好友的狀態通知過程。我設計的系統中,把用戶狀態也簡單看成類似文本聊天消息。下面用戶U的上線過程,他有好友F1, F2。
(1) connd收到U上線消息,將消息發給U所在的msgd。
(2) msgd獲取U的好友,F1, F2;如果F1, F2和U不在同一個msgd上,msgd將消息通過connd轉給F1, F2所在的msgd。
(3) 最終的msgd把上線通知通過connd發給F1, F2。
msgd的U是通過什么方式獲取最新的好友呢? 這個問題我要著重描述一下。
用戶的好友數據都在另外一個子系統中:好友子系統。 msgd通過TCP的方式(為什么用TCP呢?)主動從好友系統獲取。同時,msgd也緩存一份好友數據。msgd獲取用戶好友時,如果cache是最新的,直接從cache取,否則要從好友子系統那邊取。現在重點問題出來了,如何確定用戶的好友是最新的?這類問題我們要根據不同的業務不同的特點靈活采用不同的方法。請看一種高效的處理方式:
(1) 好友子系統為每個用戶的好友算個hash值(可以用MD5)。
(2) client獲取好友時,同時也拿到這個hash值;發和好友相關的消息時,把hash值帶給msgd。
(3) msgd第一次從好友子系統獲取某個用戶好友時,也獲取這個hash值;像要轉發狀態消息,獲取好友時,把client帶過來的hash1和自身的hash2比較一下。。。
像IM這種業務特點是,對好友數據的寫很少,讀很多,相對于讀的消耗,寫基本可以忽略的。用上面的方法,基本上每次兩者的hash值是相等的,直接從cache拿好友數據。這種處理方法也可以引入到其他應用業務中。建議不要每次都粗暴地跨進程獲取類似好友數據。
好了,上面是對IM系統狀態消息子系統的簡單介紹。
另外,像好友子系統就很簡潔,啟幾個tcp接入server,根據不同用戶,去不同的好友邏輯服務器上取好友。好友邏輯服務器,可以考慮采用LRU淘汰算法(發現老用這種算法)。如果你很有錢,也可以對好友數據做全cache,不用淘汰。
P2P系統和網上介紹的架構都差不多,大家搜一把吧。