文章摘要
ClickPipes团队在处理Postgres逻辑复制槽创建时遇到一个棘手问题:查询耗时异常且无法通过常规方法终止,导致客户不满并威胁生产数据库的稳定性。通过深入调查,发现这是Postgres的一个bug。文章详细介绍了问题的排查过程、解决方案以及与Postgres社区合作的经验。
文章总结
文章标题:当SIGTERM无效时:Postgres的一个谜团
主要内容总结:
问题背景:
- ClickPipes团队在Postgres的只读副本上创建逻辑复制槽时遇到了一个严重问题:某些查询耗时过长,且无法通过常规方法终止,导致客户不满并威胁生产数据库的稳定性。
初步调查:
- 通过检查
pg_stat_activity表,发现创建逻辑复制槽的查询处于“active”状态,但没有等待事件,表明Postgres认为该查询并未被阻塞。 - 尝试使用
SIGINT和SIGTERM信号终止该查询,但均无效。这导致复制槽无法被删除,进而可能导致WAL日志无限累积,引发存储耗尽的风险。
- 通过检查
深入分析:
- 通过
strace工具分析,发现后台进程处于一个1ms的nanosleep循环中,表明进程在等待某些事务完成。 - 进一步研究发现,Postgres在创建逻辑复制槽时需要等待所有早于该槽创建的事务完成,以确保一致性。然而,在只读副本上,由于无法直接获取主库上的事务锁,导致进程陷入无限等待。
- 通过
问题根源:
- 在只读副本上,Postgres的
XactLockTableWait函数无法像在主库上那样通过锁机制高效等待事务完成,而是通过1ms的轮询循环进行等待。由于该循环未处理中断信号,导致进程无法被终止。
- 在只读副本上,Postgres的
解决方案:
- 提交了一个补丁,在每次
pg_usleep调用前添加中断检查,使得进程可以被正常终止。该补丁被Postgres社区迅速接受并向后移植到所有支持的版本中。 - 社区成员还提出了进一步改进的建议,包括添加新的等待事件和优化只读副本上的事务等待机制。
- 提交了一个补丁,在每次
总结与建议:
- 该问题展示了现代数据库系统在复杂场景下可能出现的边缘情况。Postgres和ClickHouse作为开源数据库,允许用户深入调查问题并提交补丁,从而共同提升系统的稳定性和性能。
- 对于需要从Postgres复制数据到ClickHouse的用户,推荐使用ClickPipes或PeerDB,它们提供了高效的数据复制解决方案,并支持在只读副本上进行CDC操作。
图片标记:
- 
评论总结
关于固定睡眠时间的使用:
- 观点:在程序中使用固定的睡眠时间通常是错误的,因为它要么太长,要么太短,且无法保证程序会精确地睡眠所请求的时间。
- 论据:
gsliepen提到:“Virtually any time you put a fixed sleep in your program, it's going to be wrong.”(几乎每次在程序中使用固定睡眠时间都是错误的。) - 建议:使用条件变量或其他类似机制更为合适。
关于信号处理的复杂性:
- 观点:Postgres 作为长期运行的服务器进程,其信号处理机制复杂,某些循环可能无法及时处理信号。
- 论据:
Joker_vD指出:“Postgres, as any long-running 'server' process, does not run with SIGDFL as the handler for SIGTERM.”(Postgres 作为任何长期运行的“服务器”进程,不会使用 SIGDFL 作为 SIGTERM 的处理程序。) - 担忧:
eunos表示:“With quirk like these, honestly I'm not even confident how can PostgreSQL or any software in general can be used in mission critical system.”(对于这些怪癖,老实说,我对 PostgreSQL 或任何软件在关键任务系统中的使用都没有信心。)
关于信号处理测试的重要性:
- 观点:在边缘条件下,Postgres 进程可能会忽略 SIGTERM 信号,建议在故障转移或副本维护期间测试信号处理。
- 论据:
OkPin提到:“Makes me wonder how many other Postgres processes might ignore SIGTERM under edge conditions.”(让我想知道在边缘条件下,还有多少其他 Postgres 进程可能会忽略 SIGTERM。) - 建议:将信号处理测试添加到混沌测试中。
关于开源项目的贡献流程:
- 观点:Postgres 和 Linux 内核等大型开源项目使用邮件列表进行贡献,虽然流程可能较为古老,但效率较高。
- 论据:
bhaak指出:“The Linux kernel works the same way.”(Linux 内核的工作方式相同。) - 对比:
bhaak提到:“If I were a regular contributor to a big project using GitHub, me being me, I would probably look for or write myself a GitHub to e-mail gateway.”(如果我是使用 GitHub 的大型项目的常规贡献者,我可能会寻找或自己编写一个 GitHub 到电子邮件的网关。)
关于同步与异步方法的冲突:
- 观点:在异步事件驱动的上下文中使用同步的、基于锁的方法会导致问题,建议采用基于事件监听的方法。
- 论据:
gpavanb指出:“The fundamental problem is that a synchronous, lock-based approach is being used in an asynchronous, event-driven context.”(根本问题在于在异步事件驱动的上下文中使用了同步的、基于锁的方法。) - 建议:Postgres 团队需要重新设计,避免轮询,采用基于事件监听的方法。
关于类似问题的普遍性:
- 观点:Postgres 在其他情况下也可能表现出类似的行为,建议将解决方法推广到其他类型的故障。
- 论据:
caffeinated_me提到:“This isn't the only place Postgres can act like this, though.”(这并不是 Postgres 唯一表现出这种行为的地方。) - 建议:将解决方法推广到处理其他类型的故障。