1. 程式人生 > >淺談伺服器效能測試的全生命週期——從測試、結果分析到優化策略

淺談伺服器效能測試的全生命週期——從測試、結果分析到優化策略

本文由騰訊WeTest授權釋出
作者:Micheal,騰訊資深後臺開發工程師。
連結:http://wetest.qq.com/lab/view/?id=102
著作權歸作者所有。商業轉載請聯絡WeTest獲得授權,非商業轉載請註明出處。

WeTest導讀

伺服器效能測試是一項非常重要而且必要的工作,本文是作者Micheal在對伺服器進行效能測試的過程中不斷摸索出來的一些實用策略,通過定位問題,分析原因以及解決問題,實現對伺服器進行更有針對性的優化,提升伺服器的效能。

1.伺服器效能測試小結

講到伺服器效能大部分人會想到這個伺服器的架構是什麼樣子的,用的什麼epoll,select,spring,tornado之類的。其實從本質上來看的話目前大部分的伺服器主要包括邏輯層以及DB層,我們採用的各種框架元件處於邏輯伺服器中,如下圖所示。
這裡寫圖片描述

伺服器效能測試是一項比較繁瑣的事情,作為沒有做過效能測試的同學可能需要理清楚以下幾個事情。

1.1. 協議分析

首先是協議分析,效能測試本質上是我們用程式碼來模擬真實的使用者請求,所以我們必須要知道傳送出去的請求內容才能模擬。在典型的CS伺服器中很多使用了protobuf,thrift,tdr(騰訊自研)來序列化以及反序列號請求內容。

序列化之後一方面可以對資料進行壓縮處理,另一方面也避免請求內容明文傳輸造成被抓包·洩漏資料的危險。之前有過伺服器傳輸資料的時候使用的是明文直接傳送,而且這個資料是一些敏感的sql語句,這樣首先暴露了資料庫的表結構,同時不法分子可以通過模擬發包造成“脫褲”甚至是資料被清空。

1.1.1. Protobuf

谷歌出品,必屬精品。Protobuf使用起來很方便,學習成本非常低,而且序列化和反序列號的介面很容易使用。同時它相對於xml以及json,極大的的減小了資料佔用的空間,減少了傳輸成本。目前支援包括C++,java以及python等多個語言。Protobuf目前用的比較多,打解包也很方便,比較推薦使用。

1.1.2. Thrift

Thrift是一個跨語言的輕量級rpc訊息和資料交換框架。Thrift支援幾乎絕大部分主流的語言,包括C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, Smalltalk, and OCaml,雖然大部分我都沒有用過。相對於protobuf,thrift提供了全套RPC解決方案,包括序列化機制、傳輸層、併發處理框架等,也因為如此thrift的學習成本比較高。

1.1.3. 騰訊自研協議tdr

Tdr是騰訊自研跨平臺多語言資料表示元件,主要用於基於資料的序列化反序列化(支援二進位制方式和XML文字方式)以及ORM資料儲存。廣泛用於互娛自研遊戲和部分代理遊戲。在效能上基本和protobuf差不多,主要應用在C++程式中。
在做伺服器效能測試之前,我們需要了解它的協議是怎麼定義的。

1.2. 機器人管理

本質上機器人管理就是一個排程控制器,在獲取需要傳送的請求協議之後,需要有一個框架來管理所有的機器人,控制機器人的啟動,傳送請求以及停止的動作。框架的選擇需要根據伺服器的實際情況來,不同的業務場景,使用不同的框架產生的壓力上限也會不一樣。
這裡寫圖片描述

以一個簡單的多執行緒框架為例,主執行緒負責控制邏輯,管理所有的機器人狀態資訊。子執行緒執行每個機器人的任務,包括連線伺服器,傳送資料,接收資料,斷開連線等。

1.3. 結果統計

機器人傳送請求包之後,一般是要等待伺服器的響應回包。伺服器那邊可以計算本次壓測過程中各項業務資料,包括TPS,總的收發包量等。

不可能在測試過程中一直盯著各個資料看,我們需要把每項資料記錄下來,後續綜合各項結果進行分析。
這裡的結果統計除了需要統計每個機器人收到回包的結果,還需要統計伺服器在壓測過程中的各項效能資料變化。一旦客戶端的壓力上到一定值時,伺服器某項資源支撐不了的話,說明這個資源可能存在短板,存在可以優化的空間。

