最近遇到一个客户k8s测试集群经常崩溃,最终定位是etcd磁盘IO性能不足,最终替换成ssd盘解决,记录一下排查过程。
集群是跑在客户的共享虚机上,磁盘是机械硬盘,问题现象如下:
kube-system下涉及高可用的组件 kube-apiserver、kube-controller-manager、kube-scheduler 频繁重启,某些选主模式的组件、服务反复重启,频繁CrashLoopBackoff,查看其日志有"leaderelection lost",“timed out waiting for xxx”等字样
kubectl 反应慢,使用 kubectl get no --v=7,两三秒内才返回结果
查看kube-apiserver日志,看到有“etcdserver: request timed out”、“etcdserver:leader changed”等字样
查看etcd日志,有较多“xxx took too long”,“lost leader”等字样,time spent达到了几百ms,甚至两三秒
从现象上看,问题很可能出现在etcd上~
etcd性能瓶颈及稳定性分析链路图:
图片来源:极客时间《etcd实战课》
etcd集群性能受磁盘IO、时钟同步、master之间的网络以及节点负载影响,根据经验,磁盘IO导致的可能性较大。
1、时间同步验证
使用pssh工具,或ssh 机器执行date命令,对比时钟差异是否超过1s。时钟不同步,可以使用chrony或ntp或自建时钟源,将集群所有节点连接到同一时钟源,确保时钟同步。参考:Chrony详解:代替ntp的时间同步服务
2、master节点负载、CPU、MEM、IO、NET等检察,查看系统日志是否有明显报错,比如硬件报错,OOM(out of memory)等
使用top,iostat,iftop,iotop,sar,netstat,vmstat查看系统基础指标
使用scp,ipref,dd,fio等工具测试网络及磁盘性能:
# 制作1GB文件 dd if=/dev/zero of=/tmp/test-net bs=1M count=1000 # 测试传输速度 scp /tmp/test-net root@$master2:/tmp/ scp /tmp/test-net root@$master3:/tmp/
一般来说千兆带宽得达到约125MiB/s的传输速度;大规模集群( 500节点)需要万兆带宽,网络需要达到约1250MiB/s的传输速度。
etcd应用层提供了节点之间网络统计的metrics指标,分别如下:
etcd_network_active_peer,表示peer之间活跃的连接数;
etcd_network_peer_round_trip_time_seconds,表示peer之间RTT延时;
etcd_network_peer_sent_failures_total,表示发送给peer的失败消息数;
etcd_network_client_grpc_sent_bytes_total,表示server发送给client的总字节数,通过这个指标我们可以监控etcd出流量;
etcd_network_client_grpc_received_bytes_total,表示server收到client发送的总字节数,通过这个指标可以监控etcd入流量。
可以使用监控系统监控etcd网络指标,使用相关工具查看是否出现丢包等错误。
# 4k写 fio -direct=1 -iodepth=128 -thread -rw=write -ioengine=libaio -bs=4k -size=1G -numjobs=1-runtime=600 -group_reporting -name=mytest -filename=/var/lib/etcd/iotest # 4k读 fio -direct=1 -iodepth=128 -thread -rw=read -ioengine=libaio -bs=4k -size=1G -numjobs=1-runtime=600 -group_reporting -name=mytest -filename=/var/lib/etcd/iotest # 4K随机写(随机写IOPS 不要直接写设备,很危险!!!): fio -direct=1 -iodepth=128 -thread -rw=randwrite -ioengine=libaio -bs=4k -size=1G -numjobs=1-runtime=600 -group_reporting -name=mytest -filename=/var/lib/etcd/iotest # 4K 随机读 fio -direct=1 -iodepth=128 -thread -rw=randread -ioengine=libaio -bs=4k -size=1G -numjobs=1-runtime=600 -group_reporting -name=mytest -filename=/var/lib/etcd/iotest # 1M写 fio -direct=1 -iodepth=64 -thread -rw=write -ioengine=libaio -bs=1M -size=8G -numjobs=1-runtime=600 -group_reporting -name=mytest -filename=/var/lib/etcd/iotest # 1M读 fio -direct=1 -iodepth=64 -thread -rw=read -ioengine=libaio -bs=1M -size=8G -numjobs=1-runtime=600 -group_reporting -name=mytest -filename=/var/lib/etcd/iotest
Master配置一块独立块设备:SSD是首选(建议大小 >= 50G),推荐 [SSD 4K IOPS>=3300] 或 [企业级SAS硬盘rpm>=10000,最好15000] 或 [更高配置的NVMe)],参考:Linux系统下查看硬盘转速
小型集群:500-1000 IOPS(如开发/测试环境)。
生产集群:1000-3000 IOPS(50 节点以内)。
大规模集群:3000+ IOPS + 低延迟网络。
3、kubectl descrbe node查看节点负载信息,在输出中检查 Allocated Resources 和 Conditions 部分,可以将占用高的无状态应用迁走,减轻master节点压力
Conditions
描述了节点的状态。Condition的例子有:
Node Condition | 描述 |
---|---|
OutOfDisk | 如果节点上的空白磁盘空间不够,不能够再添加新的节点时,该字段为 True ,其他情况为 False |
Ready | 如果节点是健康的且已经就绪可以接受新的 Pod。则节点Ready字段为 True 。False 表明了该节点不健康,不能够接受新的 Pod。 |
MemoryPressure | 如果节点内存紧张,则该字段为 True ,否则为False |
PIDPressure | 如果节点上进程过多,则该字段为 True ,否则为 False |
DiskPressure | 如果节点磁盘空间紧张,则该字段为 True ,否则为 False |
NetworkUnvailable | 如果节点的网络配置有问题,则该字段为 True ,否则为 False |
最后排查发现master节点网络、节点负载、时间同步都正常,环境由于是共享虚拟机环境,机器IO性能很可能存在欺骗现象。
etcd性能不足原因定位:
1、检查 etcd 状态:
kubectl get pods -n kube-system -l component=etcd
2、查看 etcd 日志: