QPS比Nginx提升60%,阿里Tengine負載均衡算法揭祕

前言

在阿里七層流量入口接入層(Application Gateway)場景下,Nginx 官方的 Smooth Weighted Round-Robin(SWRR)負載均衡算法已經遭遇瓶頸。阿里自研 Tengine 通過實現新的負載均衡算法 Virtual Node Smooth Weighted Round-Robin(VNSWRR)解決了 SWRR 算法在阿里業務場景下的缺陷,而且 QPS 處理能力相對於 Nginx 官方的 SWRR 算法也提升了 60% 左右。

問題

接入層 Tengine 通過自研的動態 upstream 模塊實現動態服務發現,即運行時動態感知後端應用機器擴縮容、權重調整和健康檢查等信息。同時該功能可以做很多事情,比如用戶可通過調整後端應用某臺機器的權重從而達到線上真實引流壓測目的。然而,這些操作在 Nginx 原生 SWRR 算法下卻可能引起不可逆轉的血案。

  • 在接入層(Application Gateway)場景下,Nginx 的負載均衡算法 SWRR 會導致權重被調高機器的 QPS 瞬間暴漲,如上圖 App2-host-A 機器當權重調整爲 2 時,某一時刻流量會集中轉發到該機器;

  • Nginx 的 SWRR 算法的處理時間複雜度是 O(N),在大規模後端場景下 Nginx 的處理能力將線性下降;

綜上所述,對接入層 Tengine 的負載均衡轉發策略的改造及性能優化已迫在眉睫。

原生 SWRR 算法分析

在介紹案列之前,我們先簡單介紹下 Nginx 的負載均衡算法 SWRR 轉發策略及特點:

SWRR 算法全稱是 Smooth Weighted Round-Robin Balancing,顧名思義該算法相比於其它加權輪詢(WRR)算法多一個 smooth(平滑)的特性。

下面我們就一個簡單的列子來描述下該算法:

假設有 3 臺機器 A、B、C 權重分別爲 5、1、1,其中數組 s 代表機器列表、n 代表機器數量,每個機器的 cw 初始化爲 0、ew 初始化爲機器權重、tw 代表本輪選擇中所有機器的 ew 之和、best 表示本輪被選中的機器。簡單的描述就是每次選擇機器列表中 cw 值最大的機器,被選中機器的 cw 將會減去 tw,從而降低下次被選中的機會,簡單的僞代碼描述如下:

best = NULL;
tw = 0;
for(i = random() % n; i != i || falg; i = (i + 1) % n) {
    flag = 0;
    s[i].cw += s[i].ew;
    tw += s[i].ew;
    if (best == NULL || s[i].cw > best->cw) {
        best = &s[i];
    }
}

best->cw -= tw;
return best;

其 SWRR 算法選擇的順序爲:{ A, A, B, A, C, A, A }

而普通 WRR 算法選擇的順序可能爲:{ C, B, A, A, A, A, A }

SWRR 相比於普通的 WRR 算法特點:平滑、分散 。

調高權重引發的血案

從上面的描述來看,SWRR 算法似乎已經比較完美了,但是在某些場景下還是有一定的缺陷,下面我們就一個真實的案列來看看它都有哪些缺陷:

一天早上,流量調度的同學匆忙的跑到我的工位,當時看他神色是尤爲的緊張,心想肯定是出啥問題了。果不其然:“爲啥我把中心機房某臺機器的權重從 1 調整爲 2 的時候,接入層 Tengine 並不是按照這個權重比例轉發流量恩?”,當時被調高機器 QPS 變化趨勢如下圖所示:

注:其中深藍色曲線表示權重被調高機器的 QPS 變化,淺綠色曲線表示該集羣單機的平均 QPS。

當時看到這個流量趨勢變化圖的時候也是一臉茫然,不過好在有圖有數據,那就可以先分析一下這個圖的幾個特徵數字;由於部分數據敏感,詳細數據分析就不在此處展開。直接描述其現象和原因:

被調高權重的機器當時被分發到的流量基本上是該應用機房總流量的 1/2,一段時間後該機器的流量才恢復到預期的權重比例。其原因就是由於接入層 Tengine 對後端機器信息的變化是動態感知熱生效的,而 Nginx 官方的 SWRR 算法策略第一次會選擇當前機器列表中權重最大的機器轉發流量。從而進一步導致已感知到後端機器權重變化的接入層 Tengine 都會將第一個請求轉發到權重被調高的機器上。

大規模下性能驟降

如下是在 upstream 裏面配置 2000 個後端,在反向代理場景下壓測 Nginx 的函數熱點圖如下所示。其中 ngx_http_upstream_get_peer 函數 CPU 消耗佔比高達 39%,其原因是因爲 SWRR 算法的選取機器的時間複雜度爲 O(N) (其中 N 代表後端機器數量),這就相當於每個請求都要執行接近 2000 次循環才能找到對應本次轉發的後端機器。