2. 效能結果分析

效能結果分析是一個比較複雜的過程。需要綜合硬體、作業系統、應用程式等多方面來定位。

2.1. 硬體的影響

硬體對伺服器效能影響還是蠻大的,如果是土豪的話,可以直接買最好的。我們分析硬體主要是希望選擇合適的配置,節約資源,避免出現高射炮打蚊子的情況。

2.1.1. CPU

在資金的充足下,一般來說CPU的數量越多,主頻越高,那麼伺服器的效能也就會越好。在實際測試過程中,如果在大壓力下持續觀察CPU的使用率很低,那麼CPU的資源基本上是可以滿足伺服器要求的。這樣的情況其實是有點浪費CPU資源的,比較理想的情況是壓力不大的時候CPU利用率比較低,壓力上來之後CPU利用率保持在60%-70%。
大部分的CPU在同一時間內只能執行一個執行緒,但是超執行緒的處理器可以在同一個時間執行多個執行緒,我們可以利用處理前超執行緒特性提高系統性能。雖然採用超執行緒技術能同時執行兩個執行緒,但它並不象兩個真正的CPU那樣,每個CPU都具有獨立的資源。當兩個執行緒都同時需要某一個資源時,其中一個要暫時停止,並讓出資源,直到這些資源閒置後才能繼續。因此超執行緒的效能並不等於兩顆CPU的效能。

2.1.2. 記憶體

記憶體的大小也是影響伺服器效能的一個重要因素。記憶體太小,系統程序要被阻塞,應用程式會變得緩慢,甚至是失去響應;如果太大的話,也是造成一種浪費。Linux系統中採用實體記憶體和虛擬記憶體兩種方式,使用虛擬記憶體可以緩解實體記憶體的不足,但是如果佔用過多的虛擬記憶體的話,應用程式的效能會明顯的下降。

2.1.3. 網路頻寬

網路頻寬的大小限制了客戶端與伺服器互動的流量,相對其他硬體資源,網路頻寬在價格上更貴。這需要我們合理預估伺服器的可伺服器能力,需要佔用的頻寬資源。

2.1.4. 磁碟IO

目前磁碟都是機械方式運作的,主要體現在磁碟讀寫前尋找磁軌的過程。磁碟自帶的讀寫快取大小,對於磁碟讀寫速度至關重要。讀寫速度快的磁碟,通常都帶有較大的讀寫快取。磁碟的尋道過程是機械方式,決定了其隨機讀寫速度將明顯低於順序讀寫。在我們做系統設計和實現時,需要考慮到磁碟的這一特性。

2.2. 作業系統及軟體

2.2.1. 版本

不同的作業系統在核心實現上可能各不相同,因而對執行在上面的應用程式來說可能影響比較大。
筆者並沒有做過分析不同作業系統對伺服器效能的影響,因為只用過Linux開發伺服器程式。Linux作業系統在這十幾年發展的異常迅猛,目前大部分的伺服器都是執行在Linux作業系統上的。Linux目前具有最好的生態系統,伺服器端的各種軟體都為它而設計,預設都認為你是在 Linux 上跑,你要是整一個非 Linux 的伺服器,你得有足夠的心理準備,因為出現任何問題,你可能未必能找到能幫你解決問題的人。

2.2.2. 引數配置

先說一個小故事。福特公司一套重要裝置出現故障,找了很多人來維修,結果都沒有維修好,沒辦法了,就在購買裝置的英國公司高價聘請一位工程師過來維修,工程師來到之後,反覆查詢原因,最後在一個小零件上劃了一條線,然後對旁邊福特公司的人說,在劃線的地方切掉就好了,果不其然,切掉之後故障真的解除了,按照合約,福特公司應支付公司一萬美元,周圍的人都唏噓不已,感嘆一條線就可以價值一萬美元,工程師回答到:那條線只值一美元,而怎樣找到那條線值9999美元。
我們在測試伺服器的過程中,經常會遇到效能上不去。檢視CPU,網路,IO消耗都挺低的,就是定位不到問題的原因。有經驗的程式設計師可能會告訴你你把某個引數修改一下,立馬效能噌噌噌上去了。比如mysql相關設定,系統檔案描述符,緩衝區大小,time_wait快速回收設定等,甚至是執行緒池配置的執行緒個數也會對伺服器的效能產生較大的影響。
關於資料庫引數的設定,比如mysql的配置檔案my.cnf檔案中,修改不同的配置(比如innodb_flush_log_at_trx_commit 設定為0,1還是2 )可能會對資料庫的讀寫效能影響很大。

