页首Html代码

返回顶部

golang 1.18 plugin 热更新|插件化终极方案 2022经验实战总结

golang plugin 结论:

0 ** 目前 golang1.8 以上, 现在golang1.18 ,并且类linux 费windows 平台支持golang的plugin.

1 ** 目前只能加载,不能卸载so,所以 so加载导内存后,不会卸载,无限加载so会导致内存泄露;
2 so 里面引用的其他package 和 主进程 地址相同,比如so调用了 log.SetPrefix 会导致 全局 log 发生变化;
3 ** 重新加载此plugin的方法: 把so的 main 包名的目录给改掉,比如 plugin.test/main/cmd/logic 改为 plugin.test/main/cmd/logic_v1
4 通过-ldflags="-pluginpath=$pluginpath" 的方法,目前失效,主要是 找不到符号了,那此pluginpath 也就没有意义了.
5 ** 主进程加载的so 必须保持其他包不发生任何改变, 否则会报错:plugin was built with a different version of package plugin.test/main/iface plugin5.so
6 一旦发生 5 的报错, 由于1 的原因, 即使plugin5.so 修改为正确的plugin,还是无法重新加载, 因为已经进入内存,不会再次读取本地文件了.所以只能通过3 用新的so包名

7 ** 关于闭包, 不管是函数还是struct{}, 不同包下面的 相同函数地址是不同的.所以 如果把 func() 保存起来闭包执行,请确保 从一个会改变的入口函数.

 

动态库中, 非main包的的代码修改能做热更新么?
不能!(崩溃了吧, 我提了一个issue: https://github.com/golang/go/issues/20554)

如果确实做了修改, 底层会报错: plugin was built with a different version of package

解决方法: 修改plugin包底层实现并重新编译 打开runtime/plugin.go, 注释以下代码 for _, pkghash := range md.pkghashes { if pkghash.linktimehash != *pkghash.runtimehash { return "", nil, pkghash.modulename } } 执行/usr/local/go/run.bash 重编译+测试

From https://zhuanlan.zhihu.com/p/27727950

https://zhuanlan.zhihu.com/p/27727950

  

plugin包本身设计的目的是热更新么?
plugin包其实只是支持将代码分别编译为多个动态库,动态加载后运行 并不能完全支持类似C/C++的动态库方式处理代码

所以用plugin来做热更新,目前最大的困难是 pluginpath , 以及依赖包不让修改,除非使用完全新的包名

  

 

 

 

示例代码:

https://files.cnblogs.com/files/ayanmw/plugin_reload_test-ayanmw.zip?t=1653778991

 

 

 

参考链接:

https://toutiao.io/posts/dwyqix/preview #这个plugin热加载方案不行的, 貌似 也就是 go1.8到 Go 1.10之前  才可以用.

https://colobu.com/2017/08/26/panic-on-go-plugin-Open-for-different-plugins/  #同上

https://golang.google.cn/pkg/plugin/#pkg-overview

https://cloud.tencent.com/developer/article/1914954 #Golang: 插件plugin介绍 GoodDoctor

 

 https://studygolang.com/articles/27714?fr=sidebar #Golang | 插件化方案 - Go语言中文网 - Golang中文社区

https://www.jb51.net/article/138627.htm ##原始代码 参考了这个项目. https://github.com/scgywx/myplugin/tree/master/src/engine  https://my.oschina.net/scgywx/blog/1796358

https://www.jb51.net/article/219027.htm ## 这个有点意思 主要是golang的解释器 通过二进制执行,脚本化了

 

5.1 Go版本兼容问题

插件实现和主应用程序都必须使用完全相同的Go工具链版本构建. 由于插件提供的代码将与主代码在相同的进程空间中运行, 因此编译的二进制文件应与主应用程序 100%兼容.

6. 总结

我希望您记下的关键要点:

  • 1.Go插件从v1.8版本开始支持,它目前支持Linux和Mac操作系统(不支持windows)
  • 2.Go plugin包提供了一个简单的函数集动态加载,可以帮助开发人员编写可扩展的代码.
  • 3.Go插件是使用go build -buildmode = plugin构建标志编译
  • 4.Go插件包中的导出函数和公开变量,可以使用插件包在运行时查找并绑定调用.
  • 5.Go runtime import插件的开发人员必须将插件视为黑盒子,做好各种最坏的假设

代码和资料

 

2.注意事项

之所以说这个插件方案不成熟,主要是由于主程序和插件程序之间存在很强的依赖性,比如:

1.编译的GO版本必须完全一致

2.双方依赖的公共第三方库版本必须完全一致

3.GOPATH也得保持一致,这一点可以在编译时候使用trimpath参数解决

4.插件加载之后无法卸载

这些问题短时间内好像官方也没有解决的意思,或者说无法解决。总之,Go plugin目前的应用很少,毕竟作为网络编程语言,在容器化大行其道的环境下,更新程序是一件很轻松的事情,除非有特殊需要。

5 如果一个路径已经被打开,那么将会返回一个已存在的插件。(可以看plugin.go 的代码)

 

posted @ 2022-05-29 07:34  ayanmw  阅读(3952)  评论(0编辑  收藏  举报

页脚Html代码