壓測環境

  • CPU 型號:Intel® Xeon® CPU E5-2682 v4 @ 2.50GHz

  • 壓測工具:./wrk -t25 -d5m -c500 ‘http://ip/t2000

  • Tengine 核心配置:配置 2 個 worker 進程,壓力源 – 長連接 --> Tengine/Nginx – 短連接 --> 後端

下面我們做個試驗,控制變量是 upstream 裏面配置的 server 數量,觀察不同場景下 Nginx 的 QPS 處理能力以及響應時間 RT 變化情況。從圖中可以發現當後端 upstream 裏面的 server 數量每增加 500 臺則 Nginx 的 QPS 處理能力下降 10% 左右,響應 RT 增長 1ms 左右。

從上面的分析基本上已經確認是 SWRR 算法存在如上兩個缺陷,下面就開始解決;

改進的 VNSWRR 算法

雖然經典的 WRR 算法(如隨機數方式實現)可以在時間複雜度上達到 O(1) ,而且也可以避免 SWRR 算法調高權重的選取缺陷。但是在某些場景下(如小流量)可能造成後端的流量不均等問題,尤其是在流量瞬間暴漲的場景下有太多不可確定性。於是就構思是否有一種算法即能擁有 SWRR 算法的平滑、分散特點,又能具備 O(1) 的時間複雜度。所以就有了 Virtual Node Smooth Weighted Round-Robin(VNSWRR)算法。

此處拿個列子來說明此算法:3 臺機器 A、B、C 權重分別爲 1、2、3,N 代表後端機器數 、TW 代表後端機器權重總和。

算法關鍵點

  • 虛擬節點初始化順序嚴格按照 SWRR 算法選取,保證初始化列表裏的機器能夠分佈足夠散列;

  • 虛擬節點運行時分批初始化,避免密集型計算集中。每批次虛擬節點使用完後再進行下一批次虛擬節點列表初始化,每次只初始化 min(n, max) 個虛擬節點;

算法描述

  • Tengine 程序啓動或者運行時感知後端機器信息變化時,則構建 TW 個虛擬節點且第一次只初始化 N 個節點(注:TW 代表後端機器權重之和,N 代表後端機器數);

  • 各個進程設置隨機起點輪詢位置,如上圖的 Step 1 對應的列表其起點位置指向 B;

  • 當請求到達後從設置的隨機起點 B 位置輪詢虛擬節點列表,若輪詢到已經初始化的虛擬節點數組的末尾(如上圖的 Step2 紅色箭頭指向的位置),則初始化第二批虛擬節點(如上圖 Step2 對應的紅色節點),當所有虛擬節點初始化完後將不再做初始化工作(如上圖的 Step3 對應的狀態);

此方案不僅將算法時間複雜度從 O(N) 優化到 O(1) ,而且也避免了權重調高場景下帶來的問題。如下圖所示後端某臺機器權重從 1 調整爲 2 後,其 QPS 平滑的增長到預期比列。

算法效果比較

在同等壓測環境下(wrk 壓測工具、500 併發、長連接場景、upstream 配置 2000 個 server),Nginx 官方的 SWRR 算法 CPU 消耗佔比高達 39%(ngx_http_upstream_get_peer 函數)。而 VNSWRR 算法在同等條件下 CPU 消耗佔比只有 0.27% 左右(ngx_http_upstream_get_vnswrr 函數),顯而易見 SWRR CPU 消耗要高出一個數量級。

在上述壓測環境下,Nginx 官方的 SWRR 和改進的 VNSWRR 算法下的 QPS 處理能力如下圖所示:其中 VNSWRR 的 QPS 處理能力相對於 SWRR 算法提升 60% 左右。

下面我們來做個試驗,在 upstream 裏配置 server 數量變化的場景下,對比 VNSWRR 和 SWRR 算法觀察 Nginx 的 QPS 處理能力以及響應時間 RT 變化。

從圖中可以發現在 SWRR 算法下當 upstream 裏面的 server 數量每增加 500 臺,則 Nginx 的 QPS 處理能力下降 10% 左右、響應 RT 增長 1ms 左右,而在 VNSWRR 算法下 Tengine 的 QPS 處理能力及 RT 基本上變化不大。

總結

正是這種大流量場景下才暴露出 Nginx 的一些問題,所謂業務與技術相輔相成,業務可促使新的技術誕生、新的技術賦能創造新的業務。VNSWRR 算法既擁有 SWRR 算法的平滑、分散特點,也避免了其缺陷。同時在新算法下時間複雜度也從 O(N) 調整爲 O(1) ,在大規模場景下 VNSWRR 的 QPS 處理能力相對於 Nginx 官方的 SWRR 算法提升 60% 左右。

Tengine 已在 GitHub 開源,項目地址:

https://github.com/alibaba/tengine

作者簡介

王發康(花名:毅鬆),GitHub ID @wangfakang ,Tengine 開源項目 maintainer,阿里巴巴技術專家,負責阿里巴巴 WEB 統一接入層的開發及維護。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章