本文記錄了dpdk-lvs集羣的一次線上故障排查過程,排查思路可供讀者參考。
上篇文章回顧: SOAR的IDE插件——您的貼身DBA保鏢
咱們內部基於 dpdk 自研的高性能負載均衡器 dpdk-lvs 已經在多個機房部署上線,運行正常,但近期有多個金融相關的業務反饋,服務數據包在通過dpdk-lvs轉發後,會出現hang住的狀況。html
一、dpdk-lvs 已經在多個機房上線,運行時間已超過半年,爲什麼忽然有業務反饋異常後端
二、反饋問題的業務多與金融區相關(金融區因爲其特殊性,會額外增長安全方面的加固策略)安全
三、爲何問題表現均爲服務hang住bash
首先,咱們懷疑與dpdk-lvs或與金融的某些安全策略相關,所以咱們作了以下測試(後端上跑的均是相同的測試代碼,並模擬了服務端邏輯):網絡
一、client < ----- > dpdk-lvs < ----- > rs(金融區) 不正常負載均衡
二、client < ----- > dpdk-lvs < ----- > rs(非金融區) 正常運維
三、client < ----- > lvs < ----- > rs(金融區) 正常tcp
四、client < ----- > lvs < ----- > rs(非金融區) 正常ide
經過一、2組測試可以得出結論:該問題與金融區相關且dpdk-lvs轉發正常性能
經過三、4組測試可以得出結論:該問題與金融區無關且kernel版lvs轉發正常
經過一、3組測試可以得出結論:該問題與dpdk-lvs有關,通過dpdk-lvs的請求不正常
經過二、4組測試可以得出結論:該問題與dpdk-lvs/lvs無關,通過dpdk-lvs/lvs的請求均正常
以上4組結論兩兩衝突,沒法定位問題是與dpdk-lvs相關仍是與金融區相關,排查一度進入僵局,沒法定位故障點。
爲了進一步排查,咱們在client和後端rs上抓包排查,發現client的請求均可以正常到達rs,而rs的大部分數據也可以正常回復給client,但有固定的幾個包老是會被重傳且直至超時,如下是抓包截圖:
其中10.128.129.14是rs的ip,10.115.167.0/24是dpdk-lvs的local ip,經過在rs上的抓包結果能夠清楚的看出rs發給dpdk-lvs的length爲184的包正確傳輸,但length爲2的包一直在重傳,且直至超時都沒有成功,同時在client上的抓包顯示,client收到了這個length爲2的包,可是因爲tcp checksum error被丟掉了,並無交給上層應用去處理,這樣就解釋了爲何異常時的表現是hang住,由於某個數據包一直在重傳,直至timeout。
經過上面的分析,咱們又產生了疑問:如今的硬件網卡通常都具備csum offload的功能,可以經過網卡硬件幫咱們作checksum,難道是網卡的checksum offload功能出現了問題?若是真是網卡硬件的offload功能出現問題,那影響的應該不是某一個特定的數據包,而是全部通過這塊網卡的數據包纔對,所以咱們懷疑是網卡在針對某個特定數據包的計算checksum的時候產生了錯誤,爲了驗證這個問題,咱們在dpdk-lvs上進行抓包分析,如下是抓包截圖:
這個包就是被不斷重傳的包,可以看到dpdk-lvs確實收到了這個包,而且處理邏輯也徹底正常,剩下的步驟只有經過網卡作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是這樣規定的:
所以rs的網卡在數據包長度不足60字節時須要作兩件事情:
一、補充1字節的padding達到最小長度60字節
二、補充的padding爲全0
能夠看到,在二層頭中,確實有個補充的1字節的padding:ec,這個padding並無按rfc894的規定填充成全0,而是填了非0值,這樣就形成了dpdk-lvs的網卡在計算tcp checksum時把這個padding誤當成了tcp data而計算了check sum,所以在client接收到這個數據包並根據ip僞頭部和tcp頭部計算出來的checksum與數據包tcp頭部的checksum不一致,所以並無把這個數據包交給上層應用處理而是直接drop。
(網卡手冊針對 TCP/UDP checksum部分的說明)
至此,問題的緣由已經很明顯了:部分機器的網卡在作padding時未按照rfc894的規定補充全0而是補充了其餘值,致使dpdk-lvs的網卡在作checksum offload時padding的數據也參與了checksum的計算。
分析正常的rs和不正常的rs在網卡硬件上的差異,發現:網卡的硬件型號相同,驅動型號也相同,但不正常的網卡fireware與正常的網卡不相同,而fireware咱們沒有辦法自行升級或降級。
整個故障的過程能夠大概表示爲:
client dpdk-lvs rs
---1--- >
< ---2---
< ---3---
步驟1:數據包正常,請求數據
步驟2:部分數據包初始長度小於60字節,須要網卡補充padding,網卡先計算checksum填入tcp包頭後補充padding至數據包末尾,此時checksum正常,但padding不爲全0
步驟3:dpdk-lvs收到步驟2的包進行正常轉發邏輯處理後轉發至網卡,由網卡計算checksum並轉發,但在計算新的checksum時因爲padding非全0致使checksum計算錯誤,client收到後丟棄了這個包
ps:以上是rs的網卡在添加padding時補充的不是全0,另外一種場景是client的網卡在添加padding時補充的不是全0,這兩種狀況都會致使上述問題的出現。
至此,咱們已經可以解釋最開始提出的三個問題:
一、dpdk-lvs已經在多個機房上線,運行時間已超過半年,爲什麼忽然有業務反饋異常
A:該業務是在某個核心機房上線了dpdk-lvs後出現了問題,其餘機房很早上線了dpdk-lvs但因爲其餘機房是改業務的備份機房實際並未啓用,所以半年多來一直沒有發現問題
二、反饋問題的業務多與金融區相關(金融區因爲其特殊性,會額外增長安全方面的加固策略)
A:排查發現是金融區的某一批次機器的fireware存在bug致使,與金融區自己的安全策略無關
三、爲何問題表現均爲服務hang住
A:問題的實質是出現丟包,服務在等待響應,所以表現爲hang住
接下來咱們將解決該問題:
只要讓dpdk-lvs在處理數據包時,忽略數據包之前的padding部分,而由dpdk-lvs的網卡從新去處理padding(因爲網卡計算checksum是在補充padding以前,所以能夠保證此時的checksum必定是正確的)。因爲dpdk-lvs是基於dpdk開發的,數據包在dpdk-lvs中是以mbuf的結構保存和處理的,如下是mbuf的結構:
數據幀被存儲在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;複製代碼
添加以上代碼後測試經過,本次故障解決。
參考資料
https://tools.ietf.org/html/rfc894
http://doc.dpdk.org/guides/prog_guide/mbuf_lib.html
https://www.intel.com/content/dam/www/public/us/en/documents/datasheets/82599-10-gbe-controller-datasheet.pdf
本文首發於公衆號「小米運維」,點擊查看原文