一.问题原因
搭建正常运行好几年的基于kubeadm安装的kubernetes集群,针对etcd数据库路陆续出现以下问题
- etcd io经常报延迟过高, 会有leader频繁切换的情况
- 执行命令发现延迟高, 延迟100-200ms以上, 已经换了ssd,还是100ms左右或以上;
- Error: etcdserver: mvcc: database space exceeded,超过默认的2G限制
- etcd集群运行直接挂掉了(晚上半夜12点),集中式存储关掉了写缓存,造成存储IO性能下降75%,etcd集群频繁重启进而造成数据库文件文件坏了,自动恢复不了的问题
二.问题分析
Kubernetes使用etcd来存储和持久化集群的关键信息,如果etcd存储失效,或是etcd集群响应慢,会影响Kubernetes集群操作,甚至导致Kubernetes集群不可用,etcd基于Raft共识算法实现,确保数据在集群多个节点间一致且可靠。这是K8s集群稳定运行的基础,避免了"脑裂"和数据不一致。
etcd支持高效的键值变化监听。这正是Kubernetes控制器模式的核心驱动力。控制器通过Watch API Server(背后是Watch etcd),实时感知集群状态变化并做出反应。用于实现K8s的节点心跳(Node Lease)和TTL功能,帮助检测不健康的节点或Pod。
etcd使用Raft共识算法实现选举和日志复制,领导者节点定期向追随者节点发送心跳,如果追随者节点在一段时间内没有收到领导者节点的心跳信息,追随者节点就会认为领导者节点已经失效,并发起选举。当etcd在进行选举的期间,会导致Kubernetes的api Server无法对etcd执行读写请求,进而会导致kubectl操作延迟或短暂失败,并且当前的pod的创建、删除、更新等操作无法执行,对当前正在运行的pod、网络、存储等没有影响。
etcd集群选举发生的直接原因为集群选举超时,即追随者节点在election-timeout时间内未收到领导者节点的心跳信息,并认为领导者节点失效而发生选举,因此,对于发生选举的考虑主要包括两方面
- 如果领导者节点正常发送心跳包,追随者节点未能及时收到,一般来说与网络的延迟关联比较大,即因为网络丢包或其他因素,导致心跳包未能及时发送至追随者节点;
- 如果领导者节点未能正常发出心跳包,或是追随者节点收到心跳包后处理超时,导致选举,一般来说与存储的延迟关联比较大,在etcd的核心设计中,处理心跳的逻辑与磁盘的持久化写入逻辑存在顺序依赖关系。基于etcd的一致性要求,需要确保数据一旦写入就不会丢失,因此磁盘的写入操作返回时必须成功,因此,etcd采用fsync的同步操作来执行磁盘写入操作,fsync是一个同步的阻塞操作,会直接将数据写入磁盘,因此,会导致etcd会对磁盘比较敏感。一旦磁盘写入慢,会导致心跳包的处理延迟,包括领导者节点向追随者节点发出心跳包,以及追随者节点处理收到的心跳包。
三.优化参数建议
etcd 作为 K8s 的核心数据库,其参数优化直接影响集群稳定性和性能。以下是 kubeadm 部署场景下最关键的优化参数(按作用分类)
1. 性能相关核心参数
| 参数名 | 作用 | 默认值(kubeadm) | 推荐值(生产) | 说明 |
|---|---|---|---|---|
--quota-backend-bytes |
etcd 单节点存储上限 | 2GB | 8GB(≤8GB) | 限制 etcd 数据库大小,超过会触发告警 / 写失败;K8s 集群越大需越高,但不建议超过 8GB(否则影响性能) |
--max-request-bytes |
单请求最大字节数 | 1.5MB | 10MB | 支持更大的资源对象(如大 ConfigMap/Secret),避免请求被拒绝 |
--auto-compaction-mode |
压缩模式 | none | periodic | 可选periodic(按时间)或revision(按版本),生产优先 periodic |
--auto-compaction-retention |
压缩保留时间 | 0(不压缩) | 1h(或 1000 revision) | 定期压缩 etcd 历史数据,减少磁盘占用;时间越短磁盘占用越少,但需保留足够回滚版本 |
--snapshot-count |
触发快照的事务数 | 100000 | 500000 | 事务数达到阈值时生成快照;值越大快照越少,但崩溃恢复时间越长 |
2. 网络 / 连接相关参数
| 参数名 | 作用 | 默认值 | 推荐值 | 说明 |
|---|---|---|---|---|
--heartbeat-interval |
节点间心跳间隔(ms) | 100 | 200-500 | 心跳越频繁,集群故障检测越快,但网络开销越大;高延迟网络建议调大 |
--election-timeout |
选举超时时间(ms) | 1000 | 2000-5000 | 节点失联后触发选举的超时时间;需大于心跳间隔的 5 倍,高延迟网络调大 |
--client-concurrency |
客户端并发请求数 | 256 | 1024 | 提高 etcd 处理客户端(kube-apiserver)并发请求的能力 |
3. 资源限制参数(容器层面)
| 参数 | 作用 | 推荐值 | 说明 |
|---|---|---|---|
cpu |
CPU 资源限制 | 2-4 核(请求)/4-8 核(限制) | etcd 是 CPU 密集型,避免 CPU 抢占导致性能下降 |
memory |
内存限制 | 2-4GB(请求)/4-8GB(限制) | 内存不足会触发 OOM,etcd 缓存需足够内存 |
storage |
磁盘 IO | SSD(IOPS ≥ 1000) | 机械硬盘会导致 etcd 写入延迟,生产必须用 SSD |
4. 操作系统参数(建议,可选)
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-iptables = 1
fs.may_detach_mounts = 1
vm.overcommit_memory=1
vm.panic_on_oom=0
fs.inotify.max_user_watches=89100
fs.file-max=52706963
fs.nr_open=52706963
net.netfilter.nf_conntrack_max=2310720
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_keepalive_probes = 3
net.ipv4.tcp_keepalive_intvl =30
net.ipv4.tcp_max_tw_buckets = 360000
net.ipv4.tcp_tw_reuse = 0
net.ipv4.tcp_tw_recycle = 0
net.ipv4.tcp_fin_timeout = 15
net.ipv4.ip_local_port_range = 1024 65535
net.ipv4.tcp_max_orphans = 327680
net.ipv4.tcp_orphan_retries = 3
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 65535
net.ipv4.ip_conntrack_max = 65536
#net.ipv4.tcp_max_syn_backlog = 16384
net.ipv4.tcp_timestamps = 0
net.core.somaxconn = 65535
net.core.netdev_max_backlog = 65535
net.ipv6.conf.all.disable_ipv6 = 0
net.ipv6.conf.default.disable_ipv6 = 0
net.ipv6.conf.lo.disable_ipv6 = 0
net.ipv6.conf.all.forwarding = 1
# 增大接收和发送缓冲区的最大和默认值
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.core.rmem_default = 16777216
net.core.wmem_default = 16777216
# 调整 TCP 接收和发送缓冲区的范围
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216
本环境优化后的etcd的yaml文件如下(可参考)
spec:
containers:
- name: etcd
image: etcd:3.5.3-0 # 确保etcd版本≥3.5(推荐3.5+)
command:
- etcd
- --advertise-client-urls=https://192.168.1.100:2379 # 替换为节点IP
- --client-cert-auth=true
- --data-dir=/var/lib/etcd
- --initial-advertise-peer-urls=https://192.168.1.100:2380 # 替换为节点IP
- --initial-cluster=master=https://192.168.1.100:2380 # 替换为节点名称+IP
- --peer-cert-auth=true
- --snapshot-count=500000 # 优化快照触发阈值
- --auto-compaction-mode=periodic # 开启定期压缩
- --auto-compaction-retention=1h # 保留1小时历史数据
- --quota-backend-bytes=8589934592 # 8GB存储上限(8*1024*1024*1024)
- --max-request-bytes=10485760 # 10MB单请求上限
- --heartbeat-interval=200 # 心跳间隔200ms
- --election-timeout=2000 # 选举超时2000ms
- --client-concurrency=1024 # 提高并发请求数
- --log-level=info # 日志级别,避免debug日志占用资源