這是最開始的乙個架構圖:
客戶端維護兩個鏈結,乙個是與閘道器的長鏈,用於接收下推的訊息和事件;乙個是與聊天室伺服器的短鏈(其實是經過了 lvs 的負載均衡 dr **),用於發言、點讚、加入和退出聊天室。
chatroom server 在收到使用者加入的請求後,將使用者資訊儲存在 redis 中。redis 中還儲存有房間資訊、房間的成員列表。在收到使用者退出的房間請求後,從 redis 中刪除該資訊。
chatroom server 收到使用者發言後,會從 redis 中讀出房間成員列表,然後根據使用者資訊找到對應的閘道器服務,向閘道器傳送訊息,由閘道器推給相應的客戶端。
這只是原始模型,只能說可用。使用者量大了後,因為每一次發言都要從 redis 中獲取整個房間的成員列表(hgetall 操作),給所有成員下推,資料量太大了,給 cpu 和記憶體帶來很大的壓力。同時,由於下推服務很重,拖累上行服務,造成併發量上不去。
另外,我們最開始使用的 redis,有4組例項,每組例項只有乙個 master 節點,沒有從節點,這在資料保障和併發性上都不及格。hgetall 是乙個慢操作,乙個房間人數增長到一定程度,這個操作會嚴重影響房間所在的 redis 的效能。因此,我們採取了兩個措施,乙個每組例項新增從節點,主節點寫,從節點讀,redis 客戶端實現讀寫分離;二,資料分片,當房間人數增加到一定程度,在 redis 客戶端對房間成員進行分片,平均分配到4組例項上,採用輪詢的方式。
我們對架構進行了一次調整:
我們把下推服務單獨分離出來。chatroom server 收到使用者的發言請求後,會將內容寫入到佇列中. broadcast 服務從佇列中讀取訊息,從 redis 中讀取房間成員列表,然後推給閘道器。這樣實現 i/o 密集型操作與cpu密集型操作分離。經過這次修改,我們的併發量有了很大提公升。
舉個例子,乙個房間有 1w 使用者,每個使用者發一條訊息,一條訊息是 1k,那麼我要推 1w * 1w * 1k 的資料下去,這個流量太大了。所以,必須採取主動丟棄的策略。因為在聊天室中使用者的訊息,並不需要像 im 那樣實時準確,過於頻繁時丟棄一些,使用者體驗反而會更好。
我們在 broadcast 前加了乙個漏桶,使用者的所有發言、點讚等下推訊息都放在這個漏桶中,broadcast 廣播完一條訊息,就去讀下一條訊息。但漏桶滿了,就丟棄新的訊息(或者覆蓋舊的訊息)。這裡需要注意的是,漏桶的容積不要設定過大。如果使用者發言比較頻繁,broadcast 處理速度又相對較慢,會造成大量的訊息堆積,造成的乙個現象就是直播結束了,有的使用者的發言才被推送到客戶端。
另外,在 chatroom server 內部,以單個房間為維度,我們設定了乙個頻率監控器,當房間內使用者發言行為頻率超過閾值後,主動丟棄,並給客戶端返回成功。
之後我們又做了一些改善。使用者傳送的訊息是不同的,普通使用者的發言、點讚的優先順序低一些,可以多丟棄。使用者的打賞、送禮以及明星使用者的發言優先順序高一些,盡量不丟棄。針對不同的優先順序,設定不同容量的佇列,由不同的程序處理。
該專案是用 erlang 語言來實現的,佇列使用的是 pobox 。這個工具針對 erlang 程序訊息箱做了優化,可以限定訊息箱大小。
mysql 聊天室 聊天室php mysql 六
聊天室php mysql 六 相應的 資料庫 phpmyadmin mysql dump 主機 localhost 3306 資料庫 study28 資料表的結構 chat user create table chat user userid varchar 20 not null,passwd v...
聊天室開發詳解 四
最後,我們把上面編寫的程式上傳到 空間,在客戶端用瀏覽器開啟時,我們見到了平常聊天室一樣的使用者登陸介面。我們於是輸入使用者名稱及密碼,按傳送時,我們所輸入的資料便會暗中存入使用者資料庫中。接著便出現了發言筐,我們試著輸入一句話,點發言按鈕,這時,我們的發言便會帶著我們所輸入的話,我們所選擇的說話物...
聊天室程式
伺服器 include include include include include include include include define servport 8081 伺服器端口號 define bufsize 200 最大傳輸量 int main int args,char argv s...