目 录CONTENT

文章目录

【GaussDB】解析GaussDB热补丁机制

DarkAthena
2026-01-14 / 0 评论 / 0 点赞 / 13 阅读 / 0 字

【GaussDB】解析GaussDB热补丁机制

前言

热补丁(Hot Patching)是指在程序运行过程中,无需停止或重启程序,直接对其进行修补或更新的一种技术。

作为企业级数据库软件的GaussDB,也同样有热补丁的能力。

熟悉openGauss的可能比较好奇,openGauss绝大部分的内核代码实质上都编译进了可执行程序这一个文件里,其他的动态库so文件并没有太多东西,想要修改内核行为,必然需要产生新的可执行程序。但是GaussDB应用热补丁后,可执行二进程程序文件是没有变化的,这是怎么做到的呢?

引用官方文档

特性简介

热补丁将补丁以patch文件的形式加载到正在运行的数据库进程中,达到零中断修复线上系统的目的。

客户价值

热补丁最大的优势是业务零中断加载补丁,可以在不影响业务的前提下在线解决一部分数据库内核的紧急问题。

其价值主要体现在如下两点:

  • 缩短版本发布时间,紧急问题从版本回归验证轻量化为补丁回归验证,提高了线上紧急问题的响应速度。
  • 热补丁的加载,卸载对业务无感知,提高了客户满意度。

特性描述

热补丁基于发布的代码版本生成补丁文件,然后以模块的形式插入到数据库内核运行地址空间中,通过寻找热补丁目标函数的地址,并动态地,原子地替换入口地址,重定向函数代码段至补丁文件代码段达到修复线上系统缺陷的目的。

  • 热补丁的制作通过修复特定缺陷函数,制作成模块,动态地加载到运行中的内核系统。
  • 热补丁找到目标函数,并在目标函数的入口处加入跳转指令,当目标函数被调用时,跳转到补丁区执行补丁函数。
  • 目标函数的替换和还原是原子操作CPU寄存器,热补丁可以随时随地加载和卸载,线上系统无需中断,即随时可运行最新的代码。

分析热补丁包文件

正好我拿到了一个GaussDB的热补丁包,就尝试解开来看看
DBS-GaussDB-kernel_9.0.0.HP0105.20251215165913.123656517_all.tar.gz
常规解法,

  1. DBS-GaussDB-kernel_9.0.0.HP0105.20251215165913.123656517_all\DBS-GaussDB-kernel_9.0.0.HP0105.20251215165913.123656517_noarch.tar.gz
  2. repo\DBS-GaussDB-kernel-src-9.0.0.HP0105.20251215165913.123656517-1.noarch.rpm
  3. DBS-GaussDB-kernel-src-9.0.0.HP0105.20251215165913.123656517-1.noarch.cpio
  4. opt\cloud\GaussDB-kernel\v9.0.0.HP0105-GaussDBV5-install-kylin-ha-x86_64_464fcff72a80c567890b584106ffce9613b1b511defcfda44e14a32cbb7ccfbf.tar.gz
  5. GaussDB-Kernel_506.0.0.SPC0100.HP0105.pat

一路解压,得到了一个pat文件,查看二进制文件头,1F8B08,似乎是gzip,于是当成tar.gz解压,得到了
GaussDB-Kernel_KERNELHP_506.0.0.SPC0100.0105.pat

查看这个文件的可见字符(LINUX下直接string就行)

