作者:月賓jerry
前言
作為阿裡雲底層提供的基礎設施,内部的實體網絡和許多網絡産品在資料平面給客戶的可操作性并不高,從一定程度上來說是個黑盒。當然,在傳統的IDC環境,業務和實體網絡之間也存在同樣的隔閡。是以在遇到業務卡頓、延遲、不通等問題的時候,很容易懷疑到網絡。是以如何抽絲撥繭,找到正确的方向對症下藥才能夠真正的解決問題。畢竟“真相隻有一個”。
在進行問題排查和處理的時候,難度最高的場景就是極度偶發,複現頻率極低的問題。尤其在網絡排查的領域,通常為了性能和控制資源消耗,不會将每一個資料包的情況都一一記錄下來,對于一次偶發的應用層記錄的逾時,網絡層通常沒有明确的對應此次應用層調用的包互動記錄,是以排查起來非常困難。
在這次的案例中,我們通過一個用戶端查詢redis叢集偶發逾時的小案例,來說明一些診斷思路、排查手段,進而引出一些在網絡方面提高業務穩定性的最佳實踐。
問題環境
這次的問題是一個互動性web應用中的一個子子產品,主要進行redis查詢,可以簡單将其了解為視訊彈幕網站中“查詢彈幕”的小子產品。這個子產品的拓撲非常簡單:

