Go 每日一庫之微服務開發框架 DMicro 的設計思路
來源 | OSCHINA 社區
作者 | ClownFish
原文鏈接:https://my.oschina.net/clownfish/blog/5560923
DMicro
源碼地址:
-
GitHub: https://github.com/osgochina/dmicro
-
Gitee: https://gitee.com/osgochina/dmicro
背景
DMicro
誕生的背景,是因爲我寫了 10 來年的 PHP,想在公司內部推廣 Go
, 公司內部的組件及 rpc 協議都是基於 swoole
定製化開發的。調研了市面上的各種框架,包括 beego
,goframe
,gin
,go-micro
,go-zero
,erpc
等等,可能是我當時技術能力有限,並不能讓這些框架很好的適配我們的業務。
我們業務開發有幾個痛點,在當時 golang
的生態中無法找到一整套解決方案。
-
微服務應用和單體應用同時開發。
-
高性能,高可用的網絡通訊。
-
需要自定義應用層的協議 (重點)。
-
需要靈活的插件擴展機制,方便適配現有系統 (重點)。
-
服務端與客戶端的概念模糊,互相都能使用相同的 api 調用對方。
-
支持 Push 消息。
-
連接 / 會話管理。
-
高效率的開發,支持通過 proto 生成代碼。
-
支持多種網絡協議,
tcp
,websocket
,quic
,unixsocket
. -
兼容 http 協議。
-
能夠更快速的定位問題。
-
更便捷的增加新特性。
在對常用的開源框架做了簡單的調研以後,發現並沒有一款合適的框架能滿足我的所有需求。在認真思考過後,發現 erpc
和 goframe
兩個框架的結合體能滿足我的需求,於是就誕生了自研 DMicro
.
概述
DMicro
中的 drpc
組件的思想是參考 erpc
實現,甚至可以說是它的繼承者。
drpc
組件是 DMicro
框架的一部分,爲了適配 DMicro
框架,在 erpc
的基礎上做了深入的擴展開發。
整個 DMicro
大量使用 goframe
中的組件,如果業務使用 goframe
框架,可以無縫接入。
DRpc
特性列表:
-
對等通信
,對等Api
-
高性能
,非阻塞異步IO
-
自定義Proto
,,兼容http協議
,自定義Codec
-
Hook點
,插件系統
, -
Push消息
,session管理
,Socket抽象
, -
斷線重連
,過載保護
,負載均衡
,心跳機制
, -
平滑重啓
...
DServer
特性列表:
-
快速構建
,平滑重啓
,多進程支持
,單/多進程一致
-
預定義命令行
,ctrl命令管理服務
-
可觀測
,可控制
,應用沙盒
DMicro
已經內置組件:
-
[x]
Registry
服務註冊 -
[x]
Selector
服務發現 -
[x]
Eventbus
事件總線 -
[x]
Supervisor
進程管理 -
[ ]
Code gen
代碼生成 -
[ ]
Tracing
鏈路追蹤 -
[ ]
Metrics
統計告警 -
[ ]
Broker
限流熔斷 -
[ ]
OpenAPI
文檔自動生成
架構
設計理念
對 DMicro
框架的設計,從設計之初就是在追求靈活性,適應性。在保證微服務的穩定性前提下,追求項目的開發效率。
-
面向接口設計,保證代碼穩定,提供靈活定製。
-
抽象各組件的接口,高內聚,低耦合。
-
分層設計,自上而下逐層封裝,利於穩定和維護。
-
高性能,高可用,低消耗。
-
對開發友好,封裝複雜度。
-
提供豐富的組件及功能,讓開發專注業務。
無數個寫 DMicro
的日夜,我都謹記開發三原則:
-
Clarity(清晰)
-
Simplicity(簡單)
-
Productivity(生產力)
無論工作,還是做開源項目,都應該保持這三個原則,養成良好的習慣。
面向接口設計
DMicro
秉承着萬物皆接口的原則,提供框架無與倫比的擴展性.
下圖展示的是消息的發送的流轉流程,可以看到,所有的功能點都被抽象成了接口,每個功能點都提供了不同的實現.
會話 Session
大多數的 Rpc
框架並不強調會話 (session
) 的概念,因其應用場景不需要用到會話 (session
). 那麼 drpc
爲什麼需要抽象出會話 (session
) 呢?
-
Endpoint
融合了Client
和Server
, 需要提供相同的Api
. -
服務端
需要主動向客戶端
發送消息,並且獲取客戶端的響應. -
服務端
支持對多個客戶端
批量發送消息. -
異步主動斷開
一個
或多個
會話. -
獲取會話底層的
文件描述符
, 對其進行性能調優. -
可以爲每個會話綁定特殊的
數據/屬性
.
Session
抽象了整個 drpc
框架的會話,把 Socket
,Message
,Context
都融合到一起。開發者只需要對 session
進行操作,就能實現大多數需求.
-
獲取連接信息
-
控制連接的生命週期 (超時時間)
-
控制單次請求的生命週期 (超時時間)
-
接收消息
-
發送消息
-
創建消息的上下文
-
綁定會話的相關信息 (如用戶信息)
-
斷線重連
-
主動斷開會話.
-
健康檢查
-
獲取連接關閉事件
-
爲會話設置單獨的 id
Session
接口可以細分爲 4 個 interface{}
, 分別是 EarlySession
,BaseSession
,CtxSession
,Session
. 對應的是應用的不同生命階段會話 (Session
) 擁有的不同屬性.
-
EarlySession
表示剛生成會話,尚未啓動 goroutine 讀取數據的階段. -
BaseSession
只有最基礎的方法,用於關閉連接時候的插件參數. -
CtxSession
在處理程序上下文中傳遞的會話對象. -
Session
全功能的會話對象.
正常情況下,開發者用到的都是 Session
,CtxSession
這兩個接口,其他 2 個接口是在插件中使用.
消息 Message
消息 Message
包含消息頭 Header
, 消息體 Body
, 是客戶端與服務端之間通信的實體.
Message interface{}
抽象了對通信實體的操作.
-
Size
消息的長度 -
Transfer-Filter-Pipeline
報文數據過濾處理管道 -
Seq
序列號 -
MType
消息類型 -
ServiceMethod
資源標識符 -
Meta
消息的元數據 -
BodyCodec
消息體編碼格式 -
Body
消息體
協議 Proto
協議是對消息Message
對象的序列化和反向序列化,框架提供 Proto
接口。只需要實現該接口,開發者就能定製符合業務需求的自定義協議,從而提升了框架的靈活性.
接口的定義如下:
type Proto interface {
Version() (byte, string)
Pack(Message) error
Unpack(Message) error}
-
Version()
返回該協議的 id 和名字,兩個組成唯一的版本號. -
Pack
對消息Message
對象進行序列化. -
Unpack
對字節流反序列化,生成一個消息Message
對象.
目前框架已支持 Http
,Json
,Raw
,Protobuf
,JsonRpc
這 5 個協議.
RAW
協議組成如下:
其他協議可以參考代碼.
編碼 Codec
作爲一個通用性的框架,支持的協議可以有多種,消息體的編解碼也可以有多少種. drpc
使用 Codec
接口對消息體 Body 進行編解碼.
接口的定義如下:
type Codec interface {
ID() byte
Name() string
Marshal(interface{}) ([]byte, error)
Unmarshal([]byte, interface{}) error
}
-
ID
返回編 Codec 的 id -
Name
返回編 Codec 的名字,名字是爲了開發者更容易識別. -
Marshal
對消息內容進行編碼 -
Unmarshal
對消息內容進行解碼
目前框架已支持 Form
,Json
,plain
,Protobuf
,XML
這 5 個編解碼.
連接 Socket
Socket
擴展了 net.Conn
, 並且抽象出接口,方便框架對底層網絡協議的集成.
Socket
接口實現了一部分 Session
接口的功能,Session
接口調用的一些方法,實際上是轉發調用了 Socket
中的方法.
這樣的分層實現,讓 Socket
擁有的集成其他協議的能力.
-
TCP V4
,TCP V6
-
Unix Socket
-
KCP
-
QUIC
支持對連接的性能調優.
-
SetKeepAlive
開啓鏈接保活 -
SetKeepAlivePeriod
鏈接保活間隔時間 -
SetReadBuffer
設置鏈接讀緩衝區 size -
SetWriteBuffer
獲取鏈接寫緩衝區 size -
SetNoDelay
開啓關閉 no delay 算法 -
ControlFD
支持操作鏈接的原始句柄
有機的組合
前面講到,DMicro
框架萬物皆接口,分層 + 接口的設計,讓 DMicro
有了靈活的組成高效且符合業務實際情況的能力.
接下來我們要講到實現這些能力的基礎。插件系統.
插件 Plugin
插件系統給框架帶來了極大的擴展性和靈活性,是整個框架的一個靈魂模塊,有了它,框架就有了無限可能。
什麼樣的插件系統才能算是優雅呢?我能想到的有以下幾點:
-
合理且豐富的
hook
位置,能夠覆蓋整個框架的生命週期,貫穿通訊的各個環節。 -
每個
hook
位置的入參和出參都是經過精心設計。 -
每個插件都能夠使用多個
hook
位置,每個hook
位置都能被多個插件使用。 -
設計的足夠簡潔,優雅。能方便的進行二次開發定製。
在 drpc
中,鉤子貫穿與整個 Endpoint
的生命週期,是它不可或缺的重要一環。
鉤子 Hook
點,賦予了插件無限可能.
組件
有了插件,就能通過插件的組合,編寫綜合功能的組件,目前框架提供一些內置的組件,
-
服務端 Rpc Server
-
客戶端 Rpc Client
-
服務註冊 Registry
-
服務發現 Selector
-
事件總線 EventBus
-
進程管理 Supervisor
即將提供:
-
鏈路追蹤 Tracing
-
統計告警 Metrics
-
限流熔斷 Broker
.
限於篇幅的原因,具體組件的實現,這裏就不深入講解,請關注後續的文章.
未來展望
如果把 DMicro
比作人生,現在成長的階段還處在少年時期,只完成了基礎的架構設計和一部分組件的開發.
接下來的方向主要是往易用性和可靠性方向發展.
易用性:
-
項目效能工具
dmctl
工具的開發,包括代碼生成,項目結構生成,打包,編譯等等功能. -
符合 openapi 定義的文檔組件的開發.
-
更加完善的文檔和使用示例.
可靠性:
-
可觀測性
-
鏈路追蹤
-
指標信息
-
日誌流
-
生產可用
-
測試用例的完善
-
代碼覆蓋率
-
性能調優
希望 DMicro
能在大家的呵護及鞭策下茁長成長.
開源不易,需要更多小夥伴加入,共創 DMicro
. 如果你希望使用 DMicro
, 趕快引入代碼,搭建你的第一個新項目吧!如果你也想爲 DMicro
生態添磚加瓦,趕快 Fork
代碼,給我們提交 pr
吧!
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/sGwf1NUX3UpKmMniKtwa7g