我們如何使用HAProxy實現單機200萬SSL連接
先觀察上面截圖,可以看到兩個關鍵信息:
這台機器已經建立了 238 萬個 TCP 連接
使用內存大約在 48G。
下面將會介紹在單個 HAProxy 機器上實現這種規模訪問所需的配置。本文是負載測試 HAProxy 系列文章的最後一篇。有時間的讀者建議閱讀本系列的前兩篇(見文末鏈接),它將幫助您了解相應的內核調優方法。
在這個配置過程中,我們也使用了很多小組件幫助我們達到目標。
在展開最終 HAProxy 配置之前,我想給大家回顧一下負載測試的歷程及想法,心急的讀者可以直接跳到文章後段查閱相關 HAProxy 配置。
測試目標我們要測試的組件是 HAProxy 1.6 版。生產環境是在 4 核 30 G 的機器上運行該軟體,當前所有的連接都是非 SSL 的。
測試目標有兩方面:
當將整個負載從非 SSL 連接轉移到 SSL 連接時,CPU 使用率增加的百分比。CPU 的使用率肯定會增加,這是由於 5 次握手的加長和數據包加密的開銷所帶來。
其次,希望能夠測試單個 HAProxy 每秒請求數和最大並發連接數的上限
目標一主要因為業務方面功能需要通過 SSL 進行通信。 目標二是為了可以在生產環境中部署最少規模的 HAProxy 機器。
組件和配置使用多台客戶端機器來執行 HAProxy 壓力測試。
有各種配置的 HAProxy 1.6 的機器
4核,30G
16核,30G
16核,64G
相關後端伺服器,用於支持所有並發訪問。
HTTP 和 MQTT
我們的整個基礎設施支持兩種協議:
HTTP
MQTT
在我們的技術棧中,沒有使用 HTTP 2.0,因此在 HTTP 上沒有長連的功能。所以在生產環境中,單個 HAProxy 機器(上行 + 下行)的最大數量的 TCP 連接在(2 * 150k)左右。雖然並發連接數量相當低,但每秒請求的數量卻相當高。
另一方面,MQTT 是一種不同的通信方式。它提供高質量的服務參數和持久的連接性。因此,可以在 MQTT 通道上使用雙向長連通信。對於支持 MQTT(底層 TCP)連接的 HAProxy,在高峰時段會看到每台機器上大約有 600 - 700k 個 TCP 連接。
我們希望進行負載測試,這將為我們提供基於 HTTP 和 MQTT 連接的精確結果。
有很多工具可以幫助我們輕鬆地測試 HTTP 伺服器,並且提供了高級功能,如結果匯總,將文本轉換為圖形等。然而,針對 MQTT,我們找不到任何壓力測試工具。我們確實有一個自己開發的工具,但是它不夠穩定,不足以支持這種負載。
所以我們決定使用客戶端測試 HTTP 負載,並在 MQTT 伺服器使用相同配置。
初始化設置考慮到相關內容對於進行類似的壓力測試或調優的人來說有幫助,本文提供了很多相關細節,篇幅稍微有些長。
我們採用了一台 16 核 30G 機器來運行 HAProxy,考慮到 HAProxy 的 SSL 產生的 CPU 巨大開銷,因此沒有直接使用目前生產環境。
對於伺服器端,我們使用了一個簡單的 NodeJs 伺服器,它在接收到 ping 請求時用 pong 進行回復。
對於客戶端,我們最終使用 Apache Bench。使用 ab 的原因是因為它是一個大家熟悉和穩定的負載測試工具,它也提供了很好的測試結果匯總,這正是我們所需要的。
ab 工具提供了許多有用的參數用於我們的負載測試,如:
-c,指定訪問伺服器的並發請求數。
-n,顧名思義,指定當前負載運行的請求總數。
-p,包含 POST 請求的正文(要測試的內容)。
如果仔細觀察這些參數,您會發現通過調整所有這三個參數可以進行很多排列組合。示例 ab 請求將看起來像這樣
ab -S -p post_smaller.txt -T application/json -q -n 100000 -c 3000 http://test.haproxy.in:80/ping
這樣的請求的示例結果看起來像這樣
我們感興趣的數字是:
99% 的返回請求的響應延遲時間。
Time per request:每個請求的時間
No. of failed requests:失敗請求數。
Requests per second: 每秒請求量
ab 的最大問題是它不提供控制每秒發起請求量,因此我們不得不調整 -c 並發級別以獲得所需的每秒鐘請求數,並導致很多後文提到的問題和錯誤。
測試圖表我們不能隨機地進行多次測試來獲得結果,這不會給我們提供任何有意義的信息。我們必須以某種具體的方式執行這些測試,以便從中獲得有意義的結果。來看看這個圖。
該圖表明,在某一點之前,如果不斷增加請求數量,延遲將幾乎保持不變。然而,達到某個臨界點,延遲將開始呈指數級增長。這就是該機器的臨界點。
Ganglia在提供一些測試結果之前,我想提一下 Ganglia。
Ganglia 是用於高性能計算系統(如集群和網格)的可擴展分布式監控系統。
看看截圖,了解 Ganglia 是什麼,以及它提供的關於底層機器的信息。
通過 Ganglia 可以監測 HAProxy 機器上一些重要參數。
TCP established 這告訴我們在系統上建立的 TCP 連接總數。注意:這是上行和下行連接的總和。
packets sent and received 發送和接收的 TCP 數據包的總數。
bytes sent and received 這將顯示發送和接收的位元組數。
memory 隨著時間的推移使用的內存數。
network 通過線路發送數據包而消耗的網路帶寬。
以下是通過通過負載測試找到的已知限制。
700k TCP 連接,
50k 發送包數量,60k 接收包數量,
10-15MB 發送及接收的位元組數,
14-15G 內存峰值,
7MB 帶寬。
所有這些值都是基於每秒數據
HAProxy Nbproc
最初,當我們開始測試 HAProxy 時,發現使用 SSL 情況下,CPU 很早就到了瓶頸,而每秒請求數都很低。 在使用 top 命令後,發現 HAProxy 只使用 1 個 CPU 核。 而我們還有 15 個以上的核沒用。
Google 了 10 分鐘後,我們在 HAProxy 中找到某個設置,可以讓 HAProxy 使用多個核。
它被稱為 nbproc,具體設置請看這篇文章 [8]:
調整此設置是我們的負載測試策略的基礎。 讓我們可以方面的進行 HAProxy 組合以便測試。
使用 AB 進行壓力測試當開始負載測試之旅時,我們不清楚應該測量的指標和需要達到的目標。
最初,我們只有一個目標:通過改變所有下面提到的參數來找到臨界點。
我保留了各種負載測試結果的表格。 總而言之,做了 500 多次測試,以達到最終的效果。 您可以清楚地看到,每次測試都有很多不同的部分。
單客戶端問題我們看到客戶端正在成為瓶頸,因為我們不斷增加每秒的請求數。 ab 使用單個核,從文檔中可以看出,它不提供使用多核的功能。
為了有效地運行多個客戶端,我們發現一個有用的 Linux 工具叫做 Parallel [7]。 顧名思義,它可以幫助您同時運行多個命令來達到並行的目的。 正是我們想要的。
看一下使用 Parallel 運行多個客戶端的示例命令。
上述命令將運行 3 個 ab 客戶端擊訪問同一個 URL。 這有助於我們消除客戶端瓶頸。
Sleep 及 Times 參數的問題下面是 Ganglia 中的一些參數。讓我們簡單討論一下。
packets sent and received 為了產生更多數據,可以在 post 請求中添加更多數據
tcp_established 這是想實現的目標。想像一下,如果單個 ping 請求大約需要一秒鐘,那麼每秒需要大約 700k 個請求來達到 tcp_established 的目標。現在這個數字在生產環境中可能看起來更容易達到,但是在測試場景中不太可能達到。
我們在 POST 調用中加入了一個 sleep 參數,它指定了服務端發送返回之前需要 sleep 的毫秒數。這將模擬長時間運行的生產環境請求。如果讓請求 sleep 20 分鐘的話,只需要每秒發出 583 個請求就能達到 700k 並發連接的標準。
此外,我們還在 POST 調用中引入了另一個參數: times。伺服器在返回請求時應該在 TCP 連接上寫入響應的指定次數,這有助於模擬更多的數據。
Apache Bench (AB) 的問題雖然使用 AB 也得到了不少測試結果,但同時也遇到了很多問題。我不會在這裡提到所有問題,因為不是這篇文章重點(下面介紹另一個客戶端)。
我們非常滿意從 ab 上獲得的結果,但是它不支持在一段時間內生成所需指定的 TCP 連接數。不知何故,我們設置的 sleep 參數在 ab 上無法生效。
雖然在一台機器上可以運行多個 ab 客戶端並且可以用工具合并結果,但是在多台客戶機上運行此設置對我們來說仍然是一件痛苦的事情。那時我還沒有聽說過 pdsh [4] 這個工具。
此外,我們也沒有關注過超時的問題。在 HAProxy,ab 客戶端和伺服器上有一些默認的超時設置,我們完全忽略了這些。後文會講到。
我們一開始就提到通過臨界點圖來檢測系統的上限,但講了這麼多有點偏離了最主要目標。然而,要得到有意義的結果只能著眼於這一點。
使用 AB 碰到的一個問題是到了某個點 TCP 連接數不再增加。我們有大約 40 - 45 個客戶端運行在 5 - 6 台客戶端機上,但依然不能達到想要的規模。理論上,TCP 連接的數量應該隨著 sleep 時間的增加而增加,但對我們來說並非如此。
引入 Vegeta因此我們需要尋找一個負載測試工具,這些工具需要具有更好的擴展性和更好的功能性,最終,我們找到了 Vegeta [6]。
從我的個人經驗來看,我已經看到 Vegeta 具有極高的擴展性,與 ab 相比,它提供了更好的功能。 在我們的負載測試中,單個 Vegeta 客戶端能夠產生相當於 15 倍 ab 的吞吐量。
下面,我將提供使用 Vegeta 的負載測試結果。
使用 Vegeta 進行負載測試首先,看看我們用來運行一個 Vegeta 客戶端的命令。 進行測試的命令稱為 attack:(酷吧?)
我們太喜歡 Vegeta 提供的參數了,來看看下面的一些參數。
-cpus = 32 指定此客戶機要使用的 CPU 核數。 由於要生成的負載量,我們不得不將客戶機擴展到 32 核 64G。 雖然上面的速度也不是特別高。 但是當有大量處於 sleep 狀態的連接時,維持這些連接也會產生比較大的開銷。
-duration = 10m 我想這是不言自明的。如果沒有指定任何持續時間,測試將永遠運行。
-rate = 2000 每秒請求的數量。
所以如上圖所示,我們在一台 4 核機器上每秒達到了 32k 請求量。 如果你記得臨界點圖,在這種情況下,非 SSL 請求的臨時點是 31.5k。
從負載測試中看更多的結果。
16k 的 SSL 連接也不錯。 請注意,在我們的負載測試過程中,必須從頭開始,因為我們採用了一個新的客戶端,它給了我們比 ab 更好的結果。 所以不得不再來一遍。
CPU 核數的增加導致機器在未達到 CPU 限制前,每秒可以用的請求數增加。
如果將 CPU 核數從 8 個增加到 16 個,我們發現每秒的請求數量並沒有大幅度增加。如果在生產環境中使用 8 核機器,那麼我們不會分配所有的核給 HAProxy,或者是它的任何其他進程。 所以我們決定用 6 核機器進行一些測試,看看是否能得到可接受的數字。
結果還不錯。
引入 sleep我們現在對負載測試結果非常滿意。 然而,這並沒有模擬真正的生產場景。 當我們引入 sleep,才開始模擬生產環境的情況。
echo "POST https://test.haproxy.in:443/ping" | vegeta -cpus=32 attack -duration=10m -header="sleep:1000" -body=post_smaller.txt-rate=2000 -workers=500 | tee reports.bin | vegeta report
因此,x 毫秒的隨機 sleep 時間將導致伺服器 sleep 時間為 0 < x < 1000 。 因此上述負載測試將給出平均 ≥ 500ms 的延遲。
最後一個單元格中的含義是 TCP established, Packets Rec, Packets Sent
從表中可以看到,6 核機器可以支持的最大請求量從 20k 減少到 8k。 顯然,sleep 有其影響,影響的是 TCP 連接的數量。 然而這距離我們設定的 700K 目標還很遠。
里程碑 #1我們如何增加 TCP 連接的數量? 很簡單,不斷增大 sleep 時間,連接數應該上升。 我們一直增加 sleep 時間並在 60 秒的 sleep 時間停了下來。 這意味著大約 30 秒的平均延遲。
Vegeta 可以提供成功請求百分比的結果參數。 我們看到,在上述的 sleep 時間,只有 50% 的調用是成功的。 請看下面的結果。
我們達到了 400 萬個 TCP 連接,在每秒 8k 請求和 60s 的 sleep 時間的情況下。 60000R 的 R 表示隨機。
我們的第一個的發現是,在 Vegeta 中有一個默認的超時時間是 30 秒,這就解釋了為什麼 50% 的請求會失敗。 所以我們在後續測試中將超時調整到 70 秒,並隨著需求的變化而不斷變化。
在客戶端調整超時值之後,我們可以輕鬆地達到 700k 標準。 唯一的問題是這些不可持續,只是峰值的數據。 系統達到了 600k 或 700k 的峰值鏈接,但並沒有堅持很長時間。
但是我們想要得到圖上連接持續很久的效果
這顯示了穩定保持 780k 連接的狀態。如果仔細查看上面的統計信息,每秒的請求數量非常多。然而,在生產環境中,我們在單個 HAProxy 機器上的請求數量要少得多(約 300 個)。
我們確信,如果減少生產環境的 HAProxy 的數量(約 30 個,這意味著每秒 30 * 300?9k 的連接),我們將會達到機器 TCP 連接限制,而不是 CPU。
所以我們決定實現每秒 900 個請求、30MB/s 的網路流量,以及 210 萬 TCP 連接。我們選用這些數字,因為這將是單個生產環境 HAProxy 機器的 3 倍流量。
到目前為止,我們已經配置了 HAProxy 使用 6 核。我們只想測試 3 核,因為這是我們在我們的生產機器上使用的最簡單的方法(如前所述,我們的生產機器是 4 核 30G,所以用 nbproc = 3 進行更改將是最簡單的)。
里程碑 #2
現在我們對每秒請求的最大限制可以隨機器不同而變化,所以我們只剩下一個任務,如上所述,實現 3 倍的生產負載:
每秒 900 個請求
建立了 210 萬個 TCP 鏈接。
30 MB/s 網路。
在 220k 的測試環境下,我們再次陷入僵局。 無論客戶機數量多少或睡眠時間多少,TCP 連接數似乎都停留在那裡。
我們來看一些估算數據。 220k TCP 連接,每秒 900 個請求 = 110,000 / 900?= 120 秒。達到了 110k,因為 220k 連接包括上行和下行。
當我們在 HAProxy 開啟日誌時,我們懷疑 2 分鐘是系統某處的限制。 我們可以看到 120,000 ms 是日誌中大量連接的總時間。
在進一步調查中,我們發現 NodeJs 的默認請求超時為 2 分鐘。 瞧!
但我們的高興顯然很短暫,在 130 萬,HAProxy 連接數突然下降到 0,並再次開始增長。我們很快檢查了 dmesg 命令,裡面可以查到 HAProxy 進程一些有用的內核信息。
基本上,HAProxy 進程已經耗盡內存。因此,我們決定增加機器內存,並將其轉移到 nbproc = 3 的 16 核 64GB 的機器,經過調整,我們終於可以達到 240 萬長連。
後端代碼下面是正在使用的後端伺服器代碼。 我們還在伺服器代碼中使用 statsd 來獲取客戶端接收的每秒請求的統計數據。
我們還有一個小腳本運行多個伺服器。 我們有 8 台機器,每台機器部署了 10 個後端服務。 我們真的認為有條件的話可以進行無限擴容進行壓測。
對於客戶端,每個 IP 有最大 63k TCP 連接的限制。 如果您不確定這個概念,請參閱本系列之前的文章。
所以為了實現 240 萬個連接(雙向,來自客戶機的是 120 萬),我們需要約 20 台機器。 我們在所有機器上運行 Vegeta 命令,甚至找到了一種方法來使用像 csshx [3] 這樣的工具,但仍然需要合并所有的 Vegeta 客戶端的結果。
查看下面的腳本。
Vegeta 提供了名為 pdsh [4] 的工具信息,可讓您在多台計算機上同時運行命令。 此外,Vegeta 可以讓我們將多個結果合并成一個,這就是我們想要的。
HAProxy 配置下面可能是很多讀者最關心的,我們在測試中使用的 HAProxy 配置。 最重要的部分是 nbproc 和 maxconn 參數。 maxconn 設置 HAProxy 允許提供的最大 TCP 連接數(單向)。
對 maxconn 設置的更改導致 HAProxy 進程的 ulimit 增加。 看看下面
最大打開文件已增加到 400 萬,因為 HAProxy 的最大連接數設置為 200 萬。
參閱文章 [5] 獲得更多 HAProxy 優化。


