作者朱瑜坚,腾讯云后盾开发工程师,相熟 CNI 容器网络相干技术,负责腾讯云 TKE 的容器网络的构建和相干网络组件的开发保护工作,作为主力开发实现了 TKE 下一代容器网络计划。
1. 问题背景
1.1 问题形容
最近,某外部客户的 TKE VPC-CNI 模式的独立网卡集群上呈现了 pod 间拜访不通的状况,问题 pod ping 不通任何其余 pod 和节点。
查看 dmesg 内核日志,有如下报错信息:neighbour: arp_cache: neighbor table overflow!(下图为后续复现的日志截图)
并且,这个集群规模较大,约有 1000 个节点,30000 个 pod,根本能够狐疑是因为集群规模较大,导致 ARP 表项过多,从而引起 ARP Overflow 的问题。
1.2 名词解释
名词 | 阐明 |
---|---|
TKE | 全称 Tencent Kubernetes Engine, 腾讯云容器服务,是基于原生 kubernetes 提供以容器为外围的、高度可扩大的高性能容器治理服务 |
VPC-CNI 模式 | 是容器服务 TKE 基于 CNI 和 VPC 弹性网卡实现的容器网络能力 |
Pod | Pod 是 kubernetes 的根本资源管理单位,领有独立的网络命名空间,1 个 Pod 可蕴含多个容器 |
2. 问题初步剖析
从如上报错信息可知,这个问题的根本起因在于 ARP 缓存表打满了。这里波及到内核的 ARP 缓存垃圾回收机制。当 ARP 表项太多且又没有可回收的表项的时候,新表项就会无奈插入。
这就导致网络包发送时无奈找到对应的硬件地址(MAC)。使得网络包不能发送。
那么具体什么状况会导致新表项无奈插入呢?答复这个问题,咱们须要先深刻理解一下 ARP 缓存老化及垃圾回收机制。
3. ARP 缓存老化回收机制
3.1 ARP 缓存表项状态机
如上图,是整个 ARP 表项的生命周期及其状态机。
咱们晓得,对于 TCP/IP 网络包发送时,网络栈须要对端的 MAC 地址能力让网络包转换成二层的数据结构——帧,从而在网络中传输。而对于不同播送域的 IP 地址,其对端 MAC 地址为网关,发送端会将网络包发给网关让其转发,而对于同播送域中的 IP 地址,其对端 MAC 地址即与 IP 地址对应。
而通过 IP 地址找到 MAC 地址就是 ARP 协定的次要工作内容。ARP 协定的工作过程此处不再赘述,而通过 ARP 协定找到 IP 地址对应的 MAC 地址后,会将该对应关系存储在本机上一段时间,以缩小 ARP 协定的通信频率,放慢网络包的发送。该对应关系,即 ARP 缓存表项,其状态机或整个生命周期可形容如下:
- 初始时,对于任何网络包发送时,内核协定栈须要找到目标 IP 地址对应的对端 MAC 地址,如果这时 ARP 缓存中没有命中,则会新插入一条状态为 Incomplete 的表项。Incomplete 状态会尝试发送 ARP 包,申请某 IP 地址对应的 MAC 地址。
- 若收到 ARP 回应的,表项状态就变为 Reachable。
- 若尝试了肯定次数后没收到响应,表项即变为 Failed。
- Reachable 表项在达到超时工夫后,会变成 Stale 状态,Stale 状态的表项已不可再应用。
- Stale 的表项若有被援用来发包,则表项会变为 Delay 状态。
- Delay 状态的表项也不可应用来发包,但在 Delay 状态到期前,收到 ARP 的 本机确认,则从新转为 Reachable 状态。
- Delay 状态到期,表项变为 Probe 状态,该状态与 Incomplete 状态相似。
- Stale 状态到期后,会被启动的垃圾回收起回收删除。
通过以下命令可查看以后网络命名空间(network namespace)中 arp 表项及其状态:
ip neigh
如:
本机确认:这是代指本机收到了一个源 mac 地址匹配的网络包,这个网络包示意此次网络通信的“上一跳”即是该 mac 地址的机器,能收到这个网络包即阐明该 mac 地址可达。因而即可把该表项转为 Reachable 状态。通过这一机制,内核可缩小 ARP 的通信需要。
3.2 波及到的内核参数
以下列出了该机制中次要波及的内核参数:
参数 | 含意 | 默认值 |
---|---|---|
/proc/sys/net/ipv4/neigh/default/base_reachable_time | Reachable 状态根底过期工夫,每个表项过期工夫是在 [1/2base_reachable_time,3/2base_reachable_time] 之间 | 30 秒 |
/proc/sys/net/ipv4/neigh/default/base_reachable_time_ms | Reachable 状态根底过期工夫,毫秒示意 | 30 秒 |
/proc/sys/net/ipv4/neigh/default/gc_stale_time | Stale 状态过期工夫 | 60 秒 |
/proc/sys/net/ipv4/neigh/default/delay_first_probe_time | delay 状态过期到 Probe 的工夫 | 5 秒 |
/proc/sys/net/ipv4/neigh/default/gc_interval | gc 启动的周期时间 | 30 秒 |
/proc/sys/net/ipv4/neigh/default/gc_thresh1 | 少于这个值,gc 不会启动 | 2048 |
/proc/sys/net/ipv4/neigh/default/gc_thresh2 | ARP 表的最多纪录的软限度,容许超过该数字 5 秒 | 4096 |
/proc/sys/net/ipv4/neigh/default/gc_thresh3 | ARP 表的最多纪录的硬限度,大于该数目,gc 立刻启动,并强制回收 | 8192 |
其中,gc 相干的内核参数是对 所有网卡(interface)失效的。然而各种到期工夫的设置是仅对独自网卡(interface)失效的,default 值仅对新增接口设施失效。
3.3 ARP 缓存垃圾回收机制
由其缓存表项的状态机咱们晓得,不是所有的表项都会被回收,只有 Stale 状态过期后,Failed 的表项可能会被回收。另外,ARP 缓存表项的垃圾回收是触发式的,须要回收的表项不肯定立即会被回收,ARP 缓存表项的垃圾回收有四种启动逻辑:
- arp 表项数量 < gc_thresh1,不启动。
- gc_thresh1 =< arp 表项数量 <= gc_thresh2,依照 gc_interval 定期启动
- gc_thresh2 < arp 表项数量 <= gc_thresh3,5 秒后启动
- arp 表项数量 > gc_thresh3,立刻启动
对于不可回收的表项,垃圾回收即使启动了也不会对其进行回收。因而当不可回收的表项数量大于 gc_thresh3 的时候,垃圾回收也无能为力了。
4. 进一步探索
4.1 垃圾回收阈值是按命名空间级别失效还是子机级别失效
咱们晓得,每个独立的网络命名空间是有残缺的网络协议栈的。那么,ARP 缓存的垃圾回收也是每个命名空间独自解决的吗?
从波及的内核参数能够看出,gc 相干的内核参数是对所有接口设施失效的,因而,这里能够揣测垃圾回收的阈值也是子机级别失效的,而不是按网络命名空间。
这里做了一个简略的试验来验证:
- 在节点 default ns 上的 gc_thresh1, gc_thresh2 和 gc_thresh3 设置成 60。
- 在节点上创立了 19 个独立网卡模式的 Pod
- 任意抉择一个 pod ping 其余的 pod,以此产生 arp 缓存
- 用 shell 脚本扫描节点上的所有 pod,计算 arp 表项的和,能够失去:
能够发现,各命名空间的累计 arp 表项的数目在每次达到 60 之后就会疾速降落,也就是达到 60 之后就产生了垃圾回收。反复几次都是相似的后果,因而,这阐明了垃圾回收在计算 ARP 表项是否触发阈值时,是计算各命名空间的累计值,也就是按子机级别失效,而非命名空间级别。
4.2 不可回收的 ARP 表项达到 gc_thresh3 时,会产生什么
由后面的介绍咱们晓得,垃圾回收机制并非回收任意 ARP 缓存,因而,当所有可达状态的 ARP 表项打满 ARP 缓存表时,也即达到 gc_thresh3 时,会产生什么行为?能够揣测,此时旧的无奈回收,新的 ARP 表项也无奈插入,新的网络包会无奈发送,也即产生了本次文章所形容的问题。
为了验证这一点,持续在以上环境中试验:
- 将任意两个 Pod 的根底老化工夫 base_reachable_time 调长到 1800 秒,以此产生不可回收的 ARP 表项。
- 设置 gc_thresh3 为 40,以此更容易触发问题
- 抉择调整了老化工夫的 pod ping 其余的 pod,以此产生 arp 缓存。
- 能够发现,当达到阈值的时候,ping 会产生丢包或不通:
查看内核日志 dmesg -T,能够看到文章结尾形容的信息:neighbour: arp_cache: neighbor table overflow!
以上试验阐明了,不可回收的 ARP 表项打满 ARP 表会让新的表项无奈插入,从而网络不通。
4.3 为什么相比 TKE 的全局路由模式和单网卡多 IP 模式,独立网卡模式更容易产生这个问题
要答复这个问题,咱们先简略看一下 TKE 各网络模式的原理介绍
全局路由模式
该网络模式下,每个节点上的容器 IP 是事后调配到节点上的,这些 IP 同属一个子网,且每个节点就是一个小子网。咱们晓得,ARP 协定是为二层通信服务的,因而,该网络计划中,每个 Pod 的网络命名空间内的 ARP 表最大可能保留了节点上所有其余 Pod 的 ARP 表项,最初节点的 ARP 表项的数量最大即为 节点子网 IP 数的平方,如节点的子网大小是 128,则其 ARP 表项最大可能为 127 的平方,约 16000。
共享网卡模式
该网络模式下,每个节点会绑定辅助弹性网卡,节点上的 Pod 共享应用该辅助网卡,每个 Pod 内不会做网络包的路由,只会有一条 ARP 表项,理论的路由管制在节点的 default 命名空间内实现。因而,该网络模式下,ARP 缓存表简直是共享的,又因为网卡只能属于 1 个子网,因而每个节点的 Pod ARP 缓存表只能存储一个子网的 IP-MAC 映射关系,至少数量为 各网卡所在子网内 IP 的数量和,如子网是 /22,即含有约 1000 个 ip,那么 arp 表项也大略有 1000,因为节点网卡配额个别不超过 10,因而该节点的最大 ARP 表项个别不超过 10000。
下一代网络计划——独立网卡模式
独立网卡模式是 TKE 团队推出的下一代“零损耗”容器网络计划,其基本原理如下图所示:
即母机虚构出的弹性网卡,间接置于容器中,使容器取得与 CVM 子机一样的网络通信能力和网络管理能力,大大晋升了容器网络的数据面能力,真正做到“零损耗”。
目前,独立网卡网络计划已在 TKE 产品中凋谢白名单测试,欢送内外部客户体验试用。
以上网络计划中,每个 Pod 都会独占一个网卡,也会领有独立的命名空间和独立的 ARP 缓存表。而每个网卡都能够属于不同的子网。因而,在独立网卡模式里,ARP 缓存表项数量至少为 同可用区的子网 IP 数量之和。这一数量量级是能够很轻易上万的,很容易就冲破了默认的 ARP 缓存设置。也就触发了这个问题。
5. 解决方案
从以上的剖析能够看出,这个问题,调大垃圾回收的阈值,能够比拟好的解决问题。因而,长期的解决方案,就是调大 ARP 缓存表的垃圾回收阈值:
echo 8192 > /proc/sys/net/ipv4/neigh/default/gc_thresh1echo 16384 > /proc/sys/net/ipv4/neigh/default/gc_thresh2echo 32768 > /proc/sys/net/ipv4/neigh/default/gc_thresh3
6. 总结
ARP 缓存打满之后,Pod 就会网络不通。初看起来很简略,然而其背地的 ARP 缓存老化和垃圾回收机制也是比较复杂的。查问了很多材料,然而都对“垃圾回收阈值是对各命名空间的 ARP 表项累积值失效还是独自失效”,“垃圾回收会回收哪些表项”,“表项打满后的具体行为如何”等问题说不清、道不明。因而,笔者尝试通过几个小试验验证了具体的行为模式。相比间接浏览艰涩的内核源码,实验法兴许也是一个钻研问题和了解机制的捷径了。心愿可能帮忙到各位读者。
【腾讯云原生】云说新品、云研新术、云游新活、云赏资讯,扫码关注同名公众号,及时获取更多干货!!