PS D:\test> $b=[System.IO.File]::ReadAllBytes('GaussDB-Kernel_KERNELHP_506.0.0.SPC0100.0105.pat'); $s= -join ($b | ForEach-Object {[char]$_}); $matches=[regex]::Matches($s,'[ -~]{6,}'); $matches.Value | Select-Object -First 1000
CodeLen = 2776;DataLen = 192;FuncAmount = 2;CreationTime(GMT) = 2025-12-10 09:14:56;ExecInfo=gaussdb,{ProgVersion=GAUSSDBV500R002C10;InnerPatNo=1;CodeAddr=0;DataAddr=0;PatchVersion=b4a4e2e7da3e9be0b59027ff6ed9bf1;PatAreaAddr=0;ProgType=58;NetType=1;ProgID=A247;};
AWAVAUATI
8[A\A]A^A_]
AWAVAUATI
8[A\A]A^A_]
1. fix index skip scan
gaussdb
GAUSSDBV500R002C10
_ZN12UBTreeSearch22find_first_index_tupleEP17IndexScanDescData13ScanDirectionRt
_Z23_find_first_index_tupleP17IndexScanDescData13ScanDirectionRt
_Z16_bt_get_endpointP12RelationDatajb
t_thrd
__tls_get_addr
_Z19_bt_preprocess_keysP17IndexScanDescData
u_sess
_Z10_bt_getbufP12RelationDataji
_Z10_bt_relbufP12RelationDatai
_Z14buffer_releasei
_Z10_skip_freeP17IndexScanDescData
_Z13_bt_walk_leftP12RelationDataij
_ZN12UBTreeSearch13get_end_pointEP12RelationDatajb
_ZN12UBTreeSearch9skip_freeEP17IndexScanDescData
.text._Z23_find_first_index_tupleP17IndexScanDescData13ScanDirectionRt
.text._ZN12UBTreeSearch22find_first_index_tupleEP17IndexScanDescData13ScanDirectionRt      
2023-07-04 21:00:00

可以观察到这个里面包含了补丁的说明信息以及c++的一些符号,基本能判断是用于修复索引跳扫的一个BUG。
(本文仅对内核的热补丁进行分析,如果是CM/OM的,解压到这一层后需要再次当成tar.gz解压,能直接得到用于替换的完整文件)

那么补丁是怎么生效的呢?

找一个已经打了补丁的环境,在gaussdb的app目录直接搜索pat文件,可以找到
./hotpatch/pat目录,里面有解压前的pat文件和解压后的pat文件。但是gaussdb进程对这些文件并没有持有句柄。

查看文档,补丁还有一个激活过程,可以使用gs_om/gs_hotpatch/gs_ctl来激活热补丁,当然前面两个最终还是调用的gs_ctl

gs_om -t hotpatch -n NAME -c [load | unload | active | deactive | info | recover | cleanLock]
gs_hotpatch -t [load|unload|active|deactive|info|list|recover|cleanLock|setLock] -n PATCH_NAME [-X XMLFILE] [-S SOURCE_IP]
gs_ctl hotpatch  [-D DATADIR] [-a ACTION] [-n NAME]

热补丁要生效,还需要加载进内存,再激活,这就一个动态注入(游戏开外挂了)。

参考openGauss源码

其实在openGauss里,虽然文档没有说支持热补丁功能,但是源码里依然能找到hotpatch的相关代码,其核心代码就在pg_ctl.cpp里。

但是制作热补丁的方法似乎并没有开源,因此openGauss的热补丁代码在这里就没有意义了。

不过还是可以用AI来分析一下openGauss里现有这部分代码的实现机制

User: 分析整理hotpatch相关的原理机制,注意使用中文回复

