今天我們來玩一下ChaosMesh模拟網絡duplicate包的情況。同時也要看一下對應用産生的直接影響。
目标
模拟網絡重複包。
配置
- yaml檔案配置
[root@s5 ChaosMesh]# cat network-duplicate.yaml
apiVersion: chaos-mesh.org/v1alpha1
kind: NetworkChaos
metadata:
name: network-duplicate
namespace: chaos
spec:
action: duplicate
mode: one
selector:
labelSelectors:
"k8s.kuboard.cn/name": "svc-7dmall"
duplicate:
duplicate: "40"
correlation: "25"
duration: "10s"
scheduler:
cron: '@every 15s'
複制
- 界面配置
執行
- 在指令行執行:
[root@s5 ChaosMesh]# kubectl apply -f network-duplicate.yaml
networkchaos.chaos-mesh.org/network-duplicate created
複制
- 在界面上配置完成送出後即開始執行。
驗證
- 進入被模拟的POD,先檢視qdisc上增加的規則,再執行tcpdump抓包。
- 檢視qdisc上的規則
[root@svc-7dmall-664d59f75b-whtvc /]# tc qdisc ls dev eth0
qdisc netem 1: root refcnt 2 limit 1000 duplicate 40%
[root@svc-7dmall-664d59f75b-whtvc /]#
- 執行tcpdump抓包
[root@svc-7dmall-664d59f75b-whtvc /]# tcpdump -i eth0 -w networkduplicate.cap
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
^C195 packets captured
195 packets received by filter
0 packets dropped by kernel
[root@svc-7dmall-664d59f75b-whtvc /]#
複制
從上面的結果看抓到了195個包。
2. 進入pod所在機器或用其他工具把抓到的檔案複制到本地。
[root@s7 ~]# docker cp 3d4ab3241d8a:/networkduplicate.cap ./
複制
3. 用wireshark打開檢視。
确實出現了大量的重複包。
正常抓包結果是這樣的:
4. 用jmeter開始一個線程通路應用,持續60s,看下有什麼差別。
- 有重複包的結果:
- 無重複包的結果:
從上面的結果來看,産生重複包的時候,對性能的影響還是不小的。
應用直接的感受就是:響應時間長、TPS下降。
使用者直接的感受就是:慢但有響應或慢直到報錯。
5. 進入被模拟的POD,再次檢視qdisc上的規則
[root@svc-7dmall-664d59f75b-whtvc /]# tc qdisc ls dev eth0
qdisc noqueue 0: root refcnt 2
[root@svc-7dmall-664d59f75b-whtvc /]#
複制
恢複
- 在界面上停止案例
- 用指令行停止案例
[root@s5 ChaosMesh]# kubectl delete -f network-duplicate.yaml
networkchaos.chaos-mesh.org "network-duplicate" deleted
[root@s5 ChaosMesh]#
複制
重傳原理邏輯說明和RTO計算過程
重複包産生的原因有很多,像應用故障、網絡裝置故障、服務當機等等。
我們這裡主要來說明一下重傳的邏輯。
決定封包重傳機制的是重傳計時器(retransmission timer),它的功能是維護重傳逾時值(retransmission timeout)。
發出封包後,重傳計時器啟動,收到ACK後計時器停止。如果未收到ACK,發送方認為封包丢失并重傳,同時RTO加倍;如果2倍RTO之後還沒收到ACK,則再次重傳。
在linux中重傳次數預設最大為15次,由兩個參數控制:
net.ipv4.tcp_retries1 = 3
net.ipv4.tcp_retries2 = 15
複制
tcp_retries1 = 3 是指重傳了3次後,如果還沒收到ACK,則後續重傳中會先更新路由。
tcp_retries2 = 15 是指最多重傳15次,15次都傳不成功,那就放棄了。
正常情況下,你看到這裡就可以結束了。但也不排除有些人想看明白RTO的計算邏輯。那就接着看。
也許你會問RTO是多長時間?在Linux源碼中,有這樣的定義(源碼路徑include/net/tcp.h,在我這個3.10版本的核心代碼中是134、135行):
#define TCP_RTO_MAX ((unsigned)(120*HZ))
#define TCP_RTO_MIN ((unsigned)(HZ/5))
複制
看到這裡,知道RTO有最大最小值,分别是 HZ/5 和 120*HZ 。但是又有疑問,那HZ是什麼值?你可以在系統中執行如下指令獲得。
[root@s5 ~]# cat /boot/config-`uname -r` | grep '^CONFIG_HZ='
CONFIG_HZ=1000
複制
在我的系統中值是1000,也就是說RTO的最小值是200、最大值是120000(機關是毫秒)。
但是這個RTO又是怎麼算來的呢?這個值由__tcp_set_rto(3.10源碼路徑include/net/tcp.h中606-609行)函數算出(其中srtt的計算邏輯,我就不展開了,越說越多越容易亂,有興趣的可以自己去查查資料)。
static inline u32 __tcp_set_rto(const struct tcp_sock *tp)
{
return (tp->srtt >> 3) + tp->rttvar;
}
複制
這個函數算出來的值不可以小于TCP_RTO_MIN的值。
而RTO的最大值又由誰來确定呢?那就是tcp_bound_rto(3.10源碼路徑include/net/tcp.h中600-604行)了。
static inline void tcp_bound_rto(const struct sock *sk)
{
if (inet_csk(sk)->icsk_rto > TCP_RTO_MAX)
inet_csk(sk)->icsk_rto = TCP_RTO_MAX;
}
複制
以上就是RTO的計算邏輯。
留下思考的空間:
1. 怎麼分析網絡包重傳的原因?
2. 有沒有設定最小RTO的函數?