前言
UDP 若發生丟包,往往會認為封包遺失在路上,然而需要因環境架構來進行判斷
若發生問題的在一個大量的高速 UDP 的環境,則狀況可能會更加複雜,但往往事實出乎意料
知識
接收
網卡接收封包存入 Ring Buffer
然後透過 Kernel 存入 Socket Buffer
然後 Application 再從 Socket Buffer
取出封包
傳出
APP 將封包透過系統調用執行 sendTo
經歷 UDP封裝、IP封裝後進入 Socket Buffer,然後經由 Traffic Control 的 Qdisc(Classless Queuing Disciplines),而 Qdisc 會有一套傳輸的規則,符合規則才從 Ring Buffer
透過網卡送出
發生原因
- 傳送方
- UDP 傳送速率太快受到 Qdisc 規則限制
- TX Ring Buffer 太小
- Socket Buffer 太小
- 接收方
- RX Ring Buffer 太小
- Socket Buffer 太小
- App 處理太慢
檢查流程
確認網路協議統計 UDP 是否出現丟包
buffer errors
是否不為 0
|
|
確認網路協議是否丟包
bufErrors
是否不為 0
|
|
會顯下如下數值
IP | UDP | ||
---|---|---|---|
Forwarding | 2 | InDatagrams | 1279567583 |
DefaultTTL | 64 | NoPorts | 137018 |
InReceives | 1326807907 | InErrors | 4 |
InHdrErrors | 4 | OutDatagrams | 1322634707 |
InAddrErrors | 2710 | RcvbufErrors | 0 |
ForwDatagrams | 0 | SndbufErrors | 161837953 |
InUnknownProtos | 0 | InCsumErrors | 4 |
InDiscards | 0 | IgnoredMulti | 2439269 |
InDelivers | 1326738388 | ||
OutRequests | 1524661777 | ||
OutDiscards | 161838402 | ||
OutNoRoutes | 595 | ||
ReasmTimeout | 0 | ||
ReasmReqds | 0 | ||
ReasmOKs | 0 | ||
ReasmFails | 0 | ||
FragOKs | 0 | ||
FragFails | 0 | ||
FragCreates | 0 |
確認網卡傳出是否丟包
- TX-ERR: 發送時,產生錯誤的封包數。
- TX-DRP: 發送時,丟棄的封包數。
- TX-OVR: 發送時,速率過快丟棄的封包數。
|
|
確認流量控制是否出現丟包
Sent dropped
是否不為 0
|
|
解決方法
網卡丟包
可以考慮增加網卡 TX/RX Buffer
調高 Buffer 會增加延遲,需平衡調整
需要無服無狀態時才能執行
- 確認上限值
|
|
- 增加 Buffer
|
|
調整 Kernel Socker Buffer
確認需求才進行調整
TimeSlice 是 100ms / 0.001s
接收
假設需求是可以接收 5000 TPS、封包大小約 800 Bytes
理想狀態如下
0.001 秒需要接收 5 個封包,也能如其接收 5 個封包,則使用預設的 net.core.rmem_max
、net.core.rmem_default
即可
假如狀態如下
0.001 秒接收 20 個封包,而效能只能接收 5 個封包,暫時多出了 15 個封包,會先暫時留在 RX Buffer 裡面
累積持續一秒的話會有 15000 個封包留在 Buffer 裡面,約 12MB 的使用量 如果要能承受這一秒,我個人會建議設定成 13631488 (13MB)
|
|
傳出
假設需求是要能傳出 5000 TPS、封包大小約 1000 Bytes
理想狀態如下
0.001 秒需要傳出 5 個封包,也能如其傳送 5 個封包,則使用預設的 net.core.wmem_max
、net.core.wmem_default
即可
假設狀態如下
0.001 秒傳出 20 個封包,而效能只能傳送出 5 個封包,暫時多出了 15 個封包,會先暫時留在 TX Buffer 裡面
累積持續一秒的話會有 15000 個封包留在 Buffer 裡面,約 15MB 的使用量 如果要能承受這一秒,我個人會建議設定成 16777216 (16MB)
|
|
TC Qdisc 針對傳出丟包
需要因應不同的 Qdisc 規則來判斷該如何調整
每個規則會因應不同的狀況進行調整
pfifo_fast
只能調整 txqueuelen
|
|
fq_codel
需要因封包大小、反應時間等等狀況來判斷調整,在此簡單設定 interval
* interval: 封包超出此時間未回應則丟棄
|
|
fq
如 fq_codel
一樣需要因封包大小、反應時間等等狀況來判斷調整,這邊單純加大
* limit: 硬體封包佇列限制,超過就丟包
* flow_limit: 硬體進入佇列的封包數量限制,超過就丟包
|
|
APP 處理太慢
各位開發人員盡力之