2.2.3. 應用程式本身實現

比如程式中需要頻繁申請記憶體,使用bzero和memset對伺服器效能影響差距可能會很大。
另外程式中的一些查詢操作,採用不同的資料結構,可以實現時間和空間上的相互轉化,從而影響伺服器的效能。

3. Linux下的資料監控工具

3.1. Vmstat

Vmstat,virtual memmory statistics(虛擬記憶體統計),主要是對作業系統的記憶體資訊、程序狀態、cpu活動等進行監視,但是它不能對某個程序進行深入的分析。
這裡寫圖片描述

Procs中r列表示執行和等待CPU時間片的程序數,如果r值長期大於CPU個數,說明CPU資源不夠用啦,可以適當增加CPU數量。
Procs中b列表示當前等待資源的程序數,包括等待I/O,記憶體等。
Swpd列表示切換到記憶體交換區的KB數,一般si,so為0的話基本不影響系統的效能。
Cache是page cache的記憶體數量,Linux會把空閒的實體記憶體的一部分拿來做檔案和目錄的快取,以便提高程式執行的效能。如果cache的值較大的話,說明快取了太多的檔案,如果bi值小的話,說明檔案系統效率比較高。
Si是每秒從磁碟讀入虛擬記憶體的大小,如果這個值一直大於0,表示實體記憶體不夠用或者記憶體洩露了,需要查詢耗記憶體程序解決掉。
Bi,bo是表示從塊裝置讀入資料的總量以及寫到塊裝置的資料總量。如果bi+bo值比較大,而且wa值也比較大的話,說明系統磁碟I/O可能有問題,效能不高。
In和cs是每秒鐘的裝置中斷數以及上下文切換數。它們很大的話,表面核心消耗的CPU時間較多。

3.2. Top

Top是一個動態顯示過程,即可以通過使用者按鍵來不斷重新整理當前狀態。它可以按照系統中當前程序的CPU利用率以及佔用的記憶體大小進行排序,可以比較快速定位出系統響應遲鈍的原因。如果在前臺執行該命令,它將獨佔前臺,直到使用者終止該程式為止。
這裡寫圖片描述

top是一個顯示資料較多的工具,第一行顯示的是系統的開機執行時間,機器的CPU負載資訊;第二行顯示當前系統任務的總數,以及各個狀態的程序數;第三行顯示的是CPU資源的使用情況總覽;第四行顯示記憶體的使用情況總覽;第五行顯示的是記憶體交換區的使用情況總覽;後面開始是每個程序對資源使用的情況。

3.3. Nmon

Nmon提供對CPU、記憶體、網路、磁碟等系統資源佔用情況分析,相比其他Linux命令獲取到的資料,nmon的功能更為集中、配置性更強。通過nmon採集到資料之後可以在windows系統中使用nmon_analyser做資料的展示以及分析工作,視覺化效果比較好。

由於一般Linux系統都不自帶nmon,使用之前需要下載安裝。

3.4. Uptime

Uptime命令顯示系統已經運行了多長時間,它依次顯示當前時間、系統已經運行了多長時間、目前有多少登陸使用者、系統在過去的1分鐘、5分鐘和15分鐘內的平均負載。

關於系統平均負載,它表示在特定時間間隔內執行佇列中的平均程序數。如果一個程序滿足以下條件則其就會位於執行佇列中:沒有在等待I/O操作的結果;沒有主動進入等待狀態;沒有被停止。

3.5. Netstat

Netstat命令可以顯示本機的網路連線情況,監聽埠以及路由表等各種網路相關資訊。Netstat用於顯示與IP、TCP、UDP和ICMP協議相關的統計資料,一般用於檢驗本機各埠的網路連線情況。

比較常用的可以用次命令檢視當前開啟監聽的伺服器程序資訊以及埠資訊。
這裡寫圖片描述

3.6. Free

Free是監控Linux使用情況最常用的命令。
這裡寫圖片描述
“Free -m”可以檢視以M為單位的使用情況,這裡主要觀察free和cached兩列。
一般來說,如果應用程式可用記憶體/系統實體記憶體>70%時,表明目前系統記憶體資源比較充足,不影響系統性能;如果應用程式可用記憶體/系統實體記憶體<20%時,表明目前系統記憶體資源比較緊缺,需要釋放其他程式記憶體或者增加記憶體;如果應用程式可用記憶體/系統實體記憶體在20%-70%之間,表明目前系統的記憶體資源基本滿足應用需求,暫時不影響系統的效能。

