最近跟大家分享一個 2020 年初左右的問題,這個問題的徵狀使用者透過 service 去存取相關服務時,會一直遲遲連接不上,直到 63 秒後服務才會通。
這個問題有兩種類型,一個是 63 秒後服務會通,一個則是 1 秒後會通,兩個背後的原因都一樣,這邊就來稍微簡介一下這個問題
# 發生條件
1. 使用 VXLAN 作為底層 Overlay Network,最常見的就是 Flannel 這套 CNI
2. Kubernetes 的版本不能太舊,至少要 1.16 以後,不過目前這個問題已經修復,所以現在要撞到除非特別指定版本
3. 使用的 Linux Kernel 版本也不能太新,目前該問題已經修復於大部分的 upstream
# 發生原因
1. VXLAN 本身是一個基於 UDP 的封裝協議,有一個已知的 bug 會使得其 checksum 發生錯誤,導致封包不會被遠端接收方給接收
2. kube-proxy 內關於 iptables 的設定沒有妥善,導致 VXLAN 封包會進行二次 SNAT
3. 第二次的 SNAT 就會觸發(1) 的 bug(當然還有其他條件,但是那些條件也剛好符合)
,最後導致封包的 checksum 不同,因此送到遠方就被拒絕
4. 底層的 TCP 建立連線時,會不停地嘗試,每次失敗都會等待更多時間,分別是1,2,4,8,16,32秒
5. 五次都失敗後, TCP 就會觸發重傳機制,下一次的重傳就不會進入到第二次的 SNAT,因此封包就不會踩到問題,因此通過
# 解決方法
1. 基本上這個問題要踩到要各方一起努力才會踩到,也因此修復方式也是多元化
2. Kernel 本身修復了關於 UDP 封裝的 Checksum 計算
3. Kubernetes 這邊則是針對 kube-proxy 進行強化,其使用的 iptables 規則會避免二次 SNAT 的情況
# 其他問題
1. 為什麼 TCP 重送後就不會踩到二次 SNAT? 這部分我看了相關的 issue 以及諸多文章都沒有看到解釋,都在探討 SNAT 後產生的 checksum,至於為什麼 TCP 重送後就通則是一個謎底
2. 為了解決這個謎體,我特別指定 kubernetes 版本並且重新編譯 Ubuntu 的 Linux Kernel 版本,盼望從 Kernel 中來觀察並且理解這個問題,目前已經有一些初步的進度。之後完成後會在撰寫文章跟大家分享這個問題
這個問題我認為非常有趣,也許自己的環境剛好沒有踩到,但是可以透過觀察不同的 issue 來研究各式各樣問題,也藉由這些過程來學習
相關 PR: https://github.com/kubernetes/kubernetes/pull/92035
checksum 方法 在 Checksum in Linux Kernel 的推薦與評價
内核计算IP/TCPU/UDP的校验和的方法,参考How to Calculate IP/TCP/UDP Checksum–Part 1 Theory. 简单来说,就是对要计算的数据,以16bit为单元进行 ... ... <看更多>
checksum 方法 在 udp checksum 校验错误导致宿主机访问SVC 概率性失败 - GitHub 的推薦與評價
版本. Kube-OVN 1.6.0+. 现象. SVC 的Endpoint 为容器网络Pod,从宿主机访问SVC ClusterIP+Port 概率性出现请求卡主,需要半分钟左右才会返回. 排查方法. ... <看更多>
checksum 方法 在 [疑問] UDP Checksum到底要怎麼算? - 看板NTUE-CS100 的推薦與評價
UDP的Checksum要怎麼算,不知道為什麼這幾天常常被問到這問題,發問頻率
僅次於"明天要去哪裡拍照"
好吧~擒賊先擒王,想知道checksum怎麼算,當然要先懂他是怎麼算出來的
首先先來說一下UDP的checksum拿了哪些東西來運算
UPD checksum的計算包含下列四項
1. Pseudo Header
2. UDP Header
3. UDP Data
4. Padding
UDP Header和UDP Data我就不繁述了,不知道在哪的話請明年再來吧
Pseudo Header <---中文我也不知道要怎麼翻,隨便啦,假表頭還是虛擬表頭都行
這東西包含了來源IP位址 、目的IP位址 、Unused 、協定 、和Length
其中來源IP位址、目的IP位址、Protocol請到IP Header去把他找出來
Unused是長度為8bits的0
Length是UDP Header裡的Length 別抓錯了
Padding是當checksum的檢查範圍不是2Byte的倍數的時候
會在最後加上一個Padding
好啦~~checksum就是把這幾個東西加一加就是答案了,講解完畢
-----------------------------------------------------------------------------
如果還是霧颯颯的話...別擔心,來抓個範例說明最快
下面是我從電線鯊魚裡抓到的一個UDP封包,麻煩不要給我拿這組當作業交出去
0000 00 1f c6 28 fd 1f 00 50 7f c6 04 20 08 00 45 00 ...(...P ... ..E.
0010 00 3c 07 a7 00 00 2f 11 5f 00 60 f1 02 66 c0 a8 .<..../. _.`..f..
0020 01 0b 65 c2 75 a4 00 28 5d 72 24 62 b4 5a 91 db ..e.u..( ]r$b.Z..
0030 2b 65 10 b0 30 8a 94 94 4e 24 45 16 98 db 51 94 +e..0... N$E...Q.
0040 42 10 05 37 28 11 e1 f4 66 f6 B..7(... f.
該如何解析我這也不多說了,不會的老樣子請明年再來
在這裡點出幾項我們待會會用到的數值
Source IP 60 f1 02 66
Destination IP c0 a8 01 0b
Protocol 11
Length(of UPD) 00 28
Source Port 65 c2
Destination Port74 a4
Length 00 28
UDP Checksum 5d 72
Data 24 62........(我懶著打了).....66 f6
------------------------------------------------------------------------------
把這些東西解析出來後接下來就簡單啦~~
就請各位到附屬應用程式把你的小算盤打開開始加
在此提醒一下...我覺得有人會忘記,要以2Byte為一組相加
///////////開始算/////////
______________________________
60f1+0266+c0a8+010b+ //來源和目的IP
0011+0028+ //UDP協定+ UDP length Pseudo Header
______________________________
65c2+74a4+ //來源跟目的Port
0028+ //UDP length UDP Header
0000+ //checksum用0加上
______________________________
2462+.......懶著打了........+66f6 Data
=7a286 //有算錯跟我講
把進位的加回來 7+a286=a28d
然後把結果取補數 ~a28d=5d72
Nice~看看跟UDP Header裡的checksum有沒有一樣,一樣的話就大功告成啦
大家在偷菜之餘也要多關心一下佳興喔 ^_<
(懶著排版了,大家加減看)
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 219.71.33.83
※ 編輯: Markseinn 來自: 219.71.33.83 (01/05 00:51)
... <看更多>