Go 微服務開發框架DMicro的設計思路

語言: CN / TW / HK

Go 微服務開發框架DMicro的設計思路

DMicro原始碼地址:

背景

DMicro誕生的背景,是因為我寫了10來年的PHP,想在公司內部推廣Go,公司內部的元件及rpc協議都是基於swoole定製化開發的。調研了市面上的各種框架,包括beego,goframe,gin,go-micro,go-zero,erpc等等,可能是我當時技術能力有限,並不能讓這些框架很好的適配我們的業務。

我們業務開發有幾個痛點,在當時golang的生態中無法找到一整套解決方案。

  • 微服務應用和單體應用同時開發。
  • 高效能,高可用的網路通訊。
  • 需要自定義應用層的協議(重點)。
  • 需要靈活的外掛擴充套件機制,方便適配現有系統(重點)。
  • 服務端與客戶端的概念模糊,互相都能使用相同的api呼叫對方。
  • 支援Push訊息。
  • 連線/會話管理。
  • 高效率的開發,支援通過proto生成程式碼。
  • 支援多種網路協議,tcp,websocket,quic,unixsocket.
  • 相容http協議。
  • 能夠更快速的定位問題。
  • 更便捷的增加新特性。

在對常用的開源框架做了簡單的調研以後,發現並沒有一款合適的框架能滿足我的所有需求。在認真思考過後,發現erpcgoframe兩個框架的結合體能滿足我的需求,於是就誕生了自研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框架的設計,從設計之初就是在追求靈活性,適應性。在保證微服務的穩定性前提下,追求專案的開發效率。

  • 面向介面設計,保證程式碼穩定,提供靈活定製。
  • 抽象各元件的介面,高內聚,低耦合。
  • 分層設計,自上而下逐層封裝,利於穩定和維護。
  • 高效能,高可用,低消耗。
  • 對開發友好,封裝複雜度。
  • 提供豐富的元件及功能,讓開發專注業務。

無數個寫DMicro的日夜,我都謹記開發三原則:

  • Clarity(清晰)
  • Simplicity(簡單)
  • Productivity(生產力)

無論工作,還是做開源專案,都應該保持這三個原則,養成良好的習慣。

面向介面設計

DMicro秉承著萬物皆介面的原則,提供框架無與倫比的擴充套件性.

下圖展示的是訊息的傳送的流轉流程,可以看到,所有的功能點都被抽象成了介面,每個功能點都提供了不同的實現.

訊息流轉圖.png

會話 Session

大多數的Rpc框架並不強調會話(session)的概念,因其應用場景不需要用到會話(session). 那麼drpc為什麼需要抽象出會話(session)呢?

  • Endpoint 融合了ClientServer,需要提供相同的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 訊息體

訊息結構組成.png

協議 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協議組成如下:

raw協議的組成.png

其他協議可以參考程式碼.

編碼 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的生命週期,是它不可或缺的重要一環。

接收call請求的服務端和傳送call請求的客戶端.png 通過這些鉤子 Hook點,賦予了外掛無限可能.

元件

有了外掛,就能通過外掛的組合,編寫綜合功能的元件,目前框架提供一些內建的元件,

  • 服務端 Rpc Server
  • 客戶端 Rpc Client
  • 服務註冊 Registry
  • 服務發現 Selector
  • 事件匯流排 EventBus
  • 程序管理 Supervisor

即將提供:

  • 鏈路追蹤 Tracing
  • 統計告警 Metrics
  • 限流熔斷 Broker.

限於篇幅的原因,具體元件的實現,這裡就不深入講解,請關注後續的文章.

未來展望

如果把DMicro比作人生,現在成長的階段還處在少年時期,只完成了基礎的架構設計和一部分元件的開發.

接下來的方向主要是往易用性和可靠性方向發展.

易用性:

  • 專案效能工具dmctl工具的開發,包括程式碼生成,專案結構生成,打包,編譯等等功能.
  • 符合openapi定義的文件元件的開發.
  • 更加完善的文件和使用示例.

可靠性:

  • 可觀測性
    • 鏈路追蹤
    • 指標資訊
    • 日誌流
  • 生產可用
    • 測試用例的完善
    • 程式碼覆蓋率
    • 效能調優

希望DMicro能在大家的呵護及鞭策下茁長成長.

開源不易,需要更多小夥伴加入,共創DMicro. 如果你希望使用DMicro,趕快引入程式碼,搭建你的第一個新專案吧! 如果你也想為DMicro生態添磚加瓦,趕快Fork程式碼,給我們提交pr吧!