sessionAffinity: ClientIP 到底是怎么做的?超时是从第一次访问算还是最近一次?不同客户端会固定到同一个后端吗?后端被删了怎么办?这篇看 iptables 的 recent 规则并做定时实验。
plain(None):[11, 10, 9](各后端收到的数量,从多到少) sticky(ClientIP):[30](全部落在同一个后端) 另一个客户端 cli2 访问 sticky:[30];两个客户端分别固定到哪个后端:cli1→wgtmr cli2→44wps(各自独立,不一定相同)
同一个客户端 cli1 发 30 个新连接:plain Service(sessionAffinity: None)分布是 11/10/9;sticky Service(sessionAffinity: ClientIP,默认 timeoutSeconds: 10800)30 个全在一个后端。另一个客户端 cli2 访问 sticky 也全落在一个后端,但和 cli1 不是同一个——按来源 IP 各自固定。
sticky 的 SVC 链 KUBE-SVC-ORWA43K63G6M2SJE:
KUBE-SVC-ORWA43K63G6M2SJE ! -s 10.244.0.0/16 -d 10.96.150.53/32 -p tcp -m tcp --dport 80 -j KUBE-MARK-MASQ
KUBE-SVC-ORWA43K63G6M2SJE -m recent --rcheck --seconds 10800 --reap --name KUBE-SEP-BVBQE3KGEAB4HYQO --mask 255.255.255.255 --rsource -j KUBE-SEP-BVBQE3KGEAB4HYQO
KUBE-SVC-ORWA43K63G6M2SJE -m recent --rcheck --seconds 10800 --reap --name KUBE-SEP-ELHBVIMXRY3OTTBH --mask 255.255.255.255 --rsource -j KUBE-SEP-ELHBVIMXRY3OTTBH
KUBE-SVC-ORWA43K63G6M2SJE -m recent --rcheck --seconds 10800 --reap --name KUBE-SEP-YJCYVERRI7CLOUUO --mask 255.255.255.255 --rsource -j KUBE-SEP-YJCYVERRI7CLOUUO
KUBE-SVC-ORWA43K63G6M2SJE -m statistic --mode random --probability 0.33333333349 -j KUBE-SEP-BVBQE3KGEAB4HYQO
KUBE-SVC-ORWA43K63G6M2SJE -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-ELHBVIMXRY3OTTBH
KUBE-SVC-ORWA43K63G6M2SJE -j KUBE-SEP-YJCYVERRI7CLOUUO
其中一个 SEP 链 KUBE-SEP-BVBQE3KGEAB4HYQO:
KUBE-SEP-BVBQE3KGEAB4HYQO -s 10.244.1.173/32 -j KUBE-MARK-MASQ
KUBE-SEP-BVBQE3KGEAB4HYQO -p tcp -m recent --set --name KUBE-SEP-BVBQE3KGEAB4HYQO --mask 255.255.255.255 --rsource -m tcp -j DNAT --to-destination 10.244.1.173:80
内核 recent 表(每个后端一张,记录客户端 IP):['KUBE-SEP-BVBQE3KGEAB4HYQO', 'KUBE-SEP-ELHBVIMXRY3OTTBH', 'KUBE-SEP-YJCYVERRI7CLOUUO']
KUBE-SEP-BVBQE3KGEAB4HYQO 里记录的客户端:['src=10.244.1.174 ttl: 64 last_seen: 4320743250 oldest_pkt: 31 4320743028, 4320743029, 4320743031, 4320743032, ']sticky 的 SVC 链前三条是 -m recent --rcheck --seconds 10800 --reap --name KUBE-SEP-… -j KUBE-SEP-…:每个后端一条,检查来源 IP 是否在该后端的 recent 表里,在就直接跳过去;都没命中才走后面的 statistic random 抽签。SEP 链里的 DNAT 规则带 -m recent --set,把客户端 IP 记进这个后端的表。内核的 /proc/net/xt_recent/ 下每个后端一张表,能看到 src=10.244.1.174 和它的访问时间戳。
timeoutSeconds 改成 3:{'clientIP': {'timeoutSeconds': 3}}
规则里的 --seconds:['3']
12 轮试验:间隔 1 秒(<3 秒)的两次访问落在同一个后端 12/12;间隔 4 秒(>3 秒)的两次访问落在不同后端 8/12(超时后重新抽签,3 个后端时换一个的概率约 2/3)
每 2 秒访问一次(每次都在 3 秒超时内)共 7 次:1 个不同后端(每次访问都刷新计时器,所以一直粘在同一个)把 timeoutSeconds 改成 3,规则里的 --seconds 随之变成 3。12 轮试验:间隔 1 秒(小于超时)的两次访问落在同一个后端 12/12;间隔 4 秒(大于超时)的两次访问有 8 次落在不同后端(超时后重新抽签,3 个后端时换一个的概率约 2/3)。每 2 秒访问一次共 7 次始终是同一个后端:每次访问都会刷新计时器,超时是从上一次访问算起,而不是第一次。
固定的后端 44wps(超时 10800 秒)被删除后立即重新访问 5 次:['qzvtf', 'qzvtf', 'qzvtf', 'qzvtf', 'qzvtf'](客户端被重新分配到存活的后端;之后又固定下来:True)
固定的后端 44wps 被删除后,客户端立即重新访问 5 次,全部落到 qzvtf:被重新分配到存活的后端,并固定在它上面。所以滚动更新期间,会话保持的客户端会被打散到新的 Pod。