我們做IM系統1.0版本時,有以下幾個需求:
由于只有一周的時間,版的架構搭建得非常簡單:
服務端由PHP和NodeJS組成。PHP負責用戶賬戶,注冊和登錄。NodeJS負責長連以及進出房間和推送,做成簡單的交互。
個版本的前端服務器的結構非常簡單,功能很少,僅僅負責聯接客戶端,負責所有客戶端的聯接。為了保證H5也可以使用,因此在長連上選擇了WebSocket。
為了確??蛻舳搜菔镜臅r候,萬一崩潰了也不能被察覺,我們使用PM2守護了Node進程。同時讓客戶端同學做了個自動斷線重連。
然后登錄流程是這樣的,先從PHP獲取一個token,然后帶著這個token和Node建立連接,Node會在內網向PHP驗證token是否有效,然后建立連接。
然后廣播方面,使用了我稱作組的形式進行廣播,所有的房間和私信都是通過組的形式進行廣播。
首先,用戶在房間里發言的時候,實際上是往特定組發送廣播。組的名字是用特定字符開頭來歸類的。
舉例來說,需要向10000房間發送聊天信息時,實際上是向r:10000這個組發送信息。此時服務端會遍歷該組里所有連接,并發送消息。
當需要進行全服廣播的時候,我們使用一個寫死特殊的0號房間,轉換成GID也就是r:0發送消息。這將遍歷所有連接,向他們發送消息。
接下來是推送私聊,這里我為每個用戶都設置了一個私有的Gid,這樣發送私信的時候也相當于發送了廣播,服務端可以用相同邏輯處理。打個比方向UID 20000用戶發送私信,相當于向u:20000廣播。以后擴展成多進程多主機模式時,也不必知道這個用戶目前在哪臺服務器上,推送私信就會很方便。
在這個設計中,一位用戶是允許加入多個組的。就像群聊一樣,一開始就使用這樣的設計,以后可以很容易的進行擴展。
由于采用了單點連接的形式,并不需要每次進房間都建立新連接,客戶端只要首次進行連接,之后發送請求就可以進出房間,也節省了客戶端的開發工作。
2.0版本需求:
當1.0版本完成之后,接下來就是要開發2.0版本。這個版本里增加了一些必要的需求。
首先,這是一個內測版本。在內測版本中會邀請用戶使用,并進行測試。期間可能由于用戶數增多,也可能因為我們代碼本身的原因或是bug造成服務器壓力增加,此時會有擴容方面的需求。
其次是要增加廣播優先級的功能,這個很簡單,禮物肯定是比普通信息優先級更高的。
后是特定消息的回執發送,這個我們目前也還沒有實現,但是需求一直是在的。
上圖中可以看到模塊數增加了,但是總的來說客戶端需求并沒有變化,基本流程的連接流程仍然是先問PHP要token,再去連接WS。由于我們允許把WS部署在多個主機上,在這中間增加了一步就是訪問LB獲得WS地址。LB會輪詢地告知客戶端本次應使用哪個WS,并把IP返回給客戶端。確保所有WS的壓力是平均的。
另外還有一處增加的功能是,由于WS已經分離到多個進程了,那么需要一個地方可以用來處理廣播。這邊我們選擇了Redis的進行廣播。
同時另外還部署了一臺Redis專門用來保存在線列表等數據。
上圖是一個帶有優先級的推送消息。
大家可注意到,我們為每個組的GID增加了一個后綴,這個后綴是用來區分優先級的。
比如說用戶進入房間10000,那么我會把他放到2個組,分別是r:10000._和r:10000.n。
同時Node也會向Redis訂閱兩個同名頻道,此時服務端就可以從2個頻道收到推送消息,分別是_(普通)和n(優先)。
后端會有聊天信息要推送,會根據優先級,是使用普通頻道還是優先頻道進行廣播。
Node這邊會開一個主循環,比如設置12fps,每一幀會優先轉發優先組(頻道)中的消息,然后才是普通消息,根據當時壓力,將會選擇拋棄普通消息。
3.0版本需求:
到了3.0版本時,需求越來越多,需要拆分。線上有時候會有bug和做活動,會有熱更的需求。Redis廣播有可能出現瓶頸,在這之前需要需要更好的廣播性能,同時還需要優化與其他服務器之間的通信。后還需要需要有一個簡單的日志搜集器。
這是3.0版本的架構。大家可以看到下面有大量的服務了。其實這些服務原來是在WebSocket里面的,現在把它拆成不同的進程。
客戶端連接這塊沒有變化,客戶端仍然需要問PHP要token,問LB要地址,后再連接。
這個版本的WS功能上更加單一,只負責消息轉發。在這個版本里,我們做了一套RPC框架,用來方便調用內網各服務的接口。
增加了日志搜集器和API的服務。以及IM系統(私聊)。用戶之間可以聊天和查看聊天記錄等。
總的來說,功能上沒有特別大的變化,尤其是接口方面是向前兼容的。
下面介紹一下RPC服務框架:
我們的RPC框架是基于ZeroMQ的。利用他的里的Dealer和Router進行消息的收發。ZeroMQ 自帶自動重連和負載均衡功能,這方面也不用太操心,節省了開發時間。數據交換格式是JSON,明文傳輸,調試也會很方便。
ZeroMQ性能
# local_thr tcp://*:5555 100 10000000
message size: 100 [B]
message count: 10000000
mean throughput: 1097051 [msg/s]
mean throughput: 877.641 [Mb/s]
還有就是我們不再使用Redis做廣播,而改用ZeroMQ的Pub和Sub做廣播服務。這樣廣播性能就有了很大提升。
IM系統4.0版本的需求:
到了這個階段,我們遇到了一些個別地區網絡較慢的問題。
我們把WS和LB放到了代理服務器后面。LB可以根據不同運營商用戶,返回代理了的WS地址。
同時還優化了RPC服務,我們為RPC服務增加了路由器,所有的Worker都隱藏在他后面,這樣客戶端調用的時候并不需要知道具體Worker的地址。Worker的更新重啟也不會影響其他客戶端。
廣播服務也得到了業務和廣播分離,同時集群化。
本站文章版權歸原作者及原出處所有 。內容為作者個人觀點, 并不代表本站贊同其觀點和對其真實性負責,本站只提供參考并不構成任何投資及應用建議。本站是一個個人學習交流的平臺,網站上部分文章為轉載,并不用于任何商業目的,我們已經盡可能的對作者和來源進行了通告,但是能力有限或疏忽,造成漏登,請及時聯系我們,我們將根據著作權人的要求,立即更正或者刪除有關內容。本站擁有對此聲明的最終解釋權。