前先後後作的IM和推送系統已經有好幾個了,一直都想好好總結下,所以就有了這篇文章。在我剛學編程的那會兒,以爲網絡通訊是一個很牛逼和門檻很高的一門技術,可是隨着開源技術的發展和互聯網知識的共享,如今要寫出高質量的網絡通訊程序已經變得容易多了。sql
只要談通信確定繞不開協議,鑑於本人經驗下面只談本人擼過的三種協議:編程
轉自: http://www.yangguo.info/2015/08/17/%E6%BC%AB%E8%B0%88%E9%80%9A%E8%AE%AF%E6%9E%B6%E6%9E%84/服務器
XMPP(Extensible Messaging and Presence Protocol),也叫Jabber,它是基於穩定長鏈接網絡環境所設計的,對於不夠穩定和帶寬小的移動網絡不是很是合適。因爲XMPP基於XML,因此流量大,流量問題對於移動網絡來講很是敏感,而後就是消息不可靠、CMWAP兼容、開源項目對協議實現不完善等問題,也是XMPP面臨的問題。固然XML能夠經過精簡壓縮來實現流量可控,目前這也是XMPP優化的可行方案,消息的不可靠能夠經過擴展XMPP來實現ACK,隨着3/4G的發展,CMWAP網關畢竟是末日黃花,可是開源項目對協議只是部分實現等問題,也是使用XMPP繞不過去的坎。Openfire是XMPP領域最知名的開源項目,它簡單易用,是不少團隊的首選方案,這是國內使用最多的開源方案。Openfire雖然優勢不少,可是缺點也很多,最致命的就是它的分佈式擴展能力很弱,當用戶量很大的時候,水平擴展就成爲它的瓶頸所在。還有一個不得不提的項目就是Tigase,這是筆者接觸的第一個XMPP開源項目,它在分佈式擴展能力上和架構設計上比Openfire強了很多。因爲該項目開始是一個私人項目,如今好像在商業化,因此使用者並非不少,雖然國外有成熟案例,可是國內目前並很少,因此當時趟了Tigase的不少坑,目前平安好醫生的聊天系統就是基於此搭建的。若是對Tigase感興趣,能夠閱讀我以前寫的一篇文章《Tigase集羣方案及配置說明文檔》。不論使用哪一個開源項目,雖然看起來開箱即用,可是要成爲穩定成熟的產品,還須要深度的二次開發才行。網絡
雖然XMPP有不少弊端,可是它的生態目前是最完善的,若是從成本角度來考量,XMPP是前期投入最小產出最快的。可是若是是搭建一個SAAS平臺或者千萬量級的IM,XMPP就不是最優的選擇了。固然這是一家之言,國內外目前商業化的IM SAAS平臺有好幾家都是基於XMPP實現的,這個你們能夠自行Google。架構
MQTT是輕量級基於代理的發佈/訂閱的消息傳輸協議,它的最大特色就是協議開銷很是小,伴隨着的就是協議簡單(40多頁)、網絡帶寬要求極低和移動設備省電。有幸接觸到該協議是筆者在開發Android推送系統時,對它進行了較細緻的研究,雖然最終方案中沒有使用該協議,可是本身定製的私有協議也參考了不少MQTT的設計。MQTT整個協議的組成,能夠分爲三個部分:併發
每一個MQTT命令消息的消息頭部都包含一個固定頭部,固定頭部的格式以下:異步
Byte 1
消息類型和標誌字段分佈式
Byte 2
剩餘長度字段(至少1個字節,最多4個字節),採用big-endian模式存儲高併發
Message Type優化
1 |
0:保留 |
保證消息可靠傳輸,默認爲0,只佔用一個bit,表示是否第一次發送,它不能用於檢測消息重複發送。只適用於客戶端或服務器端嘗試重發PUBLISH, PUBREL, SUBSCRIBE 或 UNSUBSCRIBE消息,注意須要知足如下條件:
1 |
QoS > 0 |
此時,在可變頭部須要包含消息ID。當值爲1時,表示當前消息先前已經被傳送過。
該標誌位標明 PUBLISH 消息的交付質量級別:
僅針對PUBLISH消息。不一樣值,不一樣含義:
1:表示發送的消息須要一直持久保存(不受服務器重啓影響),不但要發送給當前的訂閱者,而且之後新來的訂閱了此Topic name的訂閱者會立刻獲得推送。
備註:新來乍到的訂閱者,只會取出最新的一個RETAIN flag = 1的消息推送。
0:僅僅爲當前訂閱者推送此消息。
假如服務器收到一個空消息體(zero-length payload)、RETAIN = 一、已存在Topic name的PUBLISH消息,服務器能夠刪除掉對應的已被持久化的PUBLISH消息。
這個字節包含當前消息的剩餘部分,包括變量頭部和負載的數據。
可變長度的編碼方式使用一個單獨的字節使消息能夠達到127字節的長度上限。協議限制最多4個字節,這樣程序能夠發送最大256M的消息。
上面即是最核心的固定頭部的內容,至於可變頭部和消息體能夠本身查詢資料,目前有不少公司在使用MQTT實現Android的推送,可是目前筆者暫時不知道誰家的IM在使用它。
一萬人眼中就有一萬個哈姆雷特,一樣的一萬人眼中就有一萬個私有協議。應用場景、設計風格,都會致使協議的設計千奇百怪。例如:數據量傳輸大的場景,壓縮方案可能也被設計到協議中,由於不一樣的環境可能用到不一樣的壓縮方式;傳輸質量,咱們可能就默認某一個級別,可能就從協議中移除,具體的設計得靠經驗和應用場景來設計。
一套很簡單的架構,CM只負責鏈路的管理,鏈路和用戶ID的關係維護在Redis中,SM負責業務邏輯和消息路由。CM和SM內部經過RPC調用,CM和SM內部所有采用事件驅動的方式,所有采用異步的方式。任何一個模塊均可以水平擴展,而且SM若是達到很是複雜的地步,還能夠拆分。最終的壓力基本就到了Redis和Mysql,這些高可用和高併發的方案,已經很是成熟,就不用多說了。
下圖是登陸流程和消息發送流程
鑑於筆者經驗,開發的IM最多承載用戶數也就百萬級別,因此架構上或者設計方案不必定完美,僅供參考!
注意事項