3.7. Sar

Sar也是一個強大的分析系統性能的工具,它可以比較全面的獲取系統的CPU,執行佇列,磁碟IO,分頁,記憶體,CPU中斷,網路等多項資料。
這裡寫圖片描述

上圖是使用sar獲取系統CPU的整體負責情況,每隔1秒統計一次,統計3次,最後會給出3次的平均值。需要檢視其他的資料可以檢視手冊使用。

3.8. Iostat

Iostat是I/O statistics的縮寫,主要功能是對系統的磁碟I/O操作進行監控。它的輸出主要顯示磁碟讀寫操作的統計資訊,同時也會給出CPU的使用情況。
這裡寫圖片描述

這裡顯示的是檢視CPU和磁碟的資訊,統計間隔2秒,共3次。

3.9. Valgrind

Valgrind是一款廣泛用於監控程式執行過程進行記憶體除錯、記憶體洩漏檢測以及效能分析的工具。它會給出記憶體洩漏的統計,包括definitely lost,indirectly lost,possibly lost,still reachable ,suppressed等,我們可以使用valgrind來測試程式中記憶體不規範使用的部分。同時對於地址越界問題也可以通過valgrind掃出來,它會統計invalid write的情況。

4. 伺服器的效能優化

在優化之前,先要搞清楚伺服器的具體業務需求是什麼,據此來優化其中的短板。

4.1. 儲存的優化

IO相對來說比較耗時,我們都知道越靠近CPU的儲存,其訪問速度越快,但是其價格越貴。下圖來展示了不同儲存的容量以及訪問時間。

目前很多同學在優化伺服器效能的時候都會從儲存這方面入手。
這裡寫圖片描述

儲存的容量以及訪問時間

4.1.1. 用記憶體換時間

4.1.1.1. 增加快取

很多web應用是有大量的靜態內容,這些靜態內容主要都是一些小檔案,並且會被頻繁的讀,採用Apache以及nginx作為web伺服器。在web訪問量不大的時候,這兩個http伺服器可以說是非常的迅速和高效,如果負載量很大的時候,我們可以採用在前端搭建cache伺服器,將伺服器中的靜態資原始檔快取到作業系統記憶體中直接進行讀操作,因為直接從記憶體讀取資料的速度要遠大於從硬碟讀取。這個其實也是增加記憶體的成本來降低訪問磁碟帶來的時間消耗。

4.1.1.2. 記憶體資料庫

記憶體資料庫,其實就是將資料放在記憶體中直接操作的資料庫。相對於磁碟,記憶體的資料讀寫速度要高出幾個數量級,將資料儲存在記憶體中相比從磁碟上訪問能夠極大地提高應用的效能。記憶體資料庫拋棄了磁碟資料管理的傳統方式,基於全部資料都在記憶體中重新設計了體系結構,並且在資料快取、快速演算法、並行操作方面也進行了相應的改進,所以資料處理速度比傳統資料庫的資料處理速度要快很多。
但是安全性的問題可以說是記憶體資料庫最大的硬傷。因為記憶體本身有掉電丟失的天然缺陷,因此我們在使用記憶體資料庫的時候,通常需要,提前對記憶體上的資料採取一些保護機制,比如備份,記錄日誌,熱備或叢集,與磁碟資料庫同步等方式。
對於一些重要性不高但是又想要快速響應使用者請求的部分資料可以考慮記憶體資料庫來儲存,同時可以定期把資料固化到磁碟。

4.1.1.3. RDD

這裡圖個新鮮,說說記憶體換時間在大資料雲端計算相關領域的一些應用。Spark最近很火,它的核心要數RDD了,RDD最早來源與Berkeley實驗室的一篇論文《Resilient Distributed Datasets: A Fault-Tolerant Abstraction for In-Memory Cluster Computing》。現有的資料流系統對兩種應用的處理並不高效:一是迭代式演算法,這在圖應用和機器學習領域很常見;二是互動式資料探勘工具。這兩種情況下,將資料儲存在記憶體中能夠極大地提高效能。這裡不詳細說RDD了,只是想說程式設計師一直是覬覦記憶體的讀取速度的。

