其中,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 会产生丢包或不通: