当 etcd 崩溃时,首先检查磁盘
Source: Hacker News
(请提供需要翻译的正文内容,我才能为您进行简体中文翻译。)
来自云‑边缘连续体测试平台的洞见
为计算机视觉演示搭建云‑边缘连续体测试平台让我们领悟到分布式系统的一个基本原则:
etcd不会宽恕慢速存储。
Source: …
演示环境
我们一直在为 MLSysOps 构建演示——一个框架,能够通过自定义策略(简单的或基于机器学习的)在云‑边‑物联网连续体上定制应用的部署和运行时行为。
其目标是展示基于遥测的策略如何动态地调整 应用运行的位置 和 运行方式,而无需开发者或运维人员手动干预。
架构
- 连续体编排器: Karmada,位于各个 k3s 集群之上。
- 应用: 一个执行实时目标检测的计算机视觉流水线。
- 硬件节点:
- Intel NUC
- Raspberry Pi
- Jetson AGX Orin
有关搭建测试平台的更多细节,请参阅 MLSysOps GitHub 仓库。

演示流程
- 目标检测工作负载被部署并在 Raspberry Pi 本地运行。
- 当 Pi 开始吃力(帧率下降,推理延迟上升)时,MLSysOps 代理通过遥测检测到性能退化。
- 策略透明地将 vAccel 后端切换到指向 Jetson AGX Orin。
- 工作负载被卸载到强大的 GPU 上,实时目标检测恢复,唯一的变化是策略的执行——无需重新部署,也无需手动干预。

我们学到了什么
在我们能够讲述那个故事之前,我们首先必须让集群启动并运行——这比我们预期的更有趣。
四节点集群在三台物理机器上

