Golang Go语言新玩具来了 go-hotfix,用于运行时热修复函数

基于 monkey-patch + plugin 机制实现的热修复方案,用于实现不停服修复 bug!!

仓库地址: https://github.com/go-hotfix/hotfix

感兴趣可以玩一下 example/webapp 这个例子,注意仅支持 Linux ( ps: Windows 可以在 wsl2 里面玩)

hotfix

hotfix is a golang function hot-fix solution


警告: 目前尚未经过严格测试,请勿用于生产环境
Warning: This has not been rigorously tested, do not use in production environment

注意: 不支持 Windows
Note: Windows is not supported

注意: 为了确保函数都能被修补,需要关闭函数内联,会因此损失一些性能
Note: To ensure that all functions can be patched, function inlining needs to be disabled, which will result in a loss of some performance

Features

  • 支持指定包级别/类级别/函数级别热补丁支持
  • Supported for hot patching at package/class/function
  • 支持导出函数/私有函数/成员方法修补
  • Support for exporting functions/private functions/member methods patching
  • 基于monkey-patch + plugin机制实现
  • Implemented based on monkey-patch + plugin
  • 线程安全, 使用 stw 确保所有协程都进入安全点从而实现线程安全的补丁
  • Thread safety, use stw to ensure that all coroutines enter safe points to hot patching

Limits

  • 受限于go plugin仅支持 Linux, FreeBSD, macOS ,其他平台目前不支持
  • The go plugin is currently only supported on Linux, FreeBSD, and macOS platforms; other platforms are not supported
  • 加载的补丁包无法卸载,如果热修复次数过多可能导致较大的内存占用
  • The loaded patch package cannot be uninstalled. Too many hot fixes may result in large memory usage
  • 不支持对闭包进行修复,需要热修复的逻辑不要放在闭包中
  • Closures are not supported, and logic that requires hotfixes should not be placed in closures
  • 不能修改已有数据结构和函数签名,否则可能将导致程序崩溃,应该仅用于 bug 修复
  • Cannot modify existing data structures and function signatures, as this may lead to program crashes. It should only be used for bug fixes
  • 编译时请保留调试符号,并且禁用函数内联-gcflags=all=-l
  • Please keep the debugging symbols when compiling, and disable function inline -gcflags=all=-l
  • 编译错误invalid reference to xxxx 是因为 go1.23开始限制了go:linkname功能,必须添加编译参数关闭限制-ldflags=-checklinkname=0
  • The compilation error invalid reference to xxxx is because go1.23 began to limit the go:linkname function, and the compilation parameter must be added to turn off the restriction -ldflags=-checklinkname=0
  • 补丁包的的编译环境必须和主程序一致,包括 go 编译器版本,编译参数,依赖等,否则加载补丁包将会失败
  • The patch package's build environment must match that of the main program, including the Go compiler version, compilation parameters, dependencies, etc., otherwise loading the patch package will fail
  • 补丁包的main包下面的init会首先调用一次,请注意不要重复初始化
  • The 'init' under the 'main' package of the patch package will be called once first, be careful not to initialize it repeatedly
  • 打补丁包时main包必须产生变化,否则可能出现 plugin already loaded错误,推荐使用 -ldflags="-X main.HotfixVersion=v1.0.1"指定版本号, 确保每次编译补丁包都会有变化
  • The main package must be changed when applying the patch package, otherwise the plugin already loaded error may occur. It is recommended to use -ldflags="-X main.HotfixVersion=v1.0.1" to specify the version number to ensure that the patch package is compiled every time There will be changes
  • 该方案处于实验性质,尚未经过严格验证
  • The solution is experimental in nature and has not yet been rigorously validated

Example

参考这个例子项目
Refer to this example project


Golang Go语言新玩具来了 go-hotfix,用于运行时热修复函数
14 回复

看着不错,学习下

更多关于Golang Go语言新玩具来了 go-hotfix,用于运行时热修复函数的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


用 plugin 标准库的话项目得编译成动态链接的 ELF ,就这一点已经很难受了

