问题背景
客户反馈在使用ipvlan模式时,将nginx的upstream的唯一后端设置为clusterip的service,会出现负载不均的问题。
排查过程
● 当upstream与nginx不区分节点部署时,能够发现对于所有与nginx位于相同节点的upstream,被动新建连接数量比不在相同节点上的要小,并且相对稳定。
● 增加两个副本,在不进行ct变动情况下压测,发现流量不均衡。
● 手动清理全部ct后,进行测试,可以发现流量趋于均衡。
● 当压测过程中,对upstream所在的deployment增加副本数,新增的副本与已经有流量的副本会有严重的不均衡,经过数据面排查,ct表中的数量有较大的差异,lb表确认在副本调整后时间不久即完成endpoint扩充。
● 经过monitor抓取后发现新扩容的副本和旧的副本之间差别较大。
● 在monitor这对不同endpoint抓取后发现,固定的nginx侧的端口最终进入ct的后端是一样的,即如果某个端口的五元组有到达某个固定upstream的ct,则会一直保持分配到这个upstream,如下图:
● 初步怀疑是ct一致保持在cilium_ct4_global表中不会过期导致某个nginx的端口持续会分配到固定的upstream,查看ct表发现expires时间几乎保持不变,如下图:
根因原理
选取cilium_ct4_global表中某个键值查看,较长时间,月30s不会有过期,猜测与map的过期机制有关。
● 在cilium的service的lb4_local代码逻辑中,如果能够从ct表中找到,无论是establish还是reopend,都会复用ct。
cilium_ct4_global表是lru_hash类型的map:
查询linux内核文档发现,lru_hash表的查找操作会让expires的时间重置,因此在流量较高的情况下,ct不会过期:
https://lore.kernel.org/all/d69d44ca-206c-d818-1177-c8f14d8be8d1@iogearbox.net/T/
lru_hash的idle回收逻辑是每1s进行一次,1s内如果ct被访问过,则不会被删除并且一直复用,产生这个现象。
关于删除时间,观察到经过10min左右的静默后,ct表中相关的数据已经过期,但是重新开始压测,发现依然存在负载不均衡的现象。分析cilium代码发现,选择后端时会通过hash的方式选择:
/* The daddr is explicitly excluded from the hash here in order to allow for * backend selection to choose the same backend even on different service VIPs. */ static __always_inline __u32 hash_from_tuple_v4(const struct ipv4_ct_tuple *tuple) { return jhash_3words(tuple->saddr, ((__u32)tuple->dport << 16) | tuple->sport, tuple->nexthdr, HASH_INIT4_SEED); }
根据这段逻辑,即使ct被销毁,只要hash因子不变,一致性哈希还是会选到相同的节点,新加入的endpoint很难被选中,经过测试发现,在重建nginx的pod之后可以均衡,应该是哈希因子重建之后,恢复均匀。
● 查看代码发现
https://github.com/cilium/cilium/blob/master/bpf/lib/conntrack.h,对Service类型不会设置为Close,最终的超时时间为6小时。
社区也有相关的issue:https://github.com/cilium/cilium/issues/18442。
最终解决是在最新的这次提交中 https://github.com/cilium/cilium/pull/19451。
提交的内容是,当Service的连接收到任何一方的fin/rst包后,在30s内如果不再有在这个连接上的包进来,那么下次命中同样conntrack的syn包会被走到CT_NEW的逻辑来重新选择后端。
所以只要在这个修改的基础上,然后应用的端口复用的间隔>30s就能避免这个问题。
● 修改已经cherry-pick到terway的policy中:
https://github.com/AliyunContainerService/terway/pull/365。
解决办法
Terway 已经在1.2.4 版本中修复
https://help.aliyun.com/document_detail/113090.html。