實時消息架構推送設計(Socket 實現)?

請各位牛人指點:
系統分為三部分,現在有客戶A端,消息交換伺服器集群B端(包含B1,B2,B3等伺服器),緩存伺服器C端。
現在的流程是小明和小新兩人都建立到消息交換伺服器集群B端的連接(都通過socket的方式建立tcp連接),並且記錄兩人分別所處的位置情況(比如小明在B1,小新在B2)到緩存伺服器C端中,客戶A端中的小明向網路中的小新推送問候消息。
該消息發送流程是,首先小明通過TCP連接發送該消息到消息伺服器集群B端,然後消息伺服器B端在緩存伺服器C端中獲取小新TCP連接所在的消息交換伺服器中的位置,然後B1和B2伺服器進行交流,以便小新能夠及時接受到消息。
請問怎樣設計B1和B2伺服器之間的交流方式呢?我們主要是考慮消息實時性能。
如果有更好的架構模式,非常感謝能夠提出來。


推薦題主了解下MQTT 和 XMPP協議。 網路上有很多開源的實現方案。
上述兩個協議都是移動端消息推送協議, 剛好畢業設計與實習是做相關的東西, 所以做了點技術調研,分享給題主。

看問題題主應該是想要實現移動端的即時通信。
首先,大概把系統分為以下兩個模塊。
1.消息推送模塊
http://2.IM的業務模塊

關於消息推送模塊
如果題主的需要是公司的項目的話嗎,我建議消息推送模塊使用第三方推送,國內的第三方推送平台已經很成熟,諸如 JPush極光推送, 騰訊信鴿推送,個推-安卓Android推送_IOS推送

如果你是純粹個人項目想實現一個簡單的推送系統的話,建議你可以參考一下 蘑菇街TeamTalk
大旨是要解決幾個問題(我只簡單了解下, 實際開發中還有很多難題需要解決):

  • 客戶端如何持續保持與服務端的長連接。
    • 也就是心跳機制,在WIFI,2G,3G,4G環境下的心跳間隔, 額外觸發心跳的機制(切換網路環境,擦入電源線,切換基站?)
    • 心跳機制是主要影響app耗電的一個問題
    • Android上的定時機制,AlarmManager和Timer的區別
  • 服務端緩存離線客戶端的消息機制
    • 客戶端難免有時會離線,登出, 服務端應該如何緩存客戶端的信息, 緩存多少等等。
  • 伺服器宕機後,重新啟動後大量客戶端同時連接客戶端的解決方案, 雪崩效應

還有N多問題,記錄在筆記中還未總結,以後用空補上。

關於IM的業務模塊
這點沒什麼好說的, 純粹的業務邏輯, 消息的接收與展示。
因為我也是剛剛開始, 計劃中大致把該模塊分為 聊天邏輯模塊好友關係模塊 歷史消息模塊
, 其中聊天模塊的相對獨立的模塊, 作為整個系統的核心, 其他好友關係模塊與歷史消息模塊都是非必須可插拔的。 模塊間基於介面編程。

對於客戶端而已,服務端是透明的,也就是客戶端A給客戶端B發送信息, 首先是客戶端A通過HTTP請求像把消息發送給服務端,服務端通過Push,將消息原封不動地推送給客戶端B。 服務端純粹的一個轉發通道。而客戶端間以一套雙方已經約定的協議來解析接收到的消息並處理。

以上的項目的架構只是簡單構思下, 具體實現的合理性還有待討論。 其實網上已經完整的IM解決方案,上述的TeamTalk, 還有環信即時通訊雲, 容聯雲通訊, AVOS等 . 題主可以根據自己的需要選擇解決方案

最後分享下一篇關於各種Android消息解決方案的分類總結。

本文主旨在於,對目前Android平台上最主流的幾種消息推送方案進行分析和對比,比較客觀地反映出這些推送方案的優缺點,幫助大家選擇最合適的實施方案。

方案1、使用GCM服務(Google Cloud Messaging)
簡介:Google推出的雲消息服務,即第二代的G2DM。
優點:Google提供的服務、原生、簡單,無需實現和部署服務端。
缺點:Android版本限制(必須大於2.2版本),該服務在國內不夠穩定、需要用戶綁定Google帳號,受限於Google。

方案2、使用XMPP協議(Openfire + Spark + Smack)
簡介:基於XML協議的通訊協議,前身是Jabber,目前已由IETF國際標準化組織完成了標準化工作。
優點:協議成熟、強大、可擴展性強、目前主要應用於許多聊天系統中,且已有開源的Java版的開發實例androidpn。
缺點:協議較複雜、冗餘(基於XML)、費流量、費電,部署硬體成本高。

方案3、使用MQTT協議(更多信息見:MQTT: MQ Telemetry Transport)
簡介:輕量級的、基於代理的「發布/訂閱」模式的消息傳輸協議。
優點:協議簡潔、小巧、可擴展性強、省流量、省電,目前已經應用到企業領域(參考:Software - runtimes, APIs and libraries for MQTT),且已有C++版的服務端組件rsmb。
缺點:不夠成熟、實現較複雜、服務端組件rsmb不開源,部署硬體成本較高。

方案4、使用HTTP輪循方式
簡介:定時向HTTP服務端介面(Web Service API)獲取最新消息。
優點:實現簡單、可控性強,部署硬體成本低。
缺點:實時性差。


分享一下 技術大牛 @張虎 在 InfoQ 的Arch Summit 上做的演講實時系統架構與實踐 ,視頻比較長但是十分值得一看。
裡面提到了海量用戶接入-負載均衡問題,用Ticket Service動態分配接入點,延時最小化,運維成本最低化的解決辦法。還有搭建千萬級並發量的實時系統的主邏輯建設,前端伺服器建設以及架構語言的考慮以及不同語言比較。
這視頻能回答很多題主的問題。


呃,第一次在知乎上回答問題。因為是我的老闆 @徐海峰 邀請的,不回答的話獎金就沒有了。

我們Worktile企業版的消息服務基本上就是你說的結構。服務端是http://Socket.io的集群,供客戶端(Web、移動端)連接。集群後面是一個Redis伺服器,保存集群中每個節點(我們稱之為Cluster)連接的客戶端ID。同時Redis裡面為每一個Cluster分配了一個隊列,保存要推送到這個Cluster的消息。

當有消息從某個客戶端發出後,所連接的Cluster從Redis裡面獲取這個消息的目標客戶端ID(由於我們同時支持一對一私聊和群組,因此一條消息可能會被推送到多個客戶端),然後把消息Push到每個Cluster的消息隊列裡面。

每一個Cluster都會以阻塞方式讀取它所對應的消息隊列,一旦發現有消息,就獲取並且查看其目標客戶端ID是不是連接在這個Cluster上。如果是,就通過http://Socket.io發送;如果不是就丟棄。然後繼續阻塞讀取,知道下一條消息到達。

PS:我們之前使用過XMPP,但是如果是產品開發,要考慮XMPP是基於Erlang語言寫的。如果需要二次開發,目前市面上Erlang工程師不是很多。

PPS:對於Cluster間如何互通,也可以考慮使用Redis的Pub/Sub。如果沒有特殊的場景,推薦用http://Socket.io自帶的 GitHub - socketio/socket.io-redis: Adapter to enable broadcasting of events to multiple separate socket.io server nodes. 我們Worktile基礎版的消息服務就是基於這個組件實現的Cluster之間消息通知。或者讓Cluster之間通過TCP協議通信。不過在高並發的情況下,需要考慮TCP包的分割合併問題,因此不是特別推薦。


個人感覺同構的系統比較好,進程間通信協議跑在可靠的網路層就好了。


b端不要直接通訊,應該在b後面有個單獨的推送伺服器d。
客戶a1發的消息到達b1之後被轉發給d,d從c中找到a2的接入伺服器b2,然後將信息推給b2,b2再轉發給a2。


分享一下,Worktile 技術大牛 浩哥 發表在CSDN的技術貼 Worktile中百萬級實時消息推送服務的實現-CSDN.NET 更多技術博客可見 https://worktile.com/tech


IRC伺服器是不是符合題主要求?


可以參考3gpp 的ims 架構,應用層sip協議,傳輸層走udp協議。


上mq,為每一個個體(可能是一個人,也可能是一個設備)劃分一個獨立的channel。確認要發送的信息,推入對應的channel。

而決策推送什麼,在負載不壓垮集群的情況下,則應該儘可能地集中在一台或少數伺服器上,減少決策途中信息交換的媒介。


我同事跟我推薦說關於做web實時推送方面,Goeasy很不錯,代碼簡潔易懂,幾分鐘自己可以寫一個demo,中英文都有,也不存在說看不懂的情況,大家可以登陸GoEasy | Free web message push service試一下;


可以再B集群後做層代理,這樣所有連接B的客戶端就能通信了


單純就問題而言, 請問怎樣設計B1和B2伺服器之間的交流方式? B1和B2可以看做是集群中的兩個節點,節點與節點互相發消息的方式,去處理後面的服務。大致可表述為:C2S -&>S2S -&>S2C. 對於erlang而言,兩個server的節點發消息是可以搞定的.


其實不需要緩存的c端,client和broker的協議使用mqtt或者xmpp,然後再實現一個broker到broker的通訊協議,當小明發送數據給小新的時候數據先被發送到小明所在的broker,broker在自己的客戶端列表中尋找是否有小新,如果不存在小新,則向相鄰的broker查詢是否有小新,同時相鄰節點沒有的話會繼向它自己相鄰的節點查詢,不過這個過程需要考慮到環路和網路風暴消息路由的ttl等問題,相對使用你說的方案,能夠起到去中心化的作用,不過實現難度要大一些,其實這就是互聯網的簡易模型了。


關注,最近也準備做個這個,純粹好玩,分別了解了xmpp,mqtt,Web socket


請使用開源中間件,不用造輪子


推薦閱讀:

TAG:推送Push | Socket | 伺服器架構 |