即時通訊伺服器架構的一些思考

2021-08-17 12:15:49 字數 2623 閱讀 9593

對於乙個即時通訊伺服器來說,在使用者量少的時候,一台伺服器就足以提供所有的服務。而這種架構也最簡單,舉個例子,使用者a與使用者b互為好友,a向b發訊息,伺服器接收到訊息時,解析出接收訊息的人,直接**給b即可。可是當使用者數量越來越多時,一台伺服器已經無法所有使用者的需求,這時就要進行服務擴容,進行分布式部署

如圖所示,不同的使用者可能登入到不同的伺服器上,那麼使用者a給使用者b發訊息時,伺服器收到訊息,首先判斷b是否也登入在本伺服器上,如果是,那麼直接**訊息即可。如果b不在本伺服器上,那應該往****這條訊息呢?最簡單的做法就是向伺服器集群中的其他伺服器廣播這條訊息,對於每個收到這條訊息的伺服器,首先判斷訊息的目的使用者是否登入在自己身上,如果不是,直接忽略該訊息。如果是,那麼向目的使用者**該訊息。固然,這種暴力粗獷的做法是最簡單直接的,但是會產生很多無效的訊息**,對於伺服器效能產生很大的影響。曾看過蘑菇街開源的即時通訊軟體teamtalk的**,伺服器就是這種實現方式。其伺服器架構如下:

不同的msg伺服器連線到同一臺route server上,所有msg伺服器之間的**全部通過route server。這無疑會加重route server的負載。即時msg server部署的再多,根據木桶理論,乙個系統的效能是由其最薄弱的環節所決定的。所以也注定這樣的架構,其系統容量也是有限的。那麼如何改善這種系統呢,很明顯伺服器之間的訊息**不能直接全部廣播,而應該有一套明確的路由系統,即伺服器在**訊息時,應該知道這條訊息應該**到哪一台伺服器,這樣就不需要每條訊息都在所有伺服器之間廣播了。

那麼如何實現這樣一套路由系統呢?

簡單的做法是,每個使用者上線時,通過其連線的msg server向其他所有msg server廣播自己的登入資訊,告知其他伺服器自己登入在哪台伺服器上面。這樣當某個使用者向其好友發訊息時,首先通過好友id檢視其登入的msg server。如果好友與自己是同一臺伺服器,那麼直接**即可;如果不是,伺服器向route server傳送**該訊息,並且帶上目標msg server的id.這樣route server 收到訊息後,解析出目標的msg server,進行一次**即可,省去了大量的廣播訊息。這種方式雖然解決了廣播訊息的問題,但是在每台msg server上都要儲存所有使用者的路由資訊。當所有使用者都登入時,幾乎就退化成了單點模型,msg server肯定承受不了。

那麼如何解決這個問題呢?試想一下,既然所有的msg server上都儲存著同樣的路由資訊,那麼我們可以把這些資料從msg server剝離出來,存在乙個單獨的伺服器上,供msg server查詢。我們暫且把這個伺服器叫做route info server(路由資訊伺服器).對於乙個使用者要儲存的資料為

假設這兩個資料都是32byte,那麼儲存一億個使用者需要的記憶體32b*10^8=3.2g。目前好點的伺服器都有50g的記憶體,很顯然記憶體不是問題。那麼就剩訪問量的問題。如果所有的msg server都從這一台伺服器上讀取資料, 肯定會影響整個系統的效能。所以路由資訊伺服器不能採用這種單點模型。考慮到這種路由資訊的特點,很明顯是一種讀多寫少的資料。乙個使用者只有在登入的時候才會寫一次路由資訊,其他時候就是**訊息的時候讀取路由資訊了。那麼可以採用類似資料庫的主備模型,主伺服器用來寫路由資訊,備伺服器用於查詢路由資訊。而且可以設定多台備伺服器,分擔msg server的讀壓力。其實我們也可以使用一些成熟的快取系統來完成路由資訊伺服器的功能,比如redis. redis擁有現成的主備方案,只是像這種通用的快取伺服器在儲存資料時,消耗的記憶體會大些。研究過redis原始碼的,大多都能理解。其key value都儲存在redisobject的結構體當中,有一些附加的資訊,所以比自己寫乙個這樣的服務所消耗的記憶體肯定會大些。

ok,說完了路由資訊伺服器,我們再回到msg server上來。那麼msg server在**訊息時,首先根據目的使用者的id 到路由資訊伺服器上查詢其所在的msg server用於訊息**。但是這也會存在乙個,每次**訊息時,都要查詢一次路由資訊,這無疑會影響訊息的**速度,而且也會增大路由資訊伺服器的訪問壓力。如果在傳送訊息之後,將路由資訊儲存到本地,那麼下次傳送訊息,就無需再去路由資訊伺服器重複查詢了。但是也不能把所有的路由全部儲存到本地,那樣又會嚴重消耗msg server的記憶體。於是,就有我們想到一種折中的方案,使用乙個lru的快取佇列,在需要儲存新的路由資訊時,首先檢視快取佇列是否已滿,如果未滿,直接插入到隊首,如果佇列已滿,淘汰到隊尾的資料。快取列隊大小可根據記憶體大小靈活設定。考慮到在我們平時在使用qq時,大部分人都登入著,但是發訊息的人並不多。對於路由資訊,在其首次**訊息是,從路由資訊伺服器查詢一次路由,在其整個回話過程中,路由資訊都快取在本地。在其會話結束後,將最近最久未使用的路由資料淘汰出去,這種做法再考慮到記憶體使用的同時,又大大減少了伺服器的訪問次數,算是一種較好的折中方案. 在完成了路由資訊系統之後,route server也可以進行水平擴充套件,route server要做的僅僅是**訊息,並不需要儲存資料,擴充套件起來非常方便。最終的系統架構如下:

總結:1. 本文所描述的即時通訊伺服器架構,著重討論的是訊息如何路由的問題,但這並不代表乙個完整的即時通訊伺服器系統,諸如註冊,登入,離線訊息,檔案等功能這些都未在本文的討論範圍之類

即時通訊伺服器架構的一些思考

對於乙個即時通訊伺服器來說,在使用者量少的時候,一台伺服器就足以提供所有的服務。而這種架構也最簡單,舉個例子,使用者a與使用者b互為好友,a向b發訊息,伺服器接收到訊息時,解析出接收訊息的人,直接 給b即可。可是當使用者數量越來越多時,一台伺服器已經無法所有使用者的需求,這時就要進行服務擴容,進行分...

自己構造的即時通訊伺服器基本功能搭建完成!

參考了qq msn gtalk fetion的協議和源 進行了一定的優化。傳輸協議使用精簡xml表達 使用attribute,不使用element 登入方式參考了qq,採取先獲取token,然後對之後的資訊進行加密傳輸。在穩定性方面,增強了對鏈結的健康度檢查,包括出錯率 傳送頻率等等 一旦出現異常立...

IM即時通訊的一些基本概念梳理

一 websocket和http的區別 相同點 websocket 和 http 都是基於tcp的應用層協議,都是可靠性傳輸協議。不同點 1 http請求是單向的,需要等到客戶端發起請求,服務端才能響應 websocket是全雙工協議,客戶端通過http 1.1協議進行握手,連線就建立了,通訊雙方都...