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