4.1.2. 使用SSD等

除了對記憶體方面的優化,還可以對磁碟這邊進行優化。跟傳統機械硬碟相比,固態硬碟具有快速讀寫、質量輕、能耗低以及體積小等特點。但是ssd的價格相比傳統機械硬碟要貴,有條件的可以使用ssd來代替機械硬碟。

4.2. 資料庫優化

大部分的伺服器請求最終都是要落到資料庫中,隨著資料量的增加,資料庫的訪問速度也會越來越慢。想要提升請求處理速度,必須要對原來的單表進行動刀了。目前主流的Linux伺服器使用的資料庫要屬mysql了,如果我們使用mysql儲存的資料單個表的記錄達到千萬級別的話,查詢速度會很慢的。
根據業務上合適的規則對資料庫進行分割槽分表,可以有效提高資料庫的訪問速度,提升伺服器的整體效能。
另外對於業務上查詢請求,在建表的時候可以根據相關需求設定索引等,以提高查詢速度。

4.3. 利用多核優勢

現在執行伺服器的主流機器配置都是多核CPU的,我們在設計伺服器的時候可以利用多核心的特點,採用多程序或者多執行緒的框架。

關於選擇多執行緒還是多程序可以根據實際的需求,結合各自的優缺點進行選擇。
對於多執行緒的使用,特別是使用執行緒池的時候可以通過測試不同執行緒池伺服器的效能來設定合適的執行緒池。

4.4. 選擇合適的IO模型

《UNIX網路程式設計卷1:套接字聯網API》中有一幅圖比較經典。
這裡寫圖片描述

IO模型

阻塞I/O模型:資料沒到達之前,I/O一直阻塞,如果資料到達,則會返回。典型的是recvfrom,一般的預設都是阻塞的。
非阻塞的I/O模型:和阻塞相反,只要不能得到結果的時候,I/O立刻返回。不會阻塞當前執行緒。
IO複用模型:也就是自己要學習的部分。多路複用的意思是,將多路訊號合併到一路上進行處理,類似多個管道彙集到一個管道,與之相反的是多路分解。
IO複用模型主要是select,poll,epoll;對一個IO埠,兩次呼叫,兩次返回,比阻塞IO並沒有什麼優越性;關鍵是能實現同時對多個IO埠進行監聽;函式也會使程序阻塞,但是和阻塞I/O所不同的的,這兩個函式可以同時阻塞多個I/O操作。而且可以同時對多個讀操作,多個寫操作的I/O函式進行檢測,直到有資料可讀或可寫時,才真正呼叫I/O操作函式。
訊號驅動:首先開啟套介面訊號驅動I/O功能,並通過系統呼叫sigaction安裝一個訊號處理函式。當資料報準備好被讀時,就為該程序生成一個SIGIO訊號。隨即可以在訊號處理程式中呼叫recvfrom來讀資料報,井通知主迴圈資料已準備好被處理中。也可以通知主迴圈,讓它來讀資料報。
非同步的IO模型:告知核心啟動某個操作,並讓核心在整個操作完成後(包括將資料從核心拷貝到使用者自己的緩衝區)通知我們。
這裡並不是說一定要用某個模型,epoll也並不是在所有情況下都比select效能要好的,在選擇的時候還是要結合業務需求來。

4.5. 分散式部署程式

當單機伺服器已經找不到合適的優化點時,我們可以通過分散式部署來提高伺服器的響應能力。優秀的伺服器開發都會為自己的伺服器的擴容,容災提出一些解決方案。個人覺得伺服器設計的時候簡單點比較好,這樣後期擴容的時候會很方便。

總結

伺服器效能測試是一項比較繁瑣的事情,作為沒有做過效能測試的同學需要事先了解伺服器的協議是如何定義的,建立框架管理機器人、統計測試中機器人收到回包的結果以及壓測過程中各項效能資料的變化。在完成了測試的過程後,可以從硬體、作業系統以及應用程式等多個方面進行對效能結果進行定位。最後在明確業務需求的前提下,通過儲存優化、資料庫優化以及分散式部署程式等手段完成伺服器的效能優化。

本文由騰訊WeTest授權釋出
作者:Micheal,騰訊資深後臺開發工程師。
連結:http://wetest.qq.com/lab/view/?id=102
著作權歸作者所有。商業轉載請聯絡WeTest獲得授權,非商業轉載請註明出處。