1. 程式人生 > >《Linux就是這個範兒》

《Linux就是這個範兒》

 我發現很多人不太愛用UDP,對UDP存有偏見,愛憎分明的我不得不為它吐吐槽。

比起TCP來,UDP的優勢在於速度快,而且不需要維護資料流,還能防止意想不到的欺騙。我遇到這麼一個專案,在nginx上設計一個add-on模組做區域網轉發。由於最終實現的服務部署在本機或區域網中,我建議通過UDP方式實現服務的呼叫。當時就有人跳起來跟我爭論,反對使用 UDP。理由是UDP是無連線的,容易丟包,有時序問題,不可靠。

首先在本地或區域網中不存在時序問題。時序問題的產生是因為資料包可能走過不同路由。區域網內不存在這種情況,也就不用理會它。另外我可以負責任地說,雖然UDP 是無連線,它在區域網中傳輸丟包的概率是微乎其微的。區域網使用的交換機對資料有很強的恢復功能。如果在區域網中你的程式出現丟包的現象,你還是先檢查一下自己程式寫得是否合理。一般的丟包都是應用寫的不合理造成的,比如接收不及時導致接收緩衝區滿了,後面的包覆蓋了前面的包,從而導致“丟包”。接收 UDP 資料包的函式儘量不要和處理UDP資料包的函式在一個執行緒,否則就可能導致收包不及時的問題發生。收包執行緒的全部工作就是不停地讀,把接收完的資料放在佇列中。

還有人提出峰值資料量過大會引起計算機忙而丟包。我做過24路1080p 30mbps碼流的視訊直播服務,畫面清晰不丟幀,沒有馬賽克。運算設計得簡單,如果是CBR的視訊流,使用720mbps頻寬,在千兆網環境下是沒有任何問題的。到目前為止我做的轉發服務還沒有超過這個峰值資料量。有人使用tcpdump驗證我的說法,向我反映即便是區域網也有“x packets dropped by kernel”。但是造成這種丟包的原因是由於libcap抓到包後,tcpdump上層沒有及時地取出,導致libcap緩衝區溢位,從而覆蓋了未處理包。雖然tcpdump工具顯示被kernel丟棄,但是並不是說真正是被Linux核心拋棄的,而是被其所使用的動態庫libcap拋棄。這時候如果是你寫的服務,還是可以正常獲取資料的。當然我們是有辦法來改善tcpdump上層的處理效率減少丟包。例如抓包時最小化抓取過濾範圍,即通過指定網絡卡、埠、包流向、包大小來減少處理包的數量;新增-n引數,禁止反向域名解析;調節/proc/sys/net/core/rmem_default和/proc/sys/net/core/rmem_max 引數改變sk_rcvbuf的大小等。

可能還有人會問:“很多教科書上都說 UDP 容易丟包呀。”這要看在什麼應用場景下。不能生搬硬套。在經過路由器的情況有時是會出現丟包的。依我的實際經驗,在過二三級路由以後,由於資料流量繁忙和TTL等原因可能會出現丟包的現象。

所以凡涉及到本機或區域網內通訊的案例,都可以考慮使用UDP。因為這個東西無連線,處理起來相當簡單,效能極高。這種情況下使用TCP很浪費CPU資源。因為根本都不丟包,每次TCP的流控還要評估網路環境。