1. 程式人生 > >如何生成每秒百萬級別的 HTTP 請求?

如何生成每秒百萬級別的 HTTP 請求?

本文是構建能夠每秒處理 3 百萬請求的高效能 Web 集群系列文章的第一篇。它記錄了我使用負載生成器工具的一些經歷,希望它能幫助每一個像我一樣不得不使用這些工具的人節省時間。

負載生成器是一些生成用於測試的流量的程式。它們可以向你展示伺服器在高負載的情況下的效能,以及讓你能夠找出伺服器可能存在的問題。通過負載測試瞭解伺服器的缺點,是測試伺服器彈性以及未雨綢繆的好方法。

負載生成工具(Load-Generating Tools)

在進行負責測試時要牢記一件重要的事:你能在 Linux 上建立多少個 socket 連線。這個限制是硬編碼在核心裡的,最典型的就是臨時 W 埠的限制。(在某種程度上)你可以在 /etc/sysctl.conf 裡擴充套件它。但是基本上,一臺 Linux 機器只能同時開啟大約 64,000 個 socket 。因此在負載測試時,我們不得不通過在單一的連線上儘可能多地發出請求來充分利用 socket 。 除此之外,我們還需要不止一臺的機器來產生負載。否則,負載生成器會把可用的 socket 佔用導致不能產生足夠的負載。

我一開始用的是‘ab’,Apache Bench 。它是我所知道的 http 基準測試工具中最簡單、最通用的。並且它是 Apache 附帶的產品,因此它可能已經存在於你的系統中。不幸的是,我在使用它的時候每秒大約只能生成 900 個請求。雖然我見過其他人使用它每秒能達到 2,000 個請求,但我可以立即告訴你,‘ab’並不適合我們的基準測試。

Httperf

接著,我嘗試了 ‘httperf’。這個工具更強大,但是它依然相對簡單並且功能有限。要算出每秒生產了多少個請求並不是僅傳遞引數那麼簡單。經過我的多次嘗試,獲取了每秒超過幾百請求的結果。例如:

它以每秒 1,000 個的速率建立了 100,000 個會話(session)。每次會話發起 5 次請求,時間間隔為 2 秒。

Shell
1 httperf--hog--server=192.168.122.10--wsess=100000,5,2--rate1000--timeout5
Shell
1234567891011121314151617 Total:connections117557requests219121replies116697test-duration111.423sConnection rate:1055.0conn/s(0.9ms/conn,<=1022concurrent connections)Connection time[ms]:min0.3avg865.9max7912.5median459.5stddev993.1Connection time[ms]:connect31.1Connection length[replies/conn]:1.000Request rate:1966.6req/s(0.5ms/req)Request size[B]:91.0Reply rate[replies/s]:min59.4avg1060.3max1639.7stddev475.2(22samples)Reply time[ms]:response56.3transfer0.0Reply size[B]:header267.0content18.0footer0.0(total285.0)Reply status:1xx=02xx=1166973xx=04xx=05xx=0CPU time[s]:user9.68system101.72(user8.7%system91.3%total100.0%)NetI/O:467.5KB/s(3.8*10^6bps)

最終,我使用這些設定達到了每秒 6,622 個連線:

Shell
1 httperf--hog--server192.168.122.10--num-conn100000--ra20000--timeout5

(總共建立了 100,000 個連線,並且以每秒 20,000 個連線的固定速率建立)

它還有一些潛在的優勢,並且擁有比‘ab‘更多的特性。但它不是我要用在這個專案裡的重量級工具。我需要的是能夠支援分散式多負載測試節點的工具。因此,我的下一個嘗試是:Jmeter。

Apache Jmeter

這是一個功能齊全的 web 應用測試套件,它可以模擬真實使用者的所有行為。你可以使用 Jmeter 的代理去訪問你的網站,進行點選、登陸、模仿使用者可以做的所有行為。Jemeter 會把這些行為記錄下來作為測試用例。然後 Jmeter 會反覆執行這些動作來模擬你想要的使用者數量。儘管配置 Jmeter 比 ‘ab‘ 和 ’httperf‘ 複雜得多,但它是一個很有趣的工具!

根據我的測試,它每秒可以產生 14,000 個請求!這絕對是一個好的進展。

我使用了 Googlle Code project 上的一些外掛,並且使用它們的“Stepping Threads”和“HTTP RAW”請求,最終每秒大約可以產生 30,000 個請求!但這已經達到極限了,所以還要尋找另一個工具。這裡有一個我之前的 Jmeter 配置,希望可以幫助到其他人。雖然這個配置離完美相差甚遠,但有時它可以滿足你的要求。

Tsung: 重型的(heavy-duty)、分散式的、多協議測試工具

它每秒基本可以產生 40,000 個請求,這絕對是我們想要的工具。類似於 Jmeter,你可以把一些行為記錄下來在測試時執行,並且可以測試大多數的協議。比如 SSL、HHTP、WebDAV、SOAP、PostgreSQL、MySQL、LDAP 和 Jabber/XMPP。與 Jmeter 不同的是,它沒有讓人感到迷茫的 GUI 設定,它僅有一個 XML 配置檔案,和一些你選擇的分散式節點的 SSH 金鑰。它的簡潔和效率對我的吸引力,完全不亞於它的健壯性和可擴充套件性。我發現它是一個很強大的工具,在正確的配置下它可以每秒產生百萬級的 HTTP 請求。

除此之外,Tsung 還可以在 html 上產生圖表以及輸入你的測試的詳細報告。測試的結果通俗易懂,並且你甚至可以把這些圖片展示給你的 boss 看!

在這個系列文章的剩餘部分,我還會講解這個工具。現在你可以繼續瀏覽下面的配置說明,或者直接跳到下一頁。

在 CentOS 6.2 上安裝 Tsung

首先,你要安裝(Erlang 需要的) EPEL 源。因此,在進行下一步之前要把它安裝好。安裝完後,繼續安裝你用來產生負載的每個節點需要的包。如果你還沒有在節點之間建立無密碼 SSH 金鑰(passwordless SSH key),那麼請建立之。

Shell
1 yum-yinstall erlang perl perl-RRD-Simple.noarchperl-Log-Log4perl-RRDs.noarchgnuplot perl-Template-Toolkit firefox

從 Github 或者 Tsung 的官網上下載最新的 Tsung。

Shell
1 wget http://tsung.erlang-projects.org/dist/tsung-1.4.2.tar.gz

解壓並且編譯。

Shell
123 tar zxfv  tsung-1.4.2.tar.gzcdtsung-1.4.2./configure&&make&&makeinstall

把示例配置複製到 ~/.tsung 目錄裡。這是 Tsung 的配置檔案和日誌檔案的存放地方。

Shell
1 cp/usr/share/doc/tsung/examples/http_simple.xml/root/.tsung/tsung.xml

你可以根據你的需求去編輯這個配置檔案,或者使用我的配置檔案。經過大量的嘗試以及失敗後,我目前的配置檔案在使用 7 個分散式節點時可以每秒產生 5 百萬個 HTTP 請求。

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758 &lt;?xml version=&quot;1.0&quot;?&gt;&lt;!DOCTYPE tsung SYSTEM&quot;/usr/share/tsung/tsung-1.0.dtd&quot;&gt;&lt;tsung loglevel=&quot;notice&quot;version=&quot;1.0&quot;&gt;&lt;clients&gt;&lt;client host=&quot;localhost&quot;weight=&quot;1&quot;cpu=&quot;10&quot;maxusers=&quot;40000&quot;&gt;&lt;ip value=&quot;192.168.122.2&quot;/&gt;&lt;/client&gt;&lt;client host=&quot;loadnode1&quot;weight=&quot;1&quot;cpu=&quot;9&quot;maxusers=&quot;40000&quot;&gt;&lt;ip value=&quot;192.168.122.2&quot;/&gt;&lt;/client&gt;&lt;client host=&quot;loadnode2&quot;weight=&quot;1&quot;maxusers=&quot;40000&quot;cpu=&quot;8&quot;&gt;&lt;ip value=&quot;192.168.122.3&quot;/&gt;&lt;/client&gt;&lt;client host=&quot;loadnode3&quot;weight=&quot;1&quot;maxusers=&quot;40000&quot;cpu=&quot;9&quot;&gt;&lt;ip value=&quot;192.168.122.21&quot;/&gt;&lt;/client&gt;&lt;client host=&quot;loadnode4&quot;weight=&quot;1&quot;maxusers=&quot;40000&quot;cpu=&quot;9&quot;&gt;&lt;ip value=&quot;192.168.122.11&quot;/&gt;&lt;/client&gt;&lt;client host=&quot;loadnode5&quot;weight=&quot;1&quot;maxusers=&quot;40000&quot;cpu=&quot;9&quot;&gt;&lt;ip value=&quot;192.168.122.12&quot;/&gt;&lt;/client&gt;&lt;client host=&quot;loadnode6&quot;weight=&quot;1&quot;maxusers=&quot;40000&quot;cpu=&quot;9&quot;&gt;&lt;ip value=&quot;192.168.122.13&quot;/&gt;&lt;/client&gt;&lt;client host=&quot;loadnode7&quot;weight=&quot;1&quot;maxusers=&quot;40000&quot;cpu=&quot;9&quot;&gt;&lt;ip value=&quot;192.168.122.14&quot;/&gt;&lt;/client&gt;&lt;/clients&gt;&lt;servers&gt;&lt;server host=&quot;192.168.122.10&quot;port=&quot;80&quot;type=&quot;tcp&quot;/&gt;&lt;/servers&gt;&lt;load&gt;&lt;arrivalphase phase=&quot;1&quot;