协助排查了一次容器内进程的性能问题
症状: 平台上容器内的 redis cluster 进程用 redis-benchmark 测试能稳定复现 spike, 但是同宿主机上的 redis 没有问题
- 首先怀疑 SDN, 因为没问题的 redis 是 host 网络. 理论上这很难查, 但是在部署了一个 SDN 网络的 redis 后发现依然没有问题, 我比较有把握不是网络问题, 不过也不是特别确定, 因为 redis cluster 的节点跨主机, 说不清楚会发生什么.
- 建立最小可复现问题的现场. 我们应该从几乎一模一样的环境(相同的容器里)重建一个拥有相同节点, 相同配置, 相同数据, 只是监听不同端口的集群, 理论上这个集群应该是能复现问题的.
- 然后一点点缩小问题的范围, 看到那一步就突然不能复现
- 摘掉所有的 slave nodes
- 把进程放到宿主机裸跑
- 把集群放到同一个宿主机
- 用 host 网络
- 结果发现把进程放到宿主机裸跑就没问题, 接下来继续缩小范围:
- 放到同一个 network ns 下运行
- 放到同一个 mount ns 下
- 放到同一个 cgroup 下
- 其他 ns
- 令人吃惊的是裸跑进程放到和有问题的进程同一 net ns 下居然没有复现问题, 彻底排除了 SDN 的问题, 继续查下去发现居然是 cgroup 的限制导致了性能问题.
- 一边
strace -fTp$PID -etrace=read,write
一边 benchmark 一边 tshark, 发现 spike 的 exchange 在时间上吻合一个长达 12ms 的write
调用, 去看 cgroup 里的cpu.throttled_*
, 发现throttled_time
和 spike 吻合地非常好, 就是 12ms. - 最后创建容器, 设置 CPUQuota=0, 不再复现, 实锤是 cgroup
cpu.cfs_quota_us
导致被 throttle 使得非阻塞的 write 调用耗时很长. - 内核下的问题我就不会查了, 溜了.
当然我只是辅助, 体力活都是波神做的, 第一次见识 eBPF/bcc
这种雷神之锤, 臣服, 想学.