不用拆分代码,原来编译成 exe 的项目,只需要额外加一个编译成 plugin 就行,可以参考 demo ,不需要做任何代码的拆分,直接编译 plugin 就行

很好,我用 k8s 滚动发布

#3 没懂我的意思。用 Go 的项目一般都是静态链接,一个 ELF 扔上去完事儿。你这个工具用到了 plugin 标准库,用这个工具的话项目必须得动态链接。你可以把 example 编译成静态链接的 ELF ,然后再试试能不能 hotfix 。

按照之前玩儿 go plugin 的经验,这东西还是有点难用的,加载之后不能卸载 + 出问题不好排查。而且还有一个问题就是,monkey patch 这东西原作者 license 里明确说了不授权任何人使用,这么搞没版权问题么。

点了下帖子里的 monkey patch 链接是跳到了 gohook ,看来不是用的之前我看到过的那个 monkey patch 的库。

目前的默认实现是 gohook 也支持使用自定义的 patch 库

参考这个脚本 https://github.com/go-hotfix/hotfix/blob/main/example/webapp/run_webapp.sh

# 这里静态编译主程序
echo “build webapp…“
go build -gcflags=all=-l -ldflags=”-X main.HotfixVersion=main” -o webapp .

echo "please modify v1 plugin, press enter key to continue…"
read input

# 这里是编译为 so 动态库( plugin )
echo “build webapp plugin v1…“
go build -gcflags=all=-l -buildmode=plugin -ldflags=”-X main.HotfixVersion=v1” -o webapp_v1.so .

不知是否是你说的这种情况

确实如此,缺点和限制都很多,除了必要情况下一般也不会去使用它

k8s 不错,特别是无状态应用几乎可以做到无感更新,但是对于一个长期运行的有状态服务器,比如游戏服务器,k8s 通常不是首选运行环境,业界通常利用 ab/滚动更新的方式来实现更新,但是这种方式更新非常的慢,通常需要以小时为单位计,如果有刷装备/金币的 bug 等到几个小时恐怕全服玩家都刷个遍了 🤣

#9 你确定这样编译出来的主程序是静态链接的?用 file 命令确认下吧。如果真是静态链接的,调 plugin.Open() 的时候会报 plugin: not implemented 错误的。

你的意思是关闭 cgo ,那肯定的都用 plugin 了 cgo 是需要启用的不然肯定无法加载插件了,这个方案也是要求启用 cgo ,因为本质上 plugin open 就是调用 dlopen 加载的

关于您提到的“go-hotfix”这一用于Go语言运行时热修复函数的工具,确实是一个值得关注的创新。在快速迭代的软件开发环境中,能够在不重启服务的情况下修复线上bug,对于提升系统的稳定性和维护效率具有重要意义。

go-hotfix通过动态替换运行时函数的方式实现了热修复功能。它允许开发者在运行时动态地加载并应用新的函数实现,从而替代原有的存在缺陷的函数。这种技术不仅能够显著减少因修复bug而带来的服务中断时间,还能够提高系统的可用性和用户体验。

然而,值得注意的是,使用go-hotfix也带来了一定的技术挑战和风险。首先,热修复需要在不破坏现有程序状态的前提下进行,这就要求开发者对程序的内存布局和运行时有深入的理解。其次,由于go-hotfix直接操作运行时内存,因此可能会引入新的稳定性和安全性问题。

因此,在使用go-hotfix时,建议开发者充分测试其功能,并谨慎评估其可能带来的风险。同时,也需要注意go-hotfix与Go语言社区和生态的兼容性,以确保其能够长期稳定地为Go语言开发者提供热修复支持。

总的来说,go-hotfix为Go语言开发者提供了一种强大的运行时热修复工具,但使用时需要权衡其带来的好处和风险。希望这一工具能够为您的项目带来便利,并推动Go语言技术的不断发展。

回到顶部
AI 助手
你好,我是IT营的 AI 助手
您可以尝试点击下方的快捷入口开启体验!