1、概述
首先要看TCP/IP協議,涉及到四層:鏈路層,網絡層,傳輸層,應用層。
其中以太網(Ethernet)的數據幀在鏈路層
IP包在網絡層
TCP或UDP包在傳輸層
TCP或UDP中的數據(Data)在應用層
它們的關係是 數據幀{IP包{TCP或UDP包{Data}}}
不同的協議層對數據包有不同的稱謂,在傳輸層叫做段(segment),在網絡層叫做數據報(datagram),在鏈路層叫做幀(frame)。數據封裝成幀後發到傳輸介質上,到達目的主機後每層協議再剝掉相應的首部,最後將應用層數據交給應用程序處理。
在應用程序中我們用到的Data的長度最大是多少,直接取決於底層的限制。
我們從下到上分析一下:
1.在鏈路層,由以太網的物理特性決定了數據幀的長度爲(46+18)-(1500+18),其中的18是數據幀的頭和尾,也就是說數據幀的內容最大爲1500(不包括幀頭和幀尾),即MTU(Maximum Transmission Unit)爲1500;
2.在網絡層,因爲IP包的首部要佔用20字節,所以這的MTU爲1500-20=1480;
3.在傳輸層,對於UDP包的首部要佔用8字節,所以這的MTU爲1480-8=1472;
所以,在應用層,你的Data最大長度爲1472。當我們的UDP包中的數據多於MTU(1472)時,發送方的IP層需要分片fragmentation進行傳輸,而在接收方IP層則需要進行數據報重組,由於UDP是不可靠的傳輸協議,如果分片丟失導致重組失敗,將導致UDP數據包被丟棄。
從上面的分析來看,在普通的局域網環境下,UDP的數據最大爲1472字節最好(避免分片重組)。
但在網絡編程中,Internet中的路由器可能有設置成不同的值(小於默認值),Internet上的標準MTU值爲576,所以Internet的UDP編程時數據長度最好在576-20-8=548字節以內。
2、TCP、UDP數據包最大值的確定
UDP和TCP協議利用端口號實現多項應用同時發送和接收數據。數據通過源端口發送出去,通過目標端口接收。有的網絡應用只能使用預留或註冊的靜態端口;而另外一些網絡應用則可以使用未被註冊的動態端口。因爲UDP和TCP報頭使用兩個字節存放端口號,所以端口號的有效範圍是從0到65535。動態端口的範圍是從1024到65535。
MTU最大傳輸單元,這個最大傳輸單元實際上和鏈路層協議有着密切的關係,EthernetII幀的結構DMAC+SMAC+Type+Data+CRC由於以太網傳輸電氣方面的限制,每個以太網幀都有最小的大小64Bytes最大不能超過1518Bytes,對於小於或者大於這個限制的以太網幀我們都可以視之爲錯誤的數據幀,一般的以太網轉發設備會丟棄這些數據幀。
由於以太網EthernetII最大的數據幀是1518Bytes這樣,刨去以太網幀的幀頭(DMAC目的MAC地址48bits=6Bytes+SMAC源MAC地址48bits=6Bytes+Type域2Bytes)14Bytes和幀尾CRC校驗部分4Bytes那麼剩下承載上層協議的地方也就是Data域最大就只能有1500Bytes這個值我們就把它稱之爲MTU。
UDP 包的大小就應該是 1500 - IP頭(20) - UDP頭(8) = 1472(Bytes)
TCP 包的大小就應該是 1500 - IP頭(20) - TCP頭(20) = 1460 (Bytes)
注*PPPoE所謂PPPoE就是在以太網上面跑“PPP”。隨着寬帶接入(這種寬帶接入一般爲Cable Modem或者xDSL或者以太網的接入),因爲以太網缺乏認證計費機制而傳統運營商是通過PPP協議來對撥號等接入服務進行認證計費的,所以引入PPPoE。PPPoE導致MTU變小了以太網的MTU是1500,再減去PPP的包頭包尾的開銷(8Bytes),就變成1492。不過目前大多數的路由設備的MTU都爲1500。
如果我們定義的TCP和UDP包沒有超過範圍,那麼我們的包在IP層就不用分包了,這樣傳輸過程中就避免了在IP層組包發生的錯誤;如果超過範圍,既IP數據報大於1500字節,發送方IP層就需要將數據包分成若干片,而接收方IP層就需要進行數據報的重組。更嚴重的是,如果使用UDP協議,當IP層組包發生錯誤,那麼包就會被丟棄。接收方無法重組數據報,將導致丟棄整個IP數據報。UDP不保證可靠傳輸;但是TCP發生組包錯誤時,該包會被重傳,保證可靠傳輸。
UDP數據報的長度是指包括報頭和數據部分在內的總字節數,其中報頭長度固定,數據部分可變。數據報的最大長度根據操作環境的不同而各異。從理論上說,包含報頭在內的數據報的最大長度爲65535字節(64K)。
我們在用Socket編程時,UDP協議要求包小於64K。TCP沒有限定,TCP包頭中就沒有“包長度”字段,而完全依靠IP層去處理分幀。這就是爲什麼TCP常常被稱作一種“流協議”的原因,開發者在使用TCP服務的時候,不必去關心數據包的大小,只需講SOCKET看作一條數據流的入口,往裏面放數據就是了,TCP協議本身會進行擁塞/流量控制。
不過鑑於Internet(非局域網)上的標準MTU值爲576字節,所以建議在進行Internet的UDP編程時,最好將UDP的數據長度控制在548字節 (576-8-20)以內。
3、TCP、UDP數據包最小值的確定
在用UDP局域網通信時,經常發生“Hello World”來進行測試,但是“Hello World”並不滿足最小有效數據(64-46)的要求,爲什麼小於18個字節,對方仍然可用收到呢?因爲在鏈路層的MAC子層中會進行數據補齊,不足18個字節的用0補齊。但當服務器在公網,客戶端在內網,發生小於18個字節的數據,就會出現接收端收不到數據的情況。
以太網EthernetII規定,以太網幀數據域部分最小爲46字節,也就是以太網幀最小是6+6+2+46+4=64。除去4個字節的FCS,因此,抓包時就是60字節。當數據字段的長度小於46字節時,MAC子層就會在數據字段的後面填充以滿足數據幀長不小於64字節。由於填充數據是由MAC子層負責,也就是設備驅動程序。不同的抓包程序和設備驅動程序所處的優先層次可能不同,抓包程序的優先級可能比設備驅動程序更高,也就是說,我們的抓包程序可能在設備驅動程序還沒有填充不到64字節的幀的時候,抓包程序已經捕獲了數據。因此不同的抓包工具抓到的數據幀的大小可能不同。下列是本人分別用wireshark和sniffer抓包的結果,對於TCP 的ACK確認幀的大小一個是54字節,一個是60字節,wireshark抓取時沒有填充數據段,sniffer抓取時有填充數據段。
4、實際應用
用UDP協議發送時,用sendto函數最大能發送數據的長度爲:65535- IP頭(20) - UDP頭(8)=65507字節。用sendto函數發送數據時,如果發送數據長度大於該值,則函數會返回錯誤。
用TCP協議發送時,由於TCP是數據流協議,因此不存在包大小的限制(暫不考慮緩衝區的大小),這是指在用send函數時,數據長度參數不受限制。而實際上,所指定的這段數據並不一定會一次性發送出去,如果這段數據比較長,會被分段發送,如果比較短,可能會等待和下一次數據一起發送。
--------------------------------------------------------------------------------------------------------------
淺談UDP(數據包長度,收包能力,丟包及進程結構選擇)
UDP數據包長度
UDP數據包的理論長度
udp數據包的理論長度是多少,合適的udp數據包應該是多少呢?從TCP-IP詳解卷一第11章的udp數據包的包頭可以看出,udp的最大包長度是2^16-1的個字節。由於udp包頭佔8個字節,而在ip層進行封裝後的ip包頭佔去20字節,所以這個是udp數據包的最大理論長度是2^16-1-8-20=65507。
然而這個只是udp數據包的最大理論長度。首先,我們知道,TCP/IP通常被認爲是一個四層協議系統,包括鏈路層、網絡層、運輸層、應用層。UDP屬於運輸層,在傳輸過程中,udp包的整體是作爲下層協議的數據字段進行傳輸的,它的長度大小受到下層ip層和數據鏈路層協議的制約。
MTU相關概念
以太網(Ethernet)數據幀的長度必須在46-1500字節之間,這是由以太網的物理特性決定的。這個1500字節被稱爲鏈路層的MTU(最大傳輸單元)。因特網協議允許IP分片,這樣就可以將數據包分成足夠小的片段以通過那些最大傳輸單元小於該數據包原始大小的鏈路了。這一分片過程發生在網絡層,它使用的是將分組發送到鏈路上的網絡接口的最大傳輸單元的值。這個最大傳輸單元的值就是MTU(Maximum Transmission Unit)。它是指一種通信協議的某一層上面所能通過的最大數據包大小(以字節爲單位)。最大傳輸單元這個參數通常與通信接口有關(網絡接口卡、串口等)。
在因特網協議中,一條因特網傳輸路徑的“路徑最大傳輸單元”被定義爲從源地址到目的地址所經過“路徑”上的所有IP跳的最大傳輸單元的最小值。
需要注意的是,loopback的MTU不受上述限制,查看loopback MTU值:
[root@bogon ~]# cat /sys/class/net/lo/mtu
65536
IP分包udp數據包長度的影響
如上所述,由於網絡接口卡的制約,mtu的長度被限制在1500字節,這個長度指的是鏈路層的數據區。對於大於這個數值的分組可能被分片,否則無法發送,而分組交換的網絡是不可靠的,存在着丟包。IP 協議的發送方不做重傳。接收方只有在收到全部的分片後才能 reassemble並送至上層協議處理代碼,否則在應用程序看來這些分組已經被丟棄。
假定同一時刻網絡丟包的概率是均等的,那麼較大的IP datagram必然有更大的概率被丟棄,因爲只要丟失了一個fragment,就導致整個IP datagram接收不到。不超過MTU的分組是不存在分片問題的。
MTU的值並不包括鏈路層的首部和尾部的18個字節。所以,這個1500字節就是網絡層IP數據報的長度限制。因爲IP數據報的首部爲20字節,所以IP數據報的數據區長度最大爲1480字節。而這個1480字節就是用來放TCP傳來的TCP報文段或UDP傳來的UDP數據報的。又因爲UDP數據報的首部8字節,所以UDP數據報的數據區最大長度爲1472字節。這個1472字節就是我們可以使用的字節數。
當我們發送的UDP數據大於1472的時候會怎樣呢?這也就是說IP數據報大於1500字節,大於MTU。這個時候發送方IP層就需要分片(fragmentation)。把數據報分成若干片,使每一片都小於MTU。而接收方IP層則需要進行數據報的重組。而更嚴重的是,由於UDP的特性,當某一片數據傳送中丟失時,接收方便無法重組數據報。將導致丟棄整個UDP數據報。因此,在普通的局域網環境下,將UDP的數據控制在1472字節以下爲好。
進行Internet編程時則不同,因爲Internet上的路由器可能會將MTU設爲不同的值。如果我們假定MTU爲1500來發送數據的,而途經的某個網絡的MTU值小於1500字節,那麼系統將會使用一系列的機制來調整MTU值,使數據報能夠順利到達目的地。鑑於Internet上的標準MTU值爲576字節,所以在進行Internet的UDP編程時,最好將UDP的數據長度控件在548字節(576-8-20)以內。
UDP丟包
udp丟包是指網卡接收到數據包後,linux內核的tcp/ip協議棧在udp數據包處理過程中的丟包,主要原因有兩個:
1、udp數據包格式錯誤或校驗和檢查失敗。
2、應用程序來不及處理udp數據包。
對於原因1,udp數據包本身的錯誤很少見,應用程序也不可控,本文不討論。
首先介紹通用的udp丟包檢測方法,使用netstat命令,加-su參數。
# netstat -su
Udp:
2495354 packets received
2100876 packets to unknown port received.
3596307 packet receive errors
14412863 packets sent
RcvbufErrors: 3596307
SndbufErrors: 0
從上面的輸出中,可以看到有一行輸出包含了"packet receive errors",如果每隔一段時間執行netstat -su,發現行首的數字不斷變大,表明發生了udp丟包。
下面介紹一下應用程序來不及處理而導致udp丟包的常見原因:
1、linux內核socket緩衝區設的太小
# cat /proc/sys/net/core/rmem_default
# cat /proc/sys/net/core/rmem_max
可以查看socket緩衝區的缺省值和最大值。
rmem_default和rmem_max設置爲多大合適呢?如果服務器的性能壓力不大,對處理時延也沒有很嚴格的要求,設置爲1M左右即可。如果服務器的性能壓力較大,或者對處理時延有很嚴格的要求,則必須謹慎設置rmem_default 和rmem_max,如果設得過小,會導致丟包,如果設得過大,會出現滾雪球。
2、服務器負載過高,佔用了大量cpu資源,無法及時處理linux內核socket緩衝區中的udp數據包,導致丟包。
一般來說,服務器負載過高有兩個原因:收到的udp包過多;服務器進程存在性能瓶頸。如果收到的udp包過多,就要考慮擴容了。服務器進程存在性能瓶頸屬於性能優化的範疇,這裏不作過多討論。
3、磁盤IO忙
服務器有大量IO操作,會導致進程阻塞,cpu都在等待磁盤IO,不能及時處理內核socket緩衝區中的udp數據包。如果業務本身就是IO密集型的,要考慮在架構上進行優化,合理使用緩存降低磁盤IO。
這裏有一個容易忽視的問題:很多服務器都有在本地磁盤記錄日誌的功能,由於運維誤操作導致日誌記錄的級別過高,或者某些錯誤突然大量出現,使得往磁盤寫日誌的IO請求量很大,磁盤IO忙,導致udp丟包。
對於運維誤操作,可以加強運營環境的管理,防止出錯。如果業務確實需要記錄大量的日誌,可以使用內存log或者遠程log。
4、物理內存不夠用,出現swap交換
swap交換本質上也是一種磁盤IO忙,因爲比較特殊,容易被忽視,所以單列出來。
只要規劃好物理內存的使用,並且合理設置系統參數,可以避免這個問題。
5)磁盤滿導致無法IO
沒有規劃好磁盤的使用,監控不到位,導致磁盤被寫滿後服務器進程無法IO,處於阻塞狀態。最根本的辦法是規劃好磁盤的使用,防止業務數據或日誌文件把磁盤塞滿,同時加強監控,例如開發一個通用的工具,當磁盤使用率達到80%時就持續告警,留出充足的反應時間。
UDP收包能力測試
測試環境
處理器:Intel(R) Xeon(R) CPU X3440 @ 2.53GHz,4核,8超線程,千兆以太網卡,8G內存
模型1
單機,單線程異步UDP服務,無業務邏輯,只有收包操作,除UDP包頭外,一個字節數據。
測試結果
進程個數 |
1 |
2 |
4 |
8 |
平均處理速度(包/秒) |
791676.1 |
1016197 |
1395040 |
1491744 |
網卡流量(Mb/s) |
514.361 |
713.786 |
714.375 |
714.036 |
CPU佔用情況(%) |
100 |
200 |
325 |
370 |
現象:
1、單機UDP收包處理能力可以每秒達到150w左右。
2、處理能力隨着進程個數的增加而增強。
3、在處理達到峯值時,CPU資源並未耗盡。
結論:
1、UDP的處理能力還是非常可觀的。
2、對於現象2和現象3,可以看出,性能的瓶頸在網卡,而不在CPU,CPU的增加,處理能力的上升,來源於丟包(UDP_ERROR)個數的減少。
模型2
其他測試條件同模型1,除UDP包頭外,一百個字節數據。
測試結果
進程個數 |
1 |
2 |
4 |
8 |
平均處理速度(包/秒) |
571433.4 |
752319.9 |
731545.6 |
751922.5 |
網卡流量(Mb/s) |
855.482 |
855.542 |
855.546 |
855.549 |
CPU佔用情況(%) |
100 |
112.9 |
—— |
—— |
現象:
1、100個字節的包大小,比較符合平常的業務情形。
2、UDP的處理能力還是非常可觀,單機峯值可以到達每秒75w。
3、在4,8個進程時,沒有記錄CPU的佔用情況(網卡流量耗盡),不過可以肯定的是,CPU未耗盡。
4、隨着進程個數的上升,處理能力沒有明顯提升,但是,丟包(UDP_ERROR)的個數大幅下降。
模型3
單機,單進程,多線程異步UDP服務,多線程共用一個fd,無業務邏輯,除UDP包頭外,一個字節數據。
測試結果:
線程個數 |
1 |
2 |
平均處理速度(包/秒) |
791676 |
509868 |
網卡流量(Mb/s) |
514.361 |
714.229 |
CPU佔用情況(%) |
100 |
150 |
現象:
1、隨着線程個數的增加,處理能力不升反降。
結論:
1、多線程共用一個fd,會造成相當大的鎖爭用。
2、多線程共用一個fd,當有包來時,會激活所有的線程,導致頻繁的上下文切換。
最終結論:
1、UDP處理能力非常可觀,在日常的業務情形中,UDP一般不會成爲性能瓶頸。
2、隨着進程個數的增加,處理能力未明顯上升,但是丟包個數明顯下降。
3、本次測試過程中,瓶頸在網卡,而不在CPU。
4、採用多進程監聽不同端口的模型,而不是多進程或多線程監聽同一個端口。
總結
UDP數據包長度 |
在本機(loopback)傳輸,可以根據需要設置MTU,但記住,UDP最大理論長度65507。 在內網傳輸,最好控制在1472字節(1500-8-20)。 在internet上傳輸,最好控制在548字節(576-8-20)以內。 |
UDP收包能力 |
UDP處理能力非常可觀,在日常的業務情形中,UDP一般不會成爲性能瓶頸。 隨着進程個數的增加,處理能力未明顯上升,但是丟包個數明顯下降。 採用多進程監聽不同端口的模型,而不是多進程或多線程監聽同一個端口。 |
轉自: https://blog.csdn.net/caoshangpa/article/details/51530685