新玩具来了 go-hotfix,用于运行时热修复函数 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
limpo
V2EX    Go 编程语言

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

  •  
  •   limpo
    limpo1989 2024-08-28 14:18:09 +08:00 3302 次点击
    这是一个创建于 413 天前的主题,其中的信息可能已经有所发展或是发生改变。

    基于 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

    13 条回复    2024-08-29 14:23:54 +08:00
    wswch4444
        1
    wswch4444  
       2024-08-28 18:17:36 +08:00
    看着不错,学习下
    Nitroethane
        2
    Nitroethane  
       2024-08-28 18:43:09 +08:00
    用 plugin 标准库的话项目得编译成动态链接的 ELF ,就这一点已经很难受了
    limpo
        3
    limpo  
    OP
       2024-08-28 18:44:40 +08:00
    @Nitroethane 不用拆分代码,原来编译成 exe 的项目,只需要额外加一个编译成 plugin 就行,可以参考 demo ,不需要做任何代码的拆分,直接编译 plugin 就行
    mshadow
        4
    mshadow  
       2024-08-28 19:39:42 +08:00 via Android
    很好,我用 k8s 滚动发布
    Nitroethane
        5
    Nitroethane  
       2024-08-28 22:36:03 +08:00
    @limpo #3 没懂我的意思。用 Go 的项目一般都是静态链接,一个 ELF 扔上去完事儿。你这个工具用到了 plugin 标准库,用这个工具的话项目必须得动态链接。你可以把 example 编译成静态链接的 ELF ,然后再试试能不能 hotfix 。
    azraeljack
        6
    azraeljack  
       2024-08-28 22:45:08 +08:00
    按照之前玩儿 go plugin 的经验,这东西还是有点难用的,加载之后不能卸载 + 出问题不好排查。而且还有一个问题就是,monkey patch 这东西原作者 license 里明确说了不授权任何人使用,这么搞没版权问题么。
    azraeljack
        7
    azraeljack  
       2024-08-28 22:48:32 +08:00
    点了下帖子里的 monkey patch 链接是跳到了 gohook ,看来不是用的之前我看到过的那个 monkey patch 的库。
    limpo
        8
    limpo  
    OP
       2024-08-29 08:48:35 +08:00
    @azraeljack 目前的默认实现是 gohook 也支持使用自定义的 patch 库
    limpo
        9
    limpo  
    OP
       2024-08-29 08:53:54 +08:00
    @Nitroethane 参考这个脚本 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 .

    不知是否是你说的这种情况
    limpo
        10
    limpo  
    OP
       2024-08-29 08:56:50 +08:00
    @azraeljack 确实如此,缺点和限制都很多,除了必要情况下一般也不会去使用它
    limpo
        11
    limpo  
    OP
       2024-08-29 09:00:50 +08:00
    @mshadow k8s 不错,特别是无状态应用几乎可以做到无感更新,但是对于一个长期运行的有状态服务器,比如游戏服务器,k8s 通常不是首选运行环境,业界通常利用 ab/滚动更新的方式来实现更新,但是这种方式更新非常的慢,通常需要以小时为单位计,如果有刷装备/金币的 bug 等到几个小时恐怕全服玩家都刷个遍了
    Nitroethane
        12
    Nitroethane  
       2024-08-29 12:49:33 +08:00
    @limpo #9 你确定这样编译出来的主程序是静态链接的?用 file 命令确认下吧。如果真是静态链接的,调 `plugin.Open()` 的时候会报 `plugin: not implemented` 错误的。
    limpo
        13
    limpo  
    OP
       2024-08-29 14:23:54 +08:00
    @Nitroethane 你的意思是关闭 cgo ,那肯定的都用 plugin 了 cgo 是需要启用的不然肯定无法加载插件了,这个方案也是要求启用 cgo ,因为本质上 plugin open 就是调用 dlopen 加载的
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1117 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 17:47 PVG 01:47 LAX 10:47 JFK 13:47
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86