GitHub Copilot: Searched for regex hotpatch|hot patch|hot_patch|HotPatch (**/src/**), 200 results

Read

Read

Read

Read

Read

Searching for regex check_and_process_hotpatch|hotpatch_remove_signal_file (**/src/**)

Searched for files matching **/src/**/hotpatch*.*, 7 matches

Searched for regex under_patching|hotpatch cmd|hotpatch.ret|hotpatch.cmd (**/src/**), 21 results

Read , lines 5400 to 5690

Searched for text check_and_process_hotpatch (**/src/**), 2 results

Read , lines 11220 to 11360

Searched for text hotpatch (**/src/gausskernel/process/postmaster/**), 12 results

Read , lines 980 to 1100

Read , lines 2900 to 2985

Searched for text hotpatch_remove_signal_file (**/src/**), 2 results

Searched for text hotpatch (**/src/gausskernel/**), 51 results

Searched for text hotpatch (**/src/gausskernel/storage/replication/walreceiver.cpp), 2 results

热补丁机制概览

  • 编译开关:SUPPORT_HOTPATCH 控制是否启用,启用后链接外部 distribute/lib/hotpatch 提供的闭源实现,并在 gaussdb 链接时添加专用链接脚本(原子性/跳转表);见 Makefile。
  • 库接口:头文件 hotpatch.h 暴露 hotpatch_initexec_hotpatch_command 等 API;状态值 HP_STATE_UNLOAD/DEACTIVE/ACTIVED 和错误码枚举定义在同文件。客户端辅助接口在 hotpatch_client.h。
  • 进程启动时初始化:Postmaster 在启动阶段调用 hotpatch_remove_signal_file 清理历史信号文件后,执行 hotpatch_init(DataDir, gs_hotpatch_log_callback)(见 postmaster.cpp)。日志回调将库输出转成 ereport
  • 运行时入口:Postmaster 主循环每轮调用 check_and_process_hotpatch()(同文件约 L11278),它由热补丁库实现,用于检查是否有新的补丁命令需要处理。触发方式是 SIGUSR1 信号;信号由客户端工具 gs_ctl hotpatch 发送。
  • 客户端工作流(pg_ctl.cpp):
  1. 校验动作 list/load/unload/active/deactive/infolist 会转换成内部动作 check
  2. 写指令文件 hotpatch.cmd.tmp(包含发起进程 pid、补丁包路径、动作),fsync 后原子重命名为 hotpatch.cmd
  3. 通过 hotpatch.lock 加锁清理上一次的结果文件 hotpatch.ret,防止并发补丁。
  4. 向 postmaster 发送 SIGUSR1
  5. 轮询等待 hotpatch.ret(最多 2000 次,1ms 间隔)。匹配到自身 pid 后读取结果字符串。若是 list,再读取 hotpatch/patch.info 中的补丁列表并打印状态。
  • 结果与状态文件:
  • hotpatch.ret:由后台写入,首字段是 pid,后跟结果字符串([PATCH-SUCCESS] 前缀代表成功)。
  • hotpatch/patch.info:由热补丁库维护,头部记录最大补丁条目,后续记录每个补丁的名称和状态,客户端用来实现 list。解析逻辑见 hotpatch_client.cpp。
  • 补丁包与工具:测试用例(hotpatch.source)显示补丁包扩展名为 .pat,典型流程为 load -> active -> info/list -> deactive/unload。构建脚本提示需要外部仓库 GaussDBKernel-hotpatch 提供的工具 makepatchfastcheck 等,并通过 PATCHLIB_HOME 软链接到 distribute/lib/hotpatch/tool/sample/
  • 约束与并发控制:
  • 通过锁文件确保一次只能有一个补丁操作;若无法删除旧结果文件则直接报错退出。
  • 等待超时(约 2s)会报 [PATCH-ERROR]: Hotpatch timeout!
  • 能见度与缺失:热补丁实际注入/回滚逻辑位于预编译的 hotpatch.o / libhotpatchcommon.a 等闭源组件,源码仓库未包含其实现;从接口和文件协议可知其工作模式是“命令文件 + 信号 + 结果文件”的 out-of-band 控制通道。

可选后续

  1. 如果需要进一步理解注入细节,需查看 distribute/lib/hotpatch 提供的源或文档(原子跳转、符号重定位策略等)。
  2. 如需验证流程,可在测试环境运行 gs_ctl hotpatch -D <data> -a load -n <patch.pat> 并观察 hotpatch.cmd/ret/patch.info 的生成与状态变化。
  3. 若要新增监控或告警,可在 hotpatch_wait_and_get_replyinfo_from_node 周围增加日志或延长等待窗口,避免 2s 超时导致的误报。

的确有启动时加载和运行时加载的逻辑,不过最核心的注入逻辑闭源了(个人感觉如果开源,风险极大)。

总结

本次通过手动解压热补丁包、参考openGauss源码以及GaussDB官方文档,基本了解了GaussDB热补丁原理,可供大家参考。

0
  1. 支付宝打赏

    qrcode alipay
  2. 微信打赏

    qrcode weixin
博主关闭了所有页面的评论