典型场景 - 微内核架构
可浏览去哪儿网的落地实际分享。
从上到下隔离级别逐步递增,灵活性逐步增高,性能逐步降落,因而在选型时须要思考插件是否是高频调用,耗时要求如何;
Go 语言落地实现
如上述可知,去哪儿网采纳了 Spring 生态下提供的运行时插件设计,是基于 java 语言的实现,以下给出几种基于 Go 语言的实现计划;
编译时插件 – 代码级别的隔离
应用引包的形式,进行依赖注入,相似于 go 规范库中的 database/sql;
运行时插件
plugin
原理可见:GO 语言设计与实现 8.1 插件零碎,利用了操作系统的动静库链接能力实现模块化的设计,go/plugin -> cgo -> c -> 操作系统
对于具体内容可见 一文搞懂 Go 语言的 plugin,在此做摘要介绍:
问题
有如下问题,因而并未被宽泛应用
- 官网只明确说反对 Linux、FreeBSD 和 macOS,因而其余零碎是否反对不能确定,且即便能够应用,会不会有潜藏危险无从得悉;
- 当一个插件第一次被 open 时,plugin 中所有不属于主程序的包的 init 函数将被调用,但一个插件只被初始化一次,而且不能被敞开;
- 若主程序和插件包依赖同一第三方库,则该独特依赖包的版本必须统一;
- 若主程序或插件库任一一方采纳 vendor 构建,则主程序和插件包必须基于同一个 vendor 目录构建;
- 主程序和插件库应用的编译器的版本必须统一;
- 应用插件库的主程序只能应用动静链接,不能应用动态链接;
- 对于插件的版本,若插件名雷同,内容也雷同,主程序屡次 load 不会呈现问题;但若插件名雷同,但内容不同,主程序运行时屡次 load 会导致无奈复原的 panic。因而插件版本治理须要留神。
解法
依据下面看到的种种束缚,如果要利用 go plugin,必须要做到:
- 构建环境统一
- 对第三方包的版本统一。
因而,业内在应用 go plugin 时多利用 builder container(用来构建程序的容器)来保障主程序和 plugin 应用雷同的构建环境。
在 go plugin 为数不多的用户中,有三个比拟出名的开源我的项目值得后续认真钻研:
- gosh: https://github.com/vladimirvi…
- tyk api gateway: https://github.com/TykTechnol…
- tidb : https://github.com/pingcap/tidb,并给出了其插件零碎应用 go plugin 的残缺设计方案:https://github.com/pingcap/ti…
远端插件 – 过程级别隔离
hashicorp/go-plugin
https://github.com/hashicorp/…
小结
实例间无差别部署,通过回环地址或 unix 域套接字实现本地插件拜访,每个机器上内部署雷同的插件,归为远端插件,理论仍是本地插件计划;
问题
- reattach(服务重启从新加载插件)须要业务代码本人记录下插件的 pid 和 addr,能力实现;
- 只实现了单个插件的加载,没有实现多个插件的治理,如果要治理多个插件的话,还是须要业务代码里自行去组织;
- 并不是一套残缺的本地插件解决方案,只实现了根本的 server 与插件的交互逻辑,在插件的管控上依然须要自行设计、治理。
其余计划
另有一种未开源计划,基于 ZK 进行插件的中心化管控,不同的机器上部署有不同的插件,实现插件的有差异部署。业务服务从 ZK 中取到插件 IP、Port 信息通过 grpc 协定进行拜访,是真正的网络插件。
总结
对 Go 来说远端插件的呈现很大水平上是为了补救运行时插件的有余,实现了灵活性的同时,却肯定水平上升高了性能。尽管应用 Unix 域套接字绝对于回环地址能够晋升性能(见此),但其性能仍低于运行时插件调用(见此:二 Go call Java)。
参考
https://www.bilibili.com/vide…
https://tonybai.com/2021/07/1…