线上问题定位------网络瓶颈
定位丟包,錯包情況
watch more /proc/net/dev用于定位丟包,錯包情況,以便看網絡瓶頸,重點關注drop(包被丟棄)和網絡包傳送的總量,不要超過網絡上限:
[root@localhost?~]#?watch?-n?2?more?/proc/net/dev Every?2.0s:?more?/proc/net/dev???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????Fri?May??1?17:16:55?2020Inter-|???Receive????????????????????????????????????????????????|??Transmitface?|bytes????packets?errs?drop?fifo?frame?compressed?multicast|bytes????packets?errs?drop?fifo?colls?carrier?compressedlo:???10025?????130????0????0????0?????0??????????0?????????0????10025?????130????0????0????0?????0???????0??????????0ens33:?759098071??569661????0????0????0?????0??????????0?????????0?19335572??225551????0????0????0?????0???????0??????????0-
最左邊的表示接口的名字,Receive表示收包,Transmit表示發送包;
-
bytes:表示收發的字節數;
-
packets:表示收發正確的包量;
-
errs:表示收發錯誤的包量;
-
drop:表示收發丟棄的包量;
查看路由經過的地址
traceroute ip可以查看路由經過的地址,常用來統計網絡在各個路由區段的耗時,如:
[root@localhost?~]#?traceroute?14.215.177.38 traceroute?to?14.215.177.38?(14.215.177.38),?30?hops?max,?60?byte?packets1??CD-HZTK5H2.mshome.net?(192.168.137.1)??0.126?ms?*?*2??*?*?*3??10.250.112.3?(10.250.112.3)??12.587?ms??12.408?ms??12.317?ms4??172.16.227.230?(172.16.227.230)??2.152?ms??2.040?ms??1.956?ms5??172.16.227.202?(172.16.227.202)??11.884?ms??11.746?ms??12.692?ms6??172.16.227.65?(172.16.227.65)??2.665?ms??3.143?ms??2.923?ms7??171.223.206.217?(171.223.206.217)??2.834?ms??2.752?ms??2.654?ms8??182.150.18.205?(182.150.18.205)??5.145?ms??5.815?ms??5.542?ms9??110.188.6.33?(110.188.6.33)??3.514?ms?171.208.199.185?(171.208.199.185)??3.431?ms?171.208.199.181?(171.208.199.181)??10.768?ms 10??202.97.29.17?(202.97.29.17)??29.574?ms?202.97.30.146?(202.97.30.146)??32.619?ms?* 11??113.96.5.126?(113.96.5.126)??36.062?ms?113.96.5.70?(113.96.5.70)??35.940?ms?113.96.4.42?(113.96.4.42)??45.859?ms 12??90.96.135.219.broad.fs.gd.dynamic.163data.com.cn?(219.135.96.90)??35.680?ms??35.468?ms??35.304?ms 13??14.215.32.102?(14.215.32.102)??35.135?ms?14.215.32.110?(14.215.32.110)??35.613?ms?14.29.117.242?(14.29.117.242)??54.712?ms 14??*?14.215.32.134?(14.215.32.134)??49.518?ms?14.215.32.122?(14.215.32.122)??47.652?ms 15??*?*?* ...查看網絡錯誤
netstat -i可以查看網絡錯誤:
[root@localhost?~]#?netstat?-i Kernel?Interface?table Iface?????????????MTU????RX-OK?RX-ERR?RX-DRP?RX-OVR????TX-OK?TX-ERR?TX-DRP?TX-OVR?Flg ens33????????????1500???570291??????0??????0?0????????225897??????0??????0??????0?BMRU lo??????????????65536??????130??????0??????0?0???????????130??????0??????0??????0?LRU-
Iface: 網絡接口名稱;
-
MTU: 最大傳輸單元,它限制了數據幀的最大長度,不同的網絡類型都有一個上限值,如:以太網的MTU是1500;
-
RX-OK:接收時,正確的數據包數。
-
RX-ERR:接收時,產生錯誤的數據包數。
-
RX-DRP:接收時,丟棄的數據包數。
-
RX-OVR:接收時,由于過速(在數據傳輸中,由于接收設備不能接收按照發送速率傳送來的數據而使數據丟失)而丟失的數據包數。
-
TX-OK:發送時,正確的數據包數。
-
TX-ERR:發送時,產生錯誤的數據包數。
-
TX-DRP:發送時,丟棄的數據包數。
-
TX-OVR:發送時,由于過速而丟失的數據包數。
-
Flg:標志,B 已經設置了一個廣播地址。L 該接口是一個回送設備。M 接收所有數據包(混亂模式)。N 避免跟蹤。O 在該接口上,禁用ARP。P 這是一個點到點鏈接。R 接口正在運行。U 接口處于“活動”狀態。
包的重傳率
cat /proc/net/snmp用來查看和分析240秒內網絡包量,流量,錯包,丟包。通過RetransSegs和OutSegs來計算重傳率tcpetr=RetransSegs/OutSegs。
[root@localhost?~]#?cat?/proc/net/snmp Ip:?Forwarding?DefaultTTL?InReceives?InHdrErrors?InAddrErrors?ForwDatagrams?InUnknownProtos?InDiscards?InDelivers?OutRequests?OutDiscards?OutNoRoutes?ReasmTimeout?ReasmReqds?ReasmOKs?ReasmFails?FragOKs?FragFails?FragCreates Ip:?1?64?241708?0?0?0?0?0?238724?225517?15?0?0?0?0?0?0?0?0 Icmp:?InMsgs?InErrors?InCsumErrors?InDestUnreachs?InTimeExcds?InParmProbs?InSrcQuenchs?InRedirects?InEchos?InEchoReps?InTimestamps?InTimestampReps?InAddrMasks?InAddrMaskReps?OutMsgs?OutErrors?OutDestUnreachs?OutTimeExcds?OutParmProbs?OutSrcQuenchs?OutRedirects?OutEchos?OutEchoReps?OutTimestamps?OutTimestampReps?OutAddrMasks?OutAddrMaskReps Icmp:?149?0?0?50?99?0?0?0?0?0?0?0?0?0?147?0?147?0?0?0?0?0?0?0?0?0?0 IcmpMsg:?InType3?InType11?OutType3 IcmpMsg:?50?99?147 Tcp:?RtoAlgorithm?RtoMin?RtoMax?MaxConn?ActiveOpens?PassiveOpens?AttemptFails?EstabResets?CurrEstab?InSegs?OutSegs?RetransSegs?InErrs?OutRsts?InCsumErrors Tcp:?1?200?120000?-1?376?6?0?0?4?236711?223186?292?0?4?0 Udp:?InDatagrams?NoPorts?InErrors?OutDatagrams?RcvbufErrors?SndbufErrors?InCsumErrors Udp:?1405?438?0?1896?0?0?0 UdpLite:?InDatagrams?NoPorts?InErrors?OutDatagrams?RcvbufErrors?SndbufErrors?InCsumErrors UdpLite:?0?0?0?0?0?0?0重傳率=292/223186≈0.13%
-
平均每秒新增TCP連接數:通過/proc/net/snmp文件得到最近240秒內PassiveOpens的增量,除以240得到每秒的平均增量;
-
機器的TCP連接數 :通過/proc/net/snmp文件的CurrEstab得到TCP連接數;
-
平均每秒的UDP接收數據報:通過/proc/net/snmp文件得到最近240秒內InDatagrams的增量,除以240得到平均每秒的UDP接收數據報;
-
平均每秒的UDP發送數據報:通過/proc/net/snmp文件得到最近240秒內OutDatagrams的增量,除以240得到平均每秒的UDP發送數據報;
超時
超時錯誤大部分處在應用層面,所以這塊著重理解概念。超時大體可以分為連接超時和讀寫超時,某些使用連接池的客戶端框架還會存在獲取連接超時和空閑連接清理超時。
-
讀寫超時。readTimeout/writeTimeout,有些框架叫做so_timeout或者socketTimeout,均指的是數據讀寫超時。注意這邊的超時大部分是指邏輯上的超時。soa的超時指的也是讀超時。讀寫超時一般都只針對客戶端設置;
-
連接超時。connectionTimeout,客戶端通常指與服務端建立連接的最大時間。服務端這邊connectionTimeout就有些五花八門了,jetty中表示空閑連接清理時間,tomcat則表示連接維持的最大時間;
-
其他。包括連接獲取超時connectionAcquireTimeout和空閑連接清理超時idleConnectionTimeout。多用于使用連接池或隊列的客戶端或服務端框架。
我們在設置各種超時時間中,需要確認的是盡量保持客戶端的超時小于服務端的超時,以保證連接正常結束。
在實際開發中,我們關心最多的應該是接口的讀寫超時了。
如何設置合理的接口超時是一個問題。如果接口超時設置的過長,那么有可能會過多地占用服務端的tcp連接。而如果接口設置的過短,那么接口超時就會非常頻繁。
服務端接口明明rt降低,但客戶端仍然一直超時又是另一個問題。這個問題其實很簡單,客戶端到服務端的鏈路包括網絡傳輸、排隊以及服務處理等,每一個環節都可能是耗時的原因。
TCP隊列溢出
tcp隊列溢出是個相對底層的錯誤,它可能會造成超時、rst等更表層的錯誤。因此錯誤也更隱蔽,所以我們單獨說一說。
如上圖所示,這里有兩個隊列:syns queue(半連接隊列)、accept queue(全連接隊列)。三次握手,在server收到client的syn后,把消息放到syns queue,回復syn+ack給client,server收到client的ack,如果這時accept queue沒滿,那就從syns queue拿出暫存的信息放入accept queue中,否則按tcp_abort_on_overflow指示的執行。
tcp_abort_on_overflow 0表示如果三次握手第三步的時候accept queue滿了那么server扔掉client發過來的ack。tcp_abort_on_overflow 1則表示第三步的時候如果全連接隊列滿了,server發送一個rst包給client,表示廢掉這個握手過程和這個連接,意味著日志里可能會有很多connection reset / connection reset by peer。
那么在實際開發中,我們怎么能快速定位到tcp隊列溢出呢?
-
netstat命令,執行netstat -s | egrep "listen|LISTEN"
如上圖所示,overflowed表示全連接隊列溢出的次數,sockets dropped表示半連接隊列溢出的次數。
-
ss命令,執行ss -lnt
上面看到Send-Q 表示第三列的listen端口上的全連接隊列最大為5,第一列Recv-Q為全連接隊列當前使用了多少。
接著我們看看怎么設置全連接、半連接隊列大小吧:
全連接隊列的大小取決于min(backlog, somaxconn)。backlog是在socket創建的時候傳入的,somaxconn是一個os級別的系統參數。而半連接隊列的大小取決于max(64, /proc/sys/net/ipv4/tcp_max_syn_backlog)。
在日常開發中,我們往往使用servlet容器作為服務端,所以我們有時候也需要關注容器的連接隊列大小。在tomcat中backlog叫做acceptCount,在jetty里面則是acceptQueueSize。
RST異常
RST包表示連接重置,用于關閉一些無用的連接,通常表示異常關閉,區別于四次揮手。
在實際開發中,我們往往會看到connection reset / connection reset by peer錯誤,這種情況就是RST包導致的。
1、端口不存在
如果像不存在的端口發出建立連接SYN請求,那么服務端發現自己并沒有這個端口則會直接返回一個RST報文,用于中斷連接。
2、主動代替FIN終止連接
一般來說,正常的連接關閉都是需要通過FIN報文實現,然而我們也可以用RST報文來代替FIN,表示直接終止連接。實際開發中,可設置SO_LINGER數值來控制,這種往往是故意的,來跳過TIMED_WAIT,提供交互效率,不閑就慎用。
3、客戶端或服務端有一邊發生了異常,該方向對端發送RST以告知關閉連接
我們上面講的tcp隊列溢出發送RST包其實也是屬于這一種。這種往往是由于某些原因,一方無法再能正常處理請求連接了(比如程序崩了,隊列滿了),從而告知另一方關閉連接。
4、接收到的TCP報文不在已知的TCP連接內
比如,一方機器由于網絡實在太差TCP報文失蹤了,另一方關閉了該連接,然后過了許久收到了之前失蹤的TCP報文,但由于對應的TCP連接已不存在,那么會直接發一個RST包以便開啟新的連接。
5、一方長期未收到另一方的確認報文,在一定時間或重傳次數后發出RST報文
這種大多也和網絡環境相關了,網絡環境差可能會導致更多的RST報文。
之前說過RST報文多會導致程序報錯,在一個已關閉的連接上讀操作會報connection reset,而在一個已關閉的連接上寫操作則會報connection reset by peer。通常我們可能還會看到broken pipe錯誤,這是管道層面的錯誤,表示對已關閉的管道進行讀寫,往往是在收到RST,報出connection reset錯后繼續讀寫數據報的錯,這個在glibc源碼注釋中也有介紹。
我們在排查故障時候怎么確定有RST包的存在呢?當然是使用tcpdump命令進行抓包,并使用wireshark進行簡單分析了。tcpdump -i en0 tcp -w xxx.cap,en0表示監聽的網卡。
接下來我們通過wireshark打開抓到的包,可能就能看到如下圖所示,紅色的就表示RST包了。
TIME_WAIT和CLOSE_WAIT
TIME_WAIT和CLOSE_WAIT是啥意思相信大家都知道。
在線上時,我們可以直接用命令netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'來查看time-wait和close_wait的數量
用ss命令會更快ss -ant | awk '{++S[$1]} END {for(a in S) print a, S[a]}'
1、TIME_WAIT
time_wait的存在一是為了丟失的數據包被后面連接復用,二是為了在2MSL的時間范圍內正常關閉連接。它的存在其實會大大減少RST包的出現。
過多的time_wait在短連接頻繁的場景比較容易出現。這種情況可以在服務端做一些內核參數調優:
#表示開啟重用。允許將TIME-WAIT sockets重新用于新的TCP連接,默認為0,表示關閉
net.ipv4.tcp_tw_reuse = 1
#表示開啟TCP連接中TIME-WAIT sockets的快速回收,默認為0,表示關閉
net.ipv4.tcp_tw_recycle = 1
當然我們不要忘記在NAT環境下因為時間戳錯亂導致數據包被拒絕的坑了,另外的辦法就是改小tcp_max_tw_buckets,超過這個數的time_wait都會被干掉,不過這也會導致報time wait bucket table overflow的錯。
2、CLOSE_WAIT
close_wait往往都是因為應用程序寫的有問題,沒有在ACK后再次發起FIN報文。close_wait出現的概率甚至比time_wait要更高,后果也更嚴重。往往是由于某個地方阻塞住了,沒有正常關閉連接,從而漸漸地消耗完所有的線程。
想要定位這類問題,最好是通過jstack來分析線程堆棧來排查問題,這里僅舉一個例子。
開發同學說應用上線后CLOSE_WAIT就一直增多,直到掛掉為止,jstack后找到比較可疑的堆棧是大部分線程都卡在了countdownlatch.await方法,找開發同學了解后得知使用了多線程但是卻沒有catch異常,修改后發現異常僅僅是最簡單的升級sdk后常出現的class not found。
總結
以上是生活随笔為你收集整理的线上问题定位------网络瓶颈的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux进程的高级管理,sched_y
- 下一篇: Kubernetes CKS【24】--