作者:張富春(ahfuzhang),轉載時請註明作者和引用鏈接,謝謝! cnblogs博客 zhihu Github 公眾號:一本正經的瞎扯 我在多進程插件框架 hashicorp/go-plugin 的基礎上,使用 protoreflect 來解析 proto3 語法的IDL文件,通過命令行工具自 ...
作者:張富春(ahfuzhang),轉載時請註明作者和引用鏈接,謝謝!
我在多進程插件框架 hashicorp/go-plugin 的基礎上,使用 protoreflect 來解析 proto3 語法的IDL文件,通過命令行工具自動生成多進程框架的 callee 和 caller 代碼。
項目的地址請看:https://github.com/ahfuzhang/go-plugin/tree/main/examples/code_generator
並且已經提了PR到官方。
golang自身的plugin還非常的弱,主要有這些限制:
- 其插件的編譯環境必須與宿主進程的編譯環境完全一致
- 插件可以動態載入,但是無法動態卸載
hashicorp公司(他們更出名的產品是terra-form)開源的go-plugin使用了多進程的模式來實現插件,宿主進程創建子進程,然後通過unix套接字來通訊。
雖然跨進程來通訊有一定的損耗,但對於計算的場景還是OK的,反之用於通訊則不太適合。
hashicorp/go-plugin有這樣一些不錯的特性:
- 提供了多進程插件化運行的框架,可以以多種方式寫caller端和callee端。
- 可以動態的載入插件(創建進程)、卸載插件(退出子進程)
- 因為是跨進程的通訊,所以子進程的穩定性不影響宿主進程;其所有的操作系統資源都是與主進程隔離的
- 官方甚至提供了一個用python實現子進程的例子
- 如果用go + lua的方式來寫插件,相信可以做到用lua來實現動態跨進程執行的效果
- 基於這個框架可以很容易寫出一個FAAS(Function as-a Service)框架來
- 提供了日誌、加密、通訊等其他支撐性的功能
最後再介紹我實現的這個小工具:如果基於grpc的風格來寫插件,其中還是要實現一部分對grpc介面的封裝,如果每次寫插件都要寫這些重覆代碼,未免有點太繁瑣了。所以可以在proto3中定義好service,並通過extension的語法來定義插件名字。具體的步驟已經寫在了文檔里,大致是:
- 通過*.proto文件來定義請求格式、響應格式、服務介面;
- 通過
plugin_name
這個extension來定義服務對應的插件名字,如果不寫,則插件名字就是服務名。
- 通過
- 通過protoc來把*.proto變成xx.pb.go的golang代碼
- 通過gen_code命令行來讀取*.proto, 生成插件需要的xx.plugin.go文件
- 同時生成callee目錄,生成插件對應的代碼。然後在todo的位置填寫代碼
- 生成callee_test.go文件,可以拷貝到宿主進程中,用於載入插件。
再補充一點,如果需要把一堆基本類型構成的[]interface{}數組的數據在插件之間傳遞,我寫的上一個工具可以解決這個場景:如何在proto3中用上golang對應的interface{}類型,以及這個工具:Serilizer
Have fun, 希望對你有用。