可能不太成熟,歡迎討論.
用戶端需要的功能: 登入, 擷取資訊(如自己的資料, 好友的線上狀態,好友資料如簽名, 圖片, 其它資料等), 客戶之間發送訊息
伺服器端:
有以下幾種伺服器:
登入伺服器:
負責管理用戶端登入/登出,驗證登入用戶端的合法性等,與用戶端發送心跳包維持串連的狀態,在用戶端登入之後, 告知Message Service器該使用者上線, Message Service器查詢是否有該使用者的離線訊息將訊息發送給使用者.
同時, 登入伺服器是僅有的C2S伺服器, 也就是說所有要發送給用戶端的訊息都需要經過登入伺服器發送, 而給用戶端發送的訊息都是採用udp形式發送(包括心跳包), udp容易丟失, 因此需要在發送之後對端有回應, 否則就要再試發送.
登入伺服器和下面的資料伺服器,Message Service器以及其它的內部伺服器之間採用TCP長串連保持串連.
資料伺服器:
負責管理客戶資料, 片,個人說明,好友分組, 好友等等, 這些都需要cache, 如果在cache中查詢不到才去資料庫中查詢.
用戶端登入之後首先往好友伺服器查詢自己的資料(圖片,個人說明,好友線上狀態等), 其中查詢好友線上狀態需要和登入伺服器進行互動.資料伺服器只是一個最外部對外面開放的伺服器, 底下下設各種與好友資料相關的伺服器, 片伺服器, 設定檔伺服器, 好友線上狀態伺服器等.
Message Service器:
負責存取離線訊息.
對外暴露的只有登入伺服器而已, 而資料伺服器和Message Service器隱藏在登入伺服器之後.
大致:
用戶端1 .... 用戶端n
/ | / ----> udp發送訊息
登入伺服器
/ / ----->tcp長串連
資料伺服器 Message Service器
/ / ------>tcp長串連
圖片伺服器 設定檔伺服器
幾個可能的效能問題:
1) 當使用者量上來的時候伺服器如何擴容?考慮採用不同的IP地址綁定同一個網域名稱的形式, 也就是說登入伺服器單獨一個網域名稱, 但是擴容之後的不同登入伺服器都綁定在這個網域名稱上, 由用戶端的DNS網域名稱解析自己決定與哪個登入伺服器進行通訊.
2) 伺服器之間採用tcp長串連, 如果其中一個伺服器宕機, 如何處理?需要有好的伺服器平滑切換備份機器的技術, 以及好的監控伺服器機制.
3) 如何高效存取離線訊息?
考慮如下一個方案:有0x00-0xff個目錄, 每個目錄有0x00-0xff個檔案, 在類似bdb這樣的資料庫中存放一條記錄, key是使用者id, value是"目錄:檔案", 查詢發送給某個使用者的離線訊息時首先到這個資料庫中得到相應的目錄和檔案, 再取出所有給該使用者的訊息(訊息在這個檔案中有自己的一套格式).當使用者量上來的時候, 需要增加前面說的目錄和檔案數量.
4) 如何儲存使用者的線上狀態?也就是說,如何迅速做到知道哪些使用者是否線上?這個是不能用cache實現的, 因為cache存放的應該是那些訪問頻繁同時不關注伺服器停止之後是否會丟失的資料, 如果用資料庫來儲存, 那麼資料的增刪很頻繁.
================= 分割線 ======================================
補充:
1)關於線上狀態伺服器:單獨拿出一個伺服器做這個儲存線上狀態的伺服器, 在記憶體中儲存使用者的線上狀態,這台伺服器與登入伺服器相連, 有使用者登入時發包加一條資料,登出時也發包刪除一條資料, 由於直接放在記憶體中, 有以下的優缺點:優點是速度快, 而且由於是一台單獨的伺服器做這個功能, 即使是千萬層級的使用者同時線上按照現在伺服器的硬體設定也足以儲存;缺點是假如這個伺服器掛了, 資料會丟失, 但是考慮到前面的登入伺服器會每隔幾秒給用戶端發送一個心跳包查詢線上狀態,因此即使有誤差也可以控制在很短的時間裡面.
因此, 現在的架構變成了登入伺服器下面還隱藏著一個儲存使用者線上狀態的伺服器.
2) 離線Message Service器:擴容的時候可以考慮把這部分的伺服器做成分布式的, 也就是說, 暴露在最外面的是一台伺服器, 當查詢某個使用者訊息的請求到來時, 再根據hash等方式計算出真正所在的伺服器, 而這一部分伺服器是分布式的, 類似於memcached那樣的.
此時架構就變成了Message Service器下面隱藏著很多真正存放訊息的伺服器.
最後的架構如下:
----------------------------------------------------------------------------------------------------------------------------
做了一些修改,見圖.
做了幾處修改:
1) 暴露在外部與用戶端直接相連的伺服器有登入伺服器, 資料伺服器, Message Service器, 線上狀態伺服器,增加了一個session伺服器, 不直接面向用戶端.用戶端在登入的時候,驗證密碼之類的合法性檢查通過之後, 登入伺服器將向session伺服器申請一個新的sessionid, 以後用戶端與這些伺服器進行通訊的時候協議包都需要帶上這個sessionid以驗證協議包是否合法.
在這裡, 登入伺服器做的事情簡化為驗證登入使用者合法性, 返回為登入使用者申請的sessionid, 以及登出使用者同時通知session伺服器登出該使用者的sessionid.
2)Message Service器與線上狀態伺服器保持串連,用戶端發送訊息的時候, 首先Message Service器要去查詢使用者是否線上, 如果不線上就存入為離線訊息.
3)線上狀態伺服器與用戶端每隔一段時間都要發送心跳包保持串連.注意這裡由用戶端主動發送, 而不是伺服器發送, 這樣某種程度上可以避免線上服務器宕機帶來的影響.
4)這幾個暴露在外面的伺服器只是簡單的對外介面, 底下可能還有很多內部使用的伺服器, 請見第一篇架構的說明, 當使用者量上來時, 還需要考慮擴容的問題.