※Java 微服務框架新選擇:Spring 5
※程序員如何提問面試官?針對工程師、技術經理及CTO的提問指南
※Elasticsearch前沿:ES 5.x改進詳解與ES6展望
※如何構建日請求數十億次高性能高可用廣告系統:微博廣告架構解密
※快報|Nginx在Web伺服器市場份額達到33.3%,而Apache則低於50%
TAG:高可用架構 |
※Wegame TOP20單機遊戲好評度85%,高於Steam評分
※全畫幅單機 佳能 EOS 5D Mark IV僅15000元
※下一個百倍潛力:BigOne單機幣之HMC
※從單機到2000萬QPS:知乎Redis平台發展與演進之路
※藉助Docker單機秒開數十萬TCP連接
※Vlog必備索尼ILCE-6400微單,單機身售價6499元
※Apache+Tomcat實現單機多網站部署
※iPhoneXR成蘋果2015年以來最暢銷,單機銷量抵六部
※《GTA5》「戰爭MOD」發布 支持20VS20單機作戰!
※vRealize Automation 7.3 發布Oracle單機版
※AppStore今日推薦 評分4.9國產良心單機手游
※iPhoneX成功運行WIN95 玩單機遊戲很流暢
※SlimTrie:戰勝Btree單機百億文件的極致索引-實現篇
※CSGO steam版已免費開放:單機版免費 想聯機需再花15美元
※嚇死人!華為、OPPO、vivo單機型榮耀費用以10億計算
※亞馬遜推出香檳金版Kindle Oasis單機版本,2658元
※筆記本顏值巔峰,Surface Laptop 2單機評測
※Valve上線《CS:GO》免費版,只支持單機對戰
※2018年最值得一玩的Steam5款單機遊戲
※Bethesda:《輻射76》引擎升級《輻射5》絕對單機!