golang寫的即時通訊伺服器gim

Alber發表於2019-12-15

簡要介紹

gim是一個即時通訊伺服器,程式碼全部使用golang完成。主要功能
1.離線訊息同步
2.多業務接入
3.單使用者多裝置同時線上
4.單聊,群聊,以及超大群聊天場景 5.支援服務水平擴充套件

使用技術:

資料庫:Mysql+Redis
元件:grpc+jsoniter+zap

安裝部署

1.首先安裝MySQL,Redis
2.建立資料庫gim,執行sql/create_table.sql,完成初始化表的建立 3.下載程式碼到你本地 4.修改conf/conf.go配置檔案,使之和你本地配置一致
5.分別切換到app的connect和logic目錄下,執行go run main.go,啟動連線層伺服器和邏輯層伺服器
6.切換到test目錄下,啟動測試指令碼
7.使用public/util/aes.go的GetToken獲取token
8.使用rpc介面傳送訊息

業務伺服器如何接入

1.首先生成私鑰和公鑰 2.在app表裡根據你的私鑰新增一條app記錄

3.將app_id和公鑰儲存到業務伺服器

4.將使用者通過LogicClientExtServer.AddUser介面新增到IM伺服器 

5.通過LogicClientExtServer.RegisterDevice介面初始化裝置,獲取裝置id(device_id)

6.將app_id,user_id,device_id用公鑰通過公鑰加密,生成token,相應庫的程式碼在public/util/aes.go

7.接下來使用這個token,app就可以和IM伺服器互動

專案目錄介紹

├─ app # 服務啟動入口
│   ├── conn # 連線層啟動入口
│   └── logic   # 邏輯層啟動入口
├─ conf # 配置
├─ conn # 連線層服務程式碼
├─ ligic # 邏輯層服務程式碼
├─ public # 連線層和邏輯層公共程式碼
├─ sql # 資料庫建表語句
├─ test # 測試指令碼
├─ docs # 專案文件

TCP拆包粘包

遵循TLV的協議格式,一個訊息包分為三部分,訊息型別(兩個位元組),訊息包內容長度(兩個位元組),訊息內容。
這裡為了減少記憶體分配,拆出來的包的記憶體複用讀快取區記憶體。
拆包流程:
1.首先從系統快取區讀取位元組流到buffer
2.根據包頭的length欄位,檢查報的value欄位的長度是否大於等於length
3.如果大於,返回一個完整包(此包記憶體複用),重複步驟2
4.如果小於,將buffer的有效位元組前移,重複步驟1

服務簡介

1.connect
維持與客戶端的TCP長連線,心跳,以及TCP拆包粘包,訊息編解碼 2.logic
訊息轉發邏輯,裝置資訊,使用者資訊,群組資訊的操作

離線訊息同步

使用者的訊息維護一個自增的序列號,當客戶端TCP連線斷開重新建立連線時,首先要做TCP長連線的登入,然後用客戶端本地已經同步的最大的序列號做訊息同步,這樣就可以保證離線訊息的不丟失。

單使用者多裝置支援

當使用者傳送訊息時,除了將訊息傳送目的使用者
在DB中,每個使用者只維護一個自己的訊息列表,但是使用者的每個裝置各自維護自己的同步序列號,裝置使用自己的同步序列號在訊息列表中做訊息同步

訊息轉發邏輯

單聊和普通群組採用寫擴散,超級大群使用讀擴散。
讀擴散和寫擴散的選型。
首先解釋一下,什麼是讀擴散,什麼是寫擴散

讀擴散

簡介:群組成員傳送訊息時,也是先建立一個會話,都將這個訊息寫入這個會話中,同步離線訊息時,需要同步這個會話的未同步訊息
優點:每個訊息只需要寫入資料庫一次就行,減少資料庫訪問次數,節省資料庫空間
缺點:一個使用者有n個群組,客戶端每次同步訊息時,要上傳n個序列號,伺服器要對這n個群組分別做訊息同步

寫擴散

簡介:就是每個使用者維持一個訊息列表,當有其他使用者給這個使用者傳送訊息時,給這個使用者的訊息列表插入一條訊息即可
優點:每個使用者只需要維護一個序列號和訊息列表
缺點:一個群組有多少人,就要插入多少條訊息,當群組成員很多時,DB的壓力會增大

群組簡介

普通群組:

1.支援離線訊息同步
2.群組成員越多,DB壓力越大

超大群組:

1.DB壓力不會隨著群組成員的人數的增加而增加
2.不支援離線訊息同步

核心流程時序圖

長連線登入

離線訊息同步

心跳

訊息單發

訊息群發

github

https://github.com/alberliu/gim

相關文章