由於要完成一個聊天的項目,因此借鑑了goim,第一篇分析打算半原版,先摘抄http://www.jianshu.com/p/8bd96a9a473d他的一些理解,寫這些仍是爲了讓本身更好的理解這個項目,若是有什麼不對的,請你們給我留言。git
在整個架構中,系統被分紅 Comet, Logic, Job, Router 四大模塊,各個模塊經過 RPC 通訊,參考官方中文文檔,Comet 程序是鏈接層,暴露給公網,全部的業務處理推給 Logic 模塊,經過 RPC 通訊。這樣設計的好處在於,長鏈接邏輯不多變更,穩定的保持公網鏈接,然後端 Logic, Router 模塊常常變更,重啓不會影響鏈接層。github
作爲典型代碼即註釋的開源項目,goim 基本無太多閱讀障礙,幾個邏輯點梳理下很快就會明白。後端
Bucket: 每一個 Comet 程序擁有若干個 Bucket, 能夠理解爲 Session Management, 保存着當前 Comet 服務於哪些 Room 和 Channel. 長鏈接具體分佈在哪一個 Bucket 上呢?根據 SubKey 一致性 Hash 來選擇。網絡
Room: 能夠理解爲房間,羣組或是一個 Group. 這個房間內維護 N 個 Channel, 即長鏈接用戶。在該 Room 內廣播消息,會發送給房間內的全部 Channel.架構
Channel: 維護一個長鏈接用戶,只能對應一個 Room. 推送的消息能夠在 Room 內廣播,也能夠推送到指定的 Channel.併發
Proto: 消息結構體,存放版本號,操做類型,消息序號和消息體。優化
Goim 支持 Tcp, Http, WebSocket, TLS WebSocket. 很是強大,底層原理同樣,下面的分析都是基於 Tcp 協議。spa
先來看看結構體的定義.net
定義很明瞭,維護當前消息通道和房間的信息,方法也很簡單,加減 Channel 和 Room. 一個 Comet Server 默認開啓 1024 Bucket, 這樣作的好處是減小鎖 ( Bucket.cLock ) 爭用,在大併發業務上尤爲明顯。最新的版本增長了routineamout,routinesize這兩個選項主要是用來作progress推送消息的做用,第一個是作消息推送協程個數,第二個是管道長度。比舊版buket取消了之前的roomoptions直接使用room的參數設計
Room 結構體稍顯複雜一些,不但要維護所屬的消息通道 Channel, 還要消息廣播的合併寫,即 Batch Write, 若是不合並寫,每來一個小的消息都經過長鏈接寫出去,系統 Syscall 調用的開銷會很是大,Pprof 的時候會看到網絡 Syscall 是大頭。新版本room改動很大,之前這麼同窗說辭不知道是否管用,可是從結構體定義來看,room增長了下個channel和一個在線狀態。
Logic Server 經過 RPC 調用,將廣播的消息發給 Room.Push, 數據會被暫存在proto這個結構體 裏,每一個 Room 在初始化時會開啓一個 groutine 用來處理暫存的消息,達到 Batch Num 數量或是延遲必定時間後,將消息批量 Push 到 Channel 消息通道。
Channel
這是一個通道。Writer/Reader 就是對網絡 Conn 的封裝,cliProto 是一個 Ring Buffer,保存 Room 廣播或是直接發送過來的消息體。
這裏只分析 Comet 代碼,因此消息生成暫時不提
1. Client 鏈接到 Comet Server, 握手認證
2. 新建當前長鏈接的 Channel, 因爲 Comet 服務不處理業務邏輯,須要 RPC 去 Logic Server 獲取該 Channel 的訂閱信息。同時 Channel 開啓一個 dispatchTCP groutine, 阻塞等待 Ring Buffer 數據可用,發送到 Client。
3. Logic 服務經過 RPC, 將消息寫到 Room (廣播)或是直接寫到指定 Channel (單播)。注意這裏,廣播是有寫合併 BatchWrite, 而單播沒有,消息生成後馬上發送。
4. Room 裏的廣播消息到達必定數量 Batch Num, 或是延遲等待必定時間後,將消息寫到 Channel Ring Buffer。
新版本跟之前那位同窗的很不同,初版本因爲時間關係,基本大多數是摘抄這位同窗的,感受新版本不少不對,可是閱讀代碼還沒到那個程度,因此初版就到這裏,這位同窗對goim大致架子分析的很清楚,細節在我後續章節會有,若是有不對的,請及時留言糾正
1. bucket按照key的cityhash求餘命中的,沒有用一致性hash,由於這裏不涉及遷移
2. 私信發送其實也有合併的,和room合併不一樣的是,在ringbuffer取消息飢餓時候纔會真正flush
3. 還有一個優化能夠改進,由於room有個特色你們消息可能都同樣,因此在room提早合併成字節buffer,而後廣播全部人,避免每一個人都序列化一次,而後利用gc來處理這個buffer的釋放,這樣能夠節省大量cpu,目前這個優化還沒作