在上面的拓撲中,客戶使用ECS建構了一個Redis叢集,前面用Codis實作了一層Redis Proxy (為了通用性,後面均用Redis proxy來描述),并将這組Redis proxy挂載在一個SLB後,通過SLB的單一入口提供服務。
問題現象
客戶的主要問題是通路其自建Redis系統的用戶端會不定期出現逾時報錯,盡管總體機率不高,但是報錯機率高于其業務運作在原有機房的水準。逾時報錯主要有兩種情況:
- 一般情況下逾時數量與業務量呈正相關,非業務高峰期但是SLB、ECS的資源使用率均較低。
- 會存在突發性的大量逾時。
診斷思路
作為問題排查的第一步,首先要了解到問題本身所處的上下文和環境。在平時診斷問題收集資訊的時候,為了有條理的、全面的收集資訊,筆者将需要收集的資訊分為兩種類型:資源因素和環境因素。
- 資源因素:即發生問題的系統的拓撲。比如涉及的各種應用程式、主機、轉發裝置、鍊路資源等,并且要充分了解這些資源組建在拓撲中起到的作用。
-
環境因素:即描述這個問題所需要的資訊,比如報錯日志,問題發生時間、頻率,應用層設定的逾時時間等等。
了解資源因素和環境因素後,可以将問題的定義明确為:在哪些資源上發生了什麼樣的問題,然後根據該定義收集與問題相關的資訊,并在解讀和分析的時候通過資料排除所有的不可能,這樣才能進行高效和準确的問題排查。
在本案例中,資源因素已經在上文的拓撲中闡述,問題所涉及的環境因素包括:客戶設定的是50ms逾時,在用戶端的報錯是read timeout(代表排除了tcp的三次握手逾時),報錯頻率為非業務高峰期一個小時10個左右,業務高峰期1小時上百個。但是偶爾(一周内偶爾發生一次到兩次)無論業務高峰還是非業務高峰都會有較多的,上百次的read timeout和connect timeout。客戶已經排查過redis,其查詢時間每次耗時不超過10ms,而redis proxy沒有記錄轉發的日志。
排查方法
因為所有可用的日志僅能定位到這個系統的兩端(用戶端、Redis),需要收集進一步的資訊。面對這種逾時類的問題,最直接、有效的辦法就是進行抓包。而該問題發生的頻率不高,整個系統流量也比較大,一直開着抓包很容易将磁盤撐滿,是以需要使用循環抓包:
tcpdump -i <接口|any> -C <每檔案大小> -W <檔案個數> -w <儲存檔案名> 抓包過濾條件
該指令的意思是針對某個接口,按照過濾條件進行抓包,儲存指定檔案名字首的檔案下,最多占用每檔案大小*檔案個數 的磁盤空間并循環覆寫。開啟循環抓包後,等待用戶端報錯再次出現,即可抓到現場的包互動過程。
抓包的結果檔案可以使用wireshark打開,但是使用循環抓包抓到的資料封包件較大、數量較多,可以使用下面的小技巧進行快速的過濾:
//在安裝了wireshark的電腦上都會有capinfos和tshark兩個指令,以筆者使用的macOS為例
~$ capinfos -a -e *cap //使用capinfos檢視抓封包件的其實時間和結束時間,選取包含報錯時間+-逾時時間的檔案,其他檔案就不需要了
File name: colasoft_packets.cap
Packet size limit: inferred: 66 bytes - 1518 bytes (range)
First packet time: 2019-06-12 09:00:00.005519934
Last packet time: 2019-06-12 09:59:59.998942048
File name: colasoft_packets1.cap
Packet size limit: inferred: 60 bytes - 1518 bytes (range)
First packet time: 2019-06-12 09:00:00.003709451
Last packet time: 2019-06-12 09:59:59.983532957
//如果依然有較多檔案,則可以使用tshark指令進行篩選。比如報錯中提到Redis查詢一個key逾時,則可以用以下腳本找到這次查詢請求具體在哪個檔案中:
~$ for f in ./*; do echo $f; tshark -r $f 'tcp.payload contains "keyname"'; done
找到對應的請求之後,再用wireshark打開該檔案,找到對應資料包,跟蹤對應流來找到五元組和整個流的上下文互動。
在本案例中,通過對比用戶端、redis proxy和redis 三層的抓包,發現用戶端送出請求到收到響應的時間的确在問題發生時話費了100多ms,而這部分耗時主要發生在Redis将響應傳回給Redis proxy的丢包重傳導緻。整體時序示意圖如下:
對于從抓包中觀察到的丢包現象,在通過阿裡雲内部監控确定了實體鍊路的确不存在丢包的情況下,我們發現Redis proxy所在的ECS上,虛拟化層面的後端驅動在向前端驅動送包的時候,前後端隊列的丢包計數的增長趨勢和業務逾時的頻率有相同趨勢,進一步排查發現客戶ECS作業系統内的網卡多隊列沒有開啟,導緻隻有一個CPU處理網卡中斷,而當流量有瞬間突增的時候,CPU來不及處理網卡中斷導緻前後端隊列堆積,隊列溢出後導緻丢包。
為了解決這個問題,我們建議客戶将網卡多隊列開啟,并将不同網卡隊列中斷的CPU親和性綁定在不同的CPU上。對于阿裡雲ECS,可以使用的網卡隊列是和執行個體規格綁定的,具體可以參考ECS執行個體規格文檔。簡單的開啟網卡隊列并使用irqbalance 自動排程網卡隊列中斷CPU親和性的方法可以參考阿裡雲官方文檔。
本案例中客戶開啟網卡多隊列并開啟irqbalance服務之後,每小時都出現的通路逾時問題已經解決,但是還是會有每隔幾天會出現的突發性大量逾時。經過彙聚客戶的報錯資訊和阿裡雲底層的網絡監控,我們最終确認這種每隔幾天就會出現的突發性大量逾時是因為阿裡雲底層的跨可用區間鍊路抖動導緻的。
阿裡雲的每一個可用區可以了解為是一個機房,而不同可用區之間可以互為同城災備關系。為了確定可用區之間不會故障擴散,不同可用區機房需要保持一定實體機距離,并通過同城傳輸光纜将所有可用區互相連接配接實作可用區之間的互訪。
連接配接可用區之間的同城傳輸光纜的可靠性遠低于機房内部跳纖,且經常容易受到道路施工、品質劣化的影響,導緻鍊路中斷。為了保證業務連續性,阿裡雲提供了充足的備援鍊路并使用傳輸倒換、路由切換等技術確定部分跨可用區鍊路時故障可以自動收斂,但是在倒換過程中産生的丢包卻無法完全避免。根據阿裡雲底層監控,當一條跨可用區鍊路中斷時,通常會導緻持續3-5秒的1%左右的丢包(具體需要看中斷鍊路數量占總鍊路數量的占比),而反映在業務上,則有可能造成時延敏感業務接近1分鐘的部分逾時報錯。是以在本案例中造成了突增的逾時報錯。
假如客戶使用資源時,可用區分布非常散亂,則會造成可用區間鍊路抖動對業務影響的頻率升高。比如客戶的用戶端ECS分布在多個可用區(A、B),SLB在可用區C ,Redis proxy和Redis在可用區D、E,則A到C、B到C、C到D、D到E的跨可用區鍊路抖動都會影響到整個系統。
最佳實踐
通過這個案例我們可以總結出關于主機網絡和網絡部署方面兩個最佳實踐:
- 主機網絡方面:打開網卡多隊列并将網卡軟中斷打散以擷取最佳的網絡性能。總體來講,為了獲得穩定的網絡性能,有以下通用建議:
- 使用VPC執行個體:除了網絡租戶隔離、支援專線、VPN網關等好處外,VPC環境在底層轉發能力上也比經典網絡執行個體有大幅提高,最新一代執行個體均基于VPC環境實作,是以也提供了更強的網絡轉發性能。
- 使用獨享型執行個體:獨享型執行個體采用嚴格的資源隔離技術,確定虛拟機不會收到“吵鬧的鄰居”影響。
- 打開網卡多隊列并綁定網卡軟中斷處理CPU親和性:對于不同網卡隊列使用不同CPU進行處理,提高網絡處理性能
- 将網卡多個隊列分别綁定到某幾個專用CPU上,而其他程序綁定到其他CPU上,讓網卡軟中斷處理使用專門的CPU:适用于純轉發類、對網絡性能要求極高的服務。
//綁定網卡軟中斷的方法:
//1. 首先看cat /proc/interrupts | grep virtio,在阿裡雲提供的标準作業系統中,virtio0是網卡隊列
~$cat /proc/interrupts | grep virtio
//omit outputs
31: 310437168 0 0 0 PCI-MSI-edge virtio0-input.0
32: 346644209 0 0 0 PCI-MSI-edge virtio0-output.0
//将第一列的中斷号記錄下來,修改下面的檔案綁定CPU親和性
echo <cpu affinity mask> /proc/irq/{irq number}/smp_affinity
//具體CPU affinity mask可以參考manpage https://linux.die.net/man/1/taskset,這裡不再說明。
- 實體網絡方面:建議從業務容忍度和時延敏感度進行權衡來選擇業務的部署。
- 從業務容忍度的角度來說,如果tcp協定中發生了丢包,那麼最壞情況下需要等待RTO逾時才能夠重傳(tail drop場景,其他場景有fast retrans機制),而RTO逾時的最小取值在kernel中的定義為200HZ,即200ms。對于内網互訪或者同城互訪這種時延較低的場景,可以了解為一次丢包的最壞情況就是200ms的重傳,是以對于關鍵業務,至少将請求逾時設定在200ms以上,讓tcp有一次重傳的機會。而對于非關鍵業務,一次查詢是否傳回資料并不關鍵的,則可以将請求逾時設定的更小以便保護整個系統。是以業務容忍有兩個方面:業務可以容忍錯誤,或者業務可以容忍重傳。
- 從時延敏感度的角度來說,為了確定時延敏感業務盡量少的受跨可用區鍊路影響,建議盡量将時延敏感業務的整個業務調用都在一個可用區内完成。而不同的可用區之間盡管提供相同服務,但是之間不會經常跨可用區調用。比如web server層調用提供緩存服務的Redis在本可用區完成,隻有緩存沒有命中的少量情況,才有可能跨可用區查詢資料庫,甚至使用隻讀執行個體等其他技術,将跨可用區鍊路抖動的影響降至最低。
結束語
通過上面的案例和最佳實踐的說明,可以看到“權衡”在業務系統架構涉及和部署當中是無處不在的。所謂優化就是在給定的環境下,為了實作業務目标,将資源傾斜到最需要的地方。另一方面,對于許多客戶在上雲前的系統架構中,受限與機房成本、位置等原因,可能沒有使用過多機房的組網場景,而雲計算對這些客戶帶來的除了基礎設施跨代更新的便利之外,還提供了天然的容災能力,而業務系統的架構和部署也需要增加因容災所帶來的組網場景的複雜化。