天天看點

記一次線上DPDK-LVS的故障排查

背景

我們内部基于dpdk自研的高性能負載均衡器dpvs已經在多個機房部署上線,運作正常,但近期有多個金融相關的業務回報,服務資料包在經過dpvs轉發後,會出現hang住的情況。

問題

dpvs已經在多個機房上線,運作時間已超過半年,為何突然有業務回報異常回報問題的業務多與金融區相關(金融區由于其特殊性,會額外增加安全方面的加強政策)為什麼問題表現均為服務hang住

問題排查

首先,我們懷疑與dpvs或與金融的某些安全政策相關,是以我們做了如下測試(後端上跑的均是相同的測試代碼,并模拟了服務端邏輯):

client < ----- > dpvs < ----- > rs(金融區) 不正常

client < ----- > dpvs < ----- > rs(非金融區) 正常

client < ----- > lvs < ----- > rs(金融區) 正常

client < ----- > lvs < ----- > rs(非金融區) 正常

通過1、2組測試能夠得出結論:該問題與金融區相關且dpvs轉發正常

通過3、4組測試能夠得出結論:該問題與金融區無關且kernel版lvs轉發正常

通過1、3組測試能夠得出結論:該問題與dpvs有關,經過dpvs的請求不正常

通過2、4組測試能夠得出結論:該問題與dpvs/lvs無關,經過dpvs/lvs的請求均正常

以上4組結論兩兩沖突,無法定位問題是與dpvs相關還是與金融區相關,排查一度進入僵局,無法定位故障點。

為了進一步排查,我們在client和後端rs上抓包排查,發現client的請求均能夠正常到達rs,而rs的大部分資料也能夠正常回複給client,但有固定的幾個包總是會被重傳且直至逾時,以下是抓包截圖:

記一次線上DPDK-LVS的故障排查

其中10.128.x.x是rs的ip,10.115.x.0/24是dpvs的local ip,通過在rs上的抓包結果可以清楚的看出rs發給dpvs的length為184的包正确傳輸,但length為2的包一直在重傳,且直至逾時都沒有成功,同時在client上的抓包顯示,client收到了這個length為2的包,但是由于tcp checksum error被丢掉了,并沒有交給上層應用去處理,這樣就解釋了為什麼異常時的表現是hang住,因為某個資料包一直在重傳,直至timeout。

通過上面的分析,我們又産生了疑問:現在的硬體網卡一般都具有csum offload的功能,能夠通過網卡硬體幫我們做checksum,難道是網卡的checksum offload功能出現了問題?如果真是網卡硬體的offload功能出現問題,那影響的應該不是某一個特定的資料包,而是所有經過這塊網卡的資料包才對,是以我們懷疑是網卡在針對某個特定資料包的計算checksum的時候産生了錯誤,為了驗證這個問題,我們在dpvs上進行抓包分析,以下是抓包截圖:

記一次線上DPDK-LVS的故障排查
這個就是被不斷重傳的包,能夠看到dpvs确實收到了這個包,并且處理邏輯也完全正常,剩下的步驟隻有通過網卡做checksum并把這個資料包轉發出去,問題似乎确實是出在了計算checksum這裡,我們在分析這個包有什麼特點,可以看到,這個包的初始大小=ethernet header length + ip header length + tcp header length + tcp data = 14 + 20 + 20 + 5 = 59,而我們知道,在網絡中傳輸的資料幀最小長度為64位元組,除去FCS的4位元組(這部分也由網卡自行計算後添加在資料包末尾),最小長度應為60位元組,也就是說,到達網卡的資料包如果不夠60位元組,那麼網卡會在動在資料包末尾增加全0的padding來使資料包能夠達到60位元組,是以這個資料包也是需要網卡硬體來補充1位元組的padding來達到最小傳輸長度。對此rfc894是這樣規定的:
記一次線上DPDK-LVS的故障排查
是以rs的網卡在資料包長度不足60位元組時需要做兩件事情:
  • 補充1位元組的padding達到最小長度60位元組
  • 補充的padding為全0
記一次線上DPDK-LVS的故障排查
可以看到,在二層頭中,确實有個補充的1位元組的padding:ec,這個padding并沒有按rfc894的規定填充成全0,而是填了非0值,這樣就造成了dpvs的網卡在計算tcp checksum時把這個padding誤當成了tcp data而計算了check sum,是以在client接收到這個資料包并根據ip僞頭部和tcp頭部計算出來的checksum與資料包tcp頭部的checksum不一緻,是以并沒有把這個資料包交給上層應用處理而是直接drop。
記一次線上DPDK-LVS的故障排查

----- 網卡手冊針對 TCP/UDP checksum部分的說明

至此,問題的原因已經很明顯了:部分機器的網卡在做padding時未按照rfc894的規定補充全0而是補充了其他值,導緻dpvs的網卡在做checksum offload時padding的資料也參與了checksum的計算。

分析正常的rs和不正常的rs在網卡硬體上的差别,發現:網卡的硬體型号相同,驅動型号也相同,但不正常的網卡fireware與正常的網卡不相同,而fireware我們沒有辦法自行更新或降級。

整個故障的過程可以大概表示為:

記一次線上DPDK-LVS的故障排查

步驟1:資料包正常,請求資料

步驟2:部分資料包初始長度小于60位元組,需要網卡補充padding,網卡先計算checksum填入tcp標頭後補充padding至資料包末尾,此時checksum正常,但padding不為全0

步驟3:dpvs收到步驟2的包進行正常轉發邏輯處理後轉發至網卡,由網卡計算checksum并轉發,但在計算新的checksum時由于padding非全0導緻checksum計算錯誤,client收到後丢棄了這個包

ps:以上是rs的網卡在添加padding時補充的不是全0,另一種場景是client的網卡在添加padding時補充的不是全0,這兩種情況都會導緻上述問題的出現。

問題解決

至此,我們已經能夠解釋最開始提出的三個問題:

dpvs已經在多個機房上線,運作時間已超過半年,為何突然有業務回報異常

a:該業務是在某個核心機房上線了dpvs後出現了問題,其他機房很早上線了dpvs但由于其他機房是改業務的備份機房實際并未啟用,是以半年多來一直沒有發現問題

回報問題的業務多與金融區相關(金融區由于其特殊性,會額外增加安全方面的加強政策)

a:排查發現是金融區的某一批次機器的fireware存在bug導緻,與金融區本身的安全政策無關

為什麼問題表現均為服務hang住

a:問題的實質是出現丢包,服務在等待響應,是以表現為hang住

接下來我們将解決該問題:

隻要讓dpvs在處理資料包時,忽略資料包以前的padding部分,而由dpvs的網卡重新去處理padding(由于網卡計算checksum是在補充padding之前,是以可以保證此時的checksum一定是正确的)。由于dpvs是基于dpdk開發的,資料包在dpvs中是以mbuf的結構儲存和處理的,以下是mbuf的結構:
記一次線上DPDK-LVS的故障排查
資料幀被存儲在headroom和tailroom之間(與skb類似),pkt_len=data_len=整個資料幀的長度,我們要做的就是将padding從data中去除(放到tailroom中去),是以可以在資料包入口處添加以下代碼:
int padding_length = mbuf->data_len - (mbuf->l2_len +rte_be_to_cpu_16(ipv4_hdr->total_length));

mbuf->data_len = mbuf->data_len - padding_length;

mbuf->pkt_len = mbuf->data_len;           

添加以上代碼後測試通過,本次故障解決。

參考資料

繼續閱讀