Karmada 将自己的状态存储在 etcd 中,独立于为每个 Kubernetes 集群提供支持的 etcd 实例。在 k3s 中,这个 etcd 已嵌入到 k3s 二进制文件里,因此我们无需管理单独的 etcd 进程。
由于 Karmada 的宿主机必须运行自己的 etcd,它必须是一个 专用节点,与它所编排的集群相互独立。鉴于只有三台物理机器可用且希望演示保持自包含,我们采用了以下布局:
| 物理机器 | 角色 |
|---|---|
| NUC | • VM 1 – Karmada 主机(etcd) • VM 2 – k3s 控制平面 |
| Raspberry Pi | k3s 集群的工作节点 |
| Jetson | k3s 集群的工作节点 |
这种安排既合乎逻辑又实用,但它也带来了一个我们后来才发现的细微问题。
症状:Pod 无法保持运行
在安装 Karmada 后,我们开始注意到 Karmada 自己的 pod 每隔五到十分钟就会崩溃——规律、可预测、令人抓狂。
这些崩溃并没有立即提供有用信息。pod 会重新启动,运行一段时间后再次崩溃。应用层看起来没有问题。
k3s 集群本身看起来是健康的。我们检查了常见的嫌疑——资源限制、网络、重启之间的配置漂移——但没有发现问题。
调查变得相当细致。我们开始在日志中寻找每一根线索,关联时间戳,寻找死亡事件及其时间的模式。
Source: …
根本原因:etcd 与 I/O 延迟
最终日志指向了一个意想不到的地方:etcd 超时。
它并不是因为 Karmada 本身的 bug 或配置错误而崩溃,而是底层存储响应不够快,未能满足 etcd 的预期。
etcd 是一个强一致性的分布式键值存储,这种一致性是有代价的:它对 I/O 延迟极其敏感。它使用预写日志,并依赖 fsync 调用在严格的时间窗口内完成。当存储变慢——即使是间歇性的——etcd 就会错过内部的心跳和选举截止时间,导致选举失败、集群失去多数,依赖 API Server 的 Pod 也随之死亡。
NUC 上的虚拟机共享宿主机的存储,在默认配置下 I/O 性能不够稳定,无法让 etcd 正常工作。提升 etcd 的超时阈值只能稍微缓解问题,却没有根本解决;它只是把故障阈值向后搬移。真正的问题在于存储本身。
解决方案:在 NUC 上调优 ZFS
在对 ZFS 存储后端进行优化——调整写入提交的激进程度以及 I/O 调度方式后——延迟特性得到改善,etcd 不再超时,Pod 崩溃停止,集群恢复稳定。
以下 ZFS 属性被应用到承载虚拟机的 dataset:
zfs set sync=disabled default # Disable synchronous writes
zfs set compression=lz4 default # Use fast LZ4 compression
zfs set atime=off default # Disable access‑time updates
zfs set recordsize=8k default # Smaller record size for etcd writes
各设置的作用
| 设置 | 效果 | 为什么有助于 etcd |
|---|---|---|
sync=disabled | ZFS 在不等待数据实际写入磁盘的情况下立即确认写入。 | fsync 调用瞬间返回,消除了导致 etcd 超时的延迟。(风险:断电时最近的写入可能会丢失。) |
compression=lz4 | 启用透明的 LZ4 压缩。 | 减少写入磁盘的数据量;LZ4 速度快,CPU 开销可忽略,提升整体 I/O 吞吐。 |
atime=off | 禁用每次读取时更新“最后访问时间”。 | 防止读密集型工作负载产生额外写入,降低 I/O 压力。 |
recordsize=8k | 将 ZFS 块大小设为 8 KB(默认 128 KB)。 | 与 etcd 的小块随机读写对齐,降低写放大。 |
这些设置共同让 ZFS 不再过于保守,而是追求速度。sync=disabled 是阻止 etcd 崩溃的关键因素;其余三个设置提供额外的 I/O 缓解,并且通常是面向性能调优工作负载的良好做法。
注意: 在生产环境中,需要权衡
sync=disabled(断电时可能导致数据丢失)的风险与性能提升之间的利弊。对于共享存储上的演示 VM,这种权衡是可以接受的,但生产级etcd集群应使用更持久的配置。
课程:当 etcd 崩溃时,检查你的磁盘
这是值得内化的模式。如果你在运行 Karmada(或任何嵌入 etcd 的 Kubernetes 相关系统),并且看到周期性的 Pod 崩溃但没有明显的应用层原因,那么第一个要问的问题是:
在 etcd 工作负载下,存储的表现如何?
etcd 文档实际上已经指出这一点:它推荐使用 SSD,并警告不要在与其他 I/O 密集型工作负载共享的存储上运行 etcd。
- 在生产集群中,你通常会为
etcd节点提供 专用存储。 - 在共享硬件上运行虚拟机的演示环境中,这一点很容易被忽视。
需要运行的诊断
-
Prometheus 指标 –
etcd暴露了一套丰富的指标。需要关注的指标有:etcd_disk_wal_fsync_duration_secondsetcd_disk_backend_commit_duration_seconds
如果任一指标的 第 99 百分位 持续 > 100 ms,说明是存储问题,而不是配置问题。
-
存储基准测试 – 在机器上安装
etcd之前,对其将使用的存储路径进行快速基准测试。使用fio等工具可以得到读取/写入延迟的基线概况。
# 示例 fio 命令(根据需要调整路径、大小和运行时间)
fio --name=etcd-bench --filename=/var/lib/etcd/data \
--rw=randwrite --bs=4k --iodepth=32 --numjobs=4 \
--time_based --runtime=60 --group_reporting
如果基准测试显示高延迟或低 IOPS,请考虑将 etcd 移动到更快的专用 SSD 存储上。这个简单的检查常常能在 Pod 因无明显原因持续崩溃时,节省数小时的排查时间。
返回演示
一旦集群稳定下来,实际演示很快就搭建完成。MLSysOps 策略层按预期工作,遥测显示 Raspberry Pi 的帧率落后,策略被触发,vAccel 后端切换到 Jetson AGX Orin,目标检测瞬间实现实时。网络跳转仍然存在,但 GPU 使其变得无关紧要。
这是一场有力的演示,展示了自适应、策略驱动的编排在异构边缘环境中能够实现的效果。我们只需克服一次磁盘 I/O 问题即可。

有时最有价值的调试过程恰恰是答案与你原本关注的方向完全正交。etcd 让我们认识到分布式系统对其基础设施有强烈的偏好——值得倾听它们。