1. 程式人生 > >自己設想的一個IM伺服器的架構

自己設想的一個IM伺服器的架構

續一在這裡:http://www.cppblog.com/converse/archive/2009/01/14/71993.html

可能不太成熟,歡迎討論.

客戶端需要的功能: 登入, 獲取資訊(如自己的資料, 好友的線上狀態,好友資料如簽名, 圖片, 其它資料等), 客戶之間傳送訊息
       
伺服器端:          
        有以下幾種伺服器:
       
        登入伺服器:   
        負責管理客戶端登入/登出,驗證登入客戶端的合法性等,與客戶端傳送心跳包維持連線的狀態,在客戶端登入之後, 告知訊息伺服器該使用者上線, 訊息伺服器查詢是否有該使用者的離線訊息將訊息傳送給使用者.
        同時, 登入伺服器是僅有的C2S伺服器, 也就是說所有要傳送給客戶端的訊息都需要經過登入伺服器傳送, 而給客戶端傳送的訊息都是採用udp形式傳送(包括心跳包), udp容易丟失, 因此需要在傳送之後對端有迴應, 否則就要再試傳送.

        登入伺服器和下面的資料伺服器,訊息伺服器以及其它的內部伺服器之間採用TCP長連線保持連線.
       
        資料伺服器:   
        負責管理客戶資料, 如圖片,個人說明,好友分組, 好友等等, 這些都需要cache, 如果在cache中查詢不到才去資料庫中查詢.
        客戶端登入之後首先往好友伺服器查詢自己的資料(圖片,個人說明,好友線上狀態等), 其中查詢好友線上狀態需要和登入伺服器進行互動.資料伺服器只是一個最外部對外面開放的伺服器, 底下下設各種與好友資料相關的伺服器, 如圖片伺服器, 個人資料伺服器, 好友線上狀態伺服器等.
                   
        訊息伺服器:   
        負責存取離線訊息.
       
        對外暴露的只有登入伺服器而已, 而資料伺服器和訊息伺服器隱藏在登入伺服器之後.
       
        大致如圖:
       
        客戶端1 ....  客戶端n
          \      |       /         ----> udp傳送訊息
             登入伺服器
            /         \            ----->tcp長連線
        資料伺服器      訊息伺服器
        /        \                 ------>tcp長連線
圖片伺服器   個人資料伺服器       
                   
幾個可能的效能問題:
1) 當用戶量上來的時候伺服器如何擴容?考慮採用不同的IP地址繫結同一個域名的形式, 也就是說登入伺服器單獨一個域名, 但是擴容之後的不同登入伺服器都繫結在這個域名上, 由客戶端的DNS域名解析自己決定與哪個登入伺服器進行通訊.
  
2) 伺服器之間採用tcp長連線, 如果其中一個伺服器宕機, 如何處理?需要有好的伺服器平滑切換備份機器的技術, 以及好的監控伺服器機制.

3) 如何高效存取離線訊息?
   考慮如下一個方案:有0x00-0xff個目錄, 每個目錄有0x00-0xff個檔案, 在類似bdb這樣的資料庫中存放一條記錄, key是使用者id, value是"目錄:檔案", 查詢傳送給某個使用者的離線訊息時首先到這個資料庫中得到相應的目錄和檔案, 再取出所有給該使用者的訊息(訊息在這個檔案中有自己的一套格式).當用戶量上來的時候, 需要增加前面說的目錄和檔案數量.
  
4) 如何儲存使用者的線上狀態?也就是說,如何迅速做到知道哪些使用者是否線上?這個是不能用cache實現的, 因為cache存放的應該是那些訪問頻繁同時不關注伺服器停止之後是否會丟失的資料, 如果用資料庫來儲存, 那麼資料的增刪很頻繁.


================= 分割線 ======================================
補充:
1)關於線上狀態伺服器:單獨拿出一個伺服器做這個儲存線上狀態的伺服器, 在記憶體中儲存使用者的線上狀態,這臺伺服器與登入伺服器相連, 有使用者登入時發包加一條資料,登出時也發包刪除一條資料, 由於直接放在記憶體中, 有以下的優缺點:優點是速度快, 而且由於是一臺單獨的伺服器做這個功能, 即使是千萬級別的使用者同時線上按照現在伺服器的硬體配置也足以儲存;缺點是假如這個伺服器掛了, 資料會丟失, 但是考慮到前面的登入伺服器會每隔幾秒給客戶端傳送一個心跳包查詢線上狀態,因此即使有誤差也可以控制在很短的時間裡面.
因此, 現在的架構變成了登入伺服器下面還隱藏著一個儲存使用者線上狀態的伺服器.

2) 離線訊息伺服器:擴容的時候可以考慮把這部分的伺服器做成分散式的, 也就是說, 暴露在最外面的是一臺伺服器, 當查詢某個使用者訊息的請求到來時, 再根據hash等方式計算出真正所在的伺服器, 而這一部分伺服器是分散式的, 類似於memcached那樣的.
此時架構就變成了訊息伺服器下面隱藏著很多真正存放訊息的伺服器.

最後的架構如下: