Go gim IM伺服器,支援多業務接入

2021-10-07 00:14:24 字數 4016 閱讀 6419

gim是乙個即時通訊伺服器,**全部使用golang完成。主要功能:

支援tcp,websocket接入

離線訊息同步

多業務接入

單聊,群聊,以及超大群聊天場景

支援服務水平擴充套件

資料庫:mysql+redis

通訊框架:grpc

長連線通訊協議:protocol buffers

日誌框架:zap

1.首先安裝mysql,redis

2.建立資料庫gim,執行sql/create_table.sql,完成初始化表的建立(資料庫包含提供測試的一些初始資料)

3.修改config下配置檔案,使之和你本地配置一致

4.分別切換到cmd的tcp_conn,ws_conn,logic目錄下,執行go run main.go,啟動tcp連線層伺服器,websocket連線層伺服器,邏輯層伺服器

專案所有的proto協議在gim/public/proto/目錄下

1.tcp.proto

長連線通訊協議

2.logic_client.ext.proto

對客戶端(android裝置,ios裝置)提供的rpc協議

3.logic_server.ext.proto

對業務伺服器提供的rpc協議

4.logic.int.proto

對conn服務層提供的rpc協議

5.conn.int.proto

對logic服務層提供的rpc協議

專案結構遵循 

api:          服務對外提供的grpc介面

cmd: 服務啟動入口

config: 服務配置

internal: 每個服務私有**

pkg: 服務共有**

sql: 專案sql檔案

test: 長連線測試指令碼

1.tcp_conn

維持與客戶端的tcp長連線,心跳,以及tcp拆包粘包,訊息編譯碼

2.ws_conn

維持與客戶端的websocket長連線,心跳,訊息編譯碼

3.logic

裝置資訊,使用者資訊,群組資訊管理,訊息**邏輯

遵循lv的協議格式,乙個訊息包分為兩部分,訊息位元組長度以及訊息內容。 這裡為了減少記憶體分配,拆出來的包的記憶體復用讀快取區記憶體。

拆包流程:

1.首先從系統快取區讀取位元組流到buffer

2.根據包頭的length欄位,檢查報的value欄位的長度是否大於等於length

3.如果大於,返回乙個完整包(此包記憶體復用),重複步驟2

4.如果小於,將buffer的有效位元組前移,重複步驟1

首先解釋一下,什麼是讀擴散,什麼是寫擴散

讀擴散簡介:群組成員傳送訊息時,先建立乙個會話,都將這個訊息寫入這個會話中,同步離線訊息時,需要同步這個會話的未同步訊息

優點:每個訊息只需要寫入資料庫一次就行,減少資料庫訪問次數,節省資料庫空間

缺點:乙個使用者有n個群組,客戶端每次同步訊息時,要上傳n個序列號,伺服器要對這n個群組分別做訊息同步

寫擴散簡介:在群組中,每個使用者維持乙個自己的訊息列表,當群組中有人傳送訊息時,給群組的每個使用者的訊息列表插入一條訊息即可

優點:每個使用者只需要維護乙個序列號和訊息列表

缺點:乙個群組有多少人,就要插入多少條訊息,當群組成員很多時,db的壓力會增大

普通群組:

採用寫擴散,群組成員資訊持久化到資料庫儲存。支援訊息離線同步。

超大群組:

採用讀擴散,群組成員資訊儲存到redis,不支援離線訊息同步。

長連線登入

離線訊息同步

心跳訊息單發

c1.d1和c1.d2分別表示c1使用者的兩個裝置d1和d2,c2.d3和c2.d4同理 

小群訊息**

c1,c2.c3表示乙個群組中的三個使用者 

大群訊息**

系統中的錯誤一般可以歸類為兩種,一種是業務定義的錯誤,一種就是未知的錯誤,在業務正式上線的時候,業務定義的錯誤的屬於正常業務邏輯,不需要列印出來, 但是未知的錯誤,我們就需要列印出來,我們不僅要知道是什麼錯誤,還要知道錯誤的呼叫堆疊,所以這裡我對grpc的錯誤進行了一些封裝,使之包含呼叫堆疊。

func wraperror(err error) error 

s := &spb.status,

},} return status.fromproto(s).err()

}// stack 獲取堆疊資訊

func stack() string

} return build.string()

}

這樣,不僅可以拿到錯誤的堆疊,錯誤的堆疊也可以跨rpc傳輸,但是,但是這樣你只能拿到當前服務的堆疊,卻不能拿到呼叫方的堆疊,就比如說,a服務呼叫 b服務,當b服務發生錯誤時,在a服務通過日誌列印錯誤的時候,我們只列印了b服務的呼叫堆疊,怎樣可以把a服務的堆疊列印出來。我們在a服務呼叫的地方也獲取 一次堆疊。

func wraprpcerror(err error) error 

e, _ := status.fromerror(err)

s := &spb.status,

},} return status.fromproto(s).err()

}func interceptor(ctx context.context, method string, req, reply inte***ce{}, cc *grpc.clientconn, invoker grpc.unaryinvoker, opts ...grpc.calloption) error

var logicintclient pb.logicintclient

func initlogicintclient(addr string)

logicintclient = pb.newlogicintclient(conn)

}

像這樣,就可以獲取完整一次呼叫堆疊。 錯誤列印也沒有必要在函式返回錯誤的時候,每次都去列印。因為錯誤已經包含了堆疊資訊

// 錯誤的方式

if err != nil

// 正確的方式

if err != nil

然後,我們在上層統一列印就可以

func startserver 

extserver := grpc.newserver(grpc.unaryinterceptor(logicclientextinterceptor))

pb.registerlogicclientextserver(extserver, &logicclientextserver{})

err = extserver.serve(extlisten)

if err != nil

}func logicclientextinterceptor(ctx context.context, req inte***ce{}, info *grpc.unaryserverinfo, handler grpc.unaryhandler) (resp inte***ce{}, err error) ()

resp, err = handler(ctx, req)

logger.logger.debug("logic_client_ext_interceptor", zap.any("info", info), zap.any("ctx", ctx), zap.any("req", req),

zap.any("resp", resp), zap.error(err))

s, _ := status.fromerror(err)

if s.code() != 0 && s.code() < 1000

return

}

func getctx() context.context

mysql多伺服器 mysql 多伺服器例項

測試環境是在windows下。不同系統啟動和停止命令有所差異 1 修改配置檔案 把需要配置的選項都設定成不一樣的 需要修改的地方有 client password your password port 3308 經過測試,這個埠改不改都沒什麼問題,但是還是改了保險點吧 socket d servic...

mysql多伺服器 單伺服器多mysql伺服器

mkdir home mysql servers mysql330 p useradd g mysql mysql3307 s bin nologin d home mysql servers mysql3307 tar xf mysql.tar.gz cd mysql configure pref...

伺服器系統支援

網路作業系統 nos 是網路的心臟和靈魂,是向網路計算機提供網路通訊和網路資源共享功能的作業系統。它是負責管理整個網路資源和方便網路使用者的軟體的集合。由於網路作業系統是執行在伺服器之上的,所以有時我們也把它稱之為伺服器作業系統。網路作業系統與執行在工作站上的單使用者作業系統 如windows98等...