服务器 pod 在合并期间被 OOMKilled
症状
一个一直运行正常的服务器 pod 被终止并反复重启,实例没有任何变化。该 pod 的最后状态为 OOMKilled,退出代码为 137。终止前的服务器日志显示内存限制异常,而当时执行的是后台合并,而不是用户查询。
在容器内存限制为 1Gi 时观察到此问题。持续重启最终会表现为 CrashLoopBackOff。
原因
容器内存限制是整个服务器进程的硬上限,而不仅仅是查询的上限。后台合并会重写分片,并且需要与正在合并的分片大小成比例的工作内存,因此,按照空闲使用量或轻量查询负载设置的限制,会在首次执行大型合并时超出。终止发生在合并期间,因此看起来像是无故发生:没有客户端执行任何异常操作。
这是一个容量规划问题,而不是缺陷。该行为很容易复现——operator 自身的示例包括一个特意设置得过小的 pod 模板,内存限制为 32Mi;其文档说明的结果是,服务器被 out-of-memory 处理程序终止,并且 pod 依次进入 OOMKilled 和 CrashLoopBackOff 状态。
确认
OOMKilled 和 137 可确认内核终止了容器。
读取容器上一个实例的日志:
检查配置的限制:
如果服务器运行时间足够长,可以查询服务器自身跟踪的内容:
修复
提高 pod 模板中的容器内存限制并重新应用:
指导建议:
- 不要在生产环境中以 1Gi 的限制运行实例。 应根据预期的最大合并进行容量规划,而不是根据空闲使用量。
- 将内存请求设置为与限制相等。 这样可以使 pod 保持在 guaranteed 类别中,避免节点过度分配资源而将其终止。
- 在常驻工作集之上预留足够余量。 合并内存是缓存以及并发运行的查询所需内存之外的额外内存。
- 在增加 ingest 量之前提高限制,不要等到之后再提高。分片大小会随 ingest 增长,合并内存也会随分片大小增长。
此更改会一次滚动一个主机,因此请先确认第一个主机恢复,再假定整个实例已修复。
验证
在包含实际合并活动的时间段内观察重启次数。在负载下重启次数保持稳定,才能确认问题已解决;空闲实例上的重启次数保持稳定并不能证明任何问题,因为触发终止的是合并。
持续跟踪内存使用量与限制的关系,而不是只检查一次 — 请参阅 监控。
ClickHouse 是 ClickHouse, Inc. 的注册商标。https://clickhouse.com
Alauda 是独立供应商。本产品与 ClickHouse, Inc. 没有关联,也未得到其认可或赞助。所有商标均归其各自所有者所有,此处仅用于标识目的。