极速飞艇平台下载
機房360首頁
當前位置:首頁 ? 廣告傳媒 ? UCloud 生產環境中負載均衡產品DPDK問題的解決

UCloud 生產環境中負載均衡產品DPDK問題的解決

來源:搜狐科技 作者: 更新時間:2019/4/4 13:45:50

摘要:ULB4是UCloud自主研發的基于DPDK的高可用四層負載均衡產品,轉發能力接近線速;DPDK則是一個高性能的開源數據面開發套件。

  ULB4是UCloud自主研發的基于DPDK的高可用四層負載均衡產品,轉發能力接近線速;DPDK則是一個高性能的開源數據面開發套件。ULB4作為用戶應用的全局入口,在大流量多元化場景下保證用戶業務的持續穩定至關重要,這也是UCloud網絡產品團隊的技術使命。尤其現網單個ULB集群承載帶寬已達10G,包量83萬PPS,運行環境復雜,即使面臨突發因素(比如觸發未知BUG),我們也要設法保證產品正常工作,避免產生嚴重影響。

  近期,我們在ULB4的線上環境中,發現了一個DPDK的發包異常現象,由于整個ULB產品為集群架構,該異常并未導致用戶服務不可用。但為了任何時刻都能保證用戶服務的足夠穩定,團隊通過GDB、報文導出工具、生產環境流量鏡像等手段,從現網GB級流量中捕獲異常報文,再結合DPDK源碼分析,定位到原因出自DPDK本身的BUG并修復解決。期間未對用戶業務造成影響,進一步保證了UCloud數萬ULB實例的穩定運行。

  本文將從問題現象著手,抽絲剝繭,詳述問題定位、分析與解決全過程,希望能為ULB用戶和DPDK開發者提供參考與啟迪。

  問題背景

  在12月初一向穩定的ULB4集群中突然出現了容災,某臺ULB4服務器工作異常被自動移出了集群。當時的現象是:

  轉發面服務監控到網卡接收方向流量正常,但是發送方向流量為0,重啟轉發面服務后又可以正常收發,同時集群其他機器也會不定期出現異常情況。對用戶業務而言,會出現少量連接輕微抖動,隨后迅速恢復。

  下面是整個問題的處理過程,我們在此過程中做出種種嘗試,最終結合DPDK源碼完成分析和解決,后續也準備將自研的報文導出工具開源共享。

  問題定位與分析

  ULB4集群一直很穩定地工作,突然陸續在集群的不同機器上出現同樣的問題,并且機器恢復加入集群后,過了一段時間又再次出現同樣的問題。根據我們的運營經驗,初步猜測是某種異常報文觸發了程序BUG。但是,面對GB級流量如何捕獲到異常報文?又如何在不影響業務情況下找出問題呢?

  一、GDB調試報文,發現疑點

  想要知道整個程序為什么不發包,最好的辦法就是能夠進入到程序中去看看具體的執行過程。對于DPDK用戶態程序來說,GDB顯然是一個好用的工具。我們在發包程序邏輯中設置斷點,并通過disassemble命令查看該函數的執行邏輯,反匯編之后足足有七百多行。(該函數中調用的很多函數都使用了inline修飾,導致該函數在匯編之后指令特別多)

  結合對應DPDK版本的源碼,單條指令一步步執行。在多次嘗試之后,發現每次都會在下圖所示的地方直接返回。

  大致流程是i40e_xmit_pkts()在發送的時候,發現發送隊列滿了就會去調用i40e_xmit_cleanup()清理隊列。DPDK中網卡在發送完數據包后會去回寫特定字段,表明該報文已經發送,而驅動程序去查看該字段就可以知道這個報文是否已經被發過。此處的問題就是驅動程序認為該隊列中的報文始終未被網卡發送出去,后續來的報文將無法加入到隊列而被直接丟棄。

  至此,直接原因已經找到,就是網卡因為某種原因不發包或者沒能正確回寫特定字段,導致驅動程序認為發送隊列始終處于隊列滿的狀態,而無法將后續的報文加入發送隊列。

  那么為什么出現隊列滿?異常包是否相關呢?帶著這個疑問,我們做了第二個嘗試。

  二、一鍵還原網卡報文

  隊列滿,而且后面的報文一直加不進去,說明此時隊列里面的報文一直卡在那。既然我們猜測可能是存在異常報文,那么有沒有可能異常報文還在隊列里面呢?如果可以把當前隊列里面的報文全部導出來,那就可以進一步驗證我們的猜測了。

  基于對DPDK的深入研究,我們根據以下步驟導出報文。

  ?我們看i40e_xmit_pkts()函數,會發現第一個參數就是發送隊列,所以我們可以獲取到隊列的信息。

  ?如下圖所示,在剛進入斷點的時候,查看寄存器信息,以此來獲得該函數對應的參數。

  ?當我們打印該隊列的消息時,卻發現沒有符號信息,此時我們可以如下圖所示去加載編譯時候生成的 i40e_rxtx.o 來獲取對應符號信息。

  ?在得到隊列信息后,我們使用GDB的dump命令將整個隊列中所有的報文全部按隊列中的順序導出,對每個報文按序號命名。

  ?此時導出的報文還是原始的報文,我們無法使用wireshark方便地查看報文信息。為此如下圖所示,我們使用libpcap庫寫了個簡單的小工具轉換成wireshark可以解析的pcap文件。

  果然,如下圖所示,在導出的所有報文中包含了一個長度為26字節,但內容為全0的報文。這個報文看上去十分異常,似乎初步驗證了我們的猜測:

  為了提高在排查問題時導出報文的速度,我們寫了一個報文一鍵導出工具,可以在異常時一鍵導出所有的報文并轉成pcap格式。

  在多次導出報文后,我們發現一個規律:每次都會有一個長度為26字節但是全0的報文,而且在其前面都會有一個同樣長度的報文,且每次源IP地址網段都來自于同一個地區。

  三、流量鏡像,確認異常包

  第二步結論讓整個排查前進了一大步,但是隊列包是經過一系列程序處理的,并不是真正的原始業務報文。不達目的不罷休,關鍵時刻還是要上鏡像抓包,于是當晚緊急聯系網絡運維同事在交換機上配置port-mirroring(端口鏡像),將發往ULB4集群的流量鏡像到一個空閑服務器上進行鏡像抓包。當然,鏡像服務器還需要做特殊配置,如下:

  1. 設置網卡混雜模式,用于收取鏡像流量(ifconfig net2 promisc)。

  2. 關閉GRO功能(ethtool -K net2 gro off),用于收取最原始的報文,防止Linux的GRO功能提前將報文進行組裝。

  根據異常IP的地域特性,我們針對性抓取了部分源IP段的流量。

  參考命令:nohup tcpdump -i net2 -s0 -w %Y%m%d_%H-%M-%S.pcap -G 1800 “proto gre and (((ip[54:4]&0x11223000)==0x11223000) or ((ip[58:4]&0x11223000)==0x11223000))” &

  經過多次嘗試后,功夫不負有心人,故障出現了,經過層層剝離篩選,找到了如下報文:

  這是IP分片報文,但是奇怪的是IP分片的第二片只有IP頭。經過仔細比對,這兩個報文合在一起就是導出隊列報文中的那兩個連在一起的報文。后26字節和全0報文完全吻合。

  我們知道在TCP/IP協議中,如果發送時一個IP報文長度超過了MTU,將會觸發IP分片,會被拆成多個小的分片報文進行發送。正常情況下,所有的分片肯定都是攜帶有數據的。但是這一個分片報文就很異常,報文的總長度是20,也就是說只有一個IP頭,后面不再攜帶任何信息,這樣的報文是沒有任何意義的。這個報文還因為長度太短在經過交換機后被填充了26字節的0。

  至此,我們最終找到了這個異常報文,也基本驗證了我們的猜測。但是還需要去實際驗證是否為這種異常報文導致。(從整個報文的交互來看,這一片報文本來是設置了不可分片的TCP報文,但是在經過某個公網網關后被強制設定了允許分片,并且分片出了這種異常的形式。)

  四、解決方案

  如果確實是這個異常報文導致的,那么只要在收包時對這種異常報文進行檢查然后丟棄就可以了。于是,我們修改DPDK程序,丟棄這類報文。作為驗證,先發布了一臺線上服務器,經過1天運行再也沒有出現異常容災情況。既然問題根因已經找到,正是這種異常報文導致了DPDK工作異常,后續就可以按灰度全網發布了。

  五、DPDK社區反饋

  本著對開源社區負責任的態度,我們準備將BUG向DPDK社區同步。對比最新的commit后,找到11月6日提交的一個commit,情況如出一轍,如下:

  ip_frag: check fragment length of incoming packet

  DPDK 18.11最新發布的版本中,已對此進行了修復,和我們處理邏輯一致,也是丟棄該異常報文。

  復盤和總結

  處理完所有問題后,我們開始做整體復盤。

  一、ULB無法發包的成因總結

  ULB4無法發包的整個產生過程如下:

  1. DPDK收到分片報文中的第一片,將其緩存下來等待后續分片;

  2. 第二片只有IP頭的異常分片到來,DPDK按照正常的報文處理邏輯進行處理,并沒有進行檢查丟棄,于是兩片報文的rte_mbuf結構被鏈在一起,組成了一個鏈式報文返回給ULB4;

  3. 這樣的報文被ULB4接收后,因為整個報文的總長度并沒有達到需要分片的長度,所以ULB4直接調用DPDK的發送接口發送出去;

  4. DPDK沒有對這種異常報文進行檢查,而是直接調用相應的用戶態網卡驅動直接將報文發送出去;

  5. 用戶態網卡驅動在發送這樣的異常報文時觸發了網卡tx hang;

  6. 觸發tx hang后,網卡不再工作,驅動隊列中報文對應的發送描述符不再被網卡正確設置發送完成標記;

  7. 后續的報文持續到來,開始在發送隊列中積壓,最終將整個隊列占滿,再有報文到來時將被直接丟棄。

  二、為什么異常報文會觸發網卡tx hang

  首先我們看下DPDK中跟網卡發送報文相關的代碼。

  從以上的圖中我們可以看到,根據網卡的Datasheet對相關字段進行正確設置非常重要,如果某種原因設置錯誤,將可能會導致不可預知的后果(具體還是要參考網卡的Datasheet)。

  如下圖所示,通常網卡對應的Datasheet中會對相應字段進行相關描述,網卡驅動中一般都會有相應的數據結構與其對應。

  在有了基本了解后,我們猜想如果直接在程序中手動構造這種類似的異常報文,是否也會導致網卡異常不發包?

  答案是肯定的。

  如下圖所示,我們使用這樣的代碼片段構成異常報文,然后調用DPDK接口直接發送,很快網卡就會tx hang。

  三、對直接操作硬件的思考

  直接操作硬件是一件需要非常謹慎的事情,在傳統的Linux系統中,驅動程序一般處于內核態由內核去管理,而且驅動程序代碼中可能進行了各種異常處理,因此很少會發生用戶程序操作導致硬件不工作的情況。而DPDK因為其自身使用用戶態驅動的特點,使得可以在用戶態直接操作硬件,同時為了提升性能可能進行了非常多的優化,如果用戶自身程序處理出問題就有可能會導致網卡tx hang這樣的異常情況發生。

  四、工具的價值

  我們編寫了一鍵導出DPDK驅動隊列報文的工具,這樣就可以在每次出現問題時,快速導出網卡驅動發送隊列中的所有報文,大大提高了排查效率。這個工具再優化下后,準備在UCloud GitHub上開源,希望對DPDK開發者有所幫助。

  寫在最后

  DPDK作為開源套件,通常情況下穩定性和可靠性不存在什么問題,但是實際的應用場景千變萬化,一些特殊情況可能導致DPDK工作異常。雖然發生概率很小,但是DPDK通常在關鍵的網關位置,一旦出現了問題,哪怕是很少見的問題也將會產生嚴重影響。

  因此技術團隊理解其工作原理并對其源碼進行分析,同時能夠結合具體現象一步步定位出DPDK存在的問題,對提高整個DPDK程序的服務可靠性具有重要意義。值得一提的是,ULB4的高可用集群架構在本次問題的處理過程中發揮了重要作用,在一臺不可用的時候,集群中其他機器也可以繼續為用戶提供可靠服務,有效提升了用戶業務的可靠性。

  責任編輯:Erin

機房360微信公眾號訂閱
掃一掃,訂閱更多數據中心資訊

本文地址:http://www.mqcrp.icu/news/201944/n8978117362.html 網友評論: 閱讀次數:
版權聲明:凡本站原創文章,未經授權,禁止轉載,否則追究法律責任。
相關評論
正在加載評論列表...
評論表單加載中...
  • 我要分享
推薦圖片
极速飞艇平台下载 3分钟极速赛车选号公式 500万计划 幸运飞艇冠亚和值有什么根据 北京pk赛车开结果 最新时时源码出售 南越风釆36选7开状结果 网上牛牛赢钱打法 新时时和值 12选5奖金规则 二十一点庄家爆牌概率