1. Introduction
1.1 為什麼需要有基準測試
- 快速有效,瞭解系統在給定工作負荷下表現的方法
- 確認系統,是否按照預期工作
- 重現錯誤,輔助解決這些問題
- 模擬更高負載,提前預測效能瓶頸,規劃業務增長
1.2 基準測試 & 真實測試
- 基準測試 + 真實測試 : 只使用基準測試,case簡單很難反映出真實情況。只使用真實測試,情況複雜多變很難總結出確切結論
2. 設計基準測試的策略
2.1 我應該測試什麼 -> 全域性基準測試 & MySQL基準測試
- 什麼時候使用全域性基準測試
- 想要測試一整個應用,連同 Web伺服器+網路+資料庫 的整體表現
- 資料庫並不一定會是效能瓶頸,聯合全域性+資料測試驗證這個結論
- 什麼時候只針對MySQL展開基準測試
- 想要比較不同表,不同查詢語句間的效能差異
- 針對應用中某個具體問題的測試
2.2 選擇測試指標
你必須得抱有一定目的: "這個CPU相比與上一種是不是快一點?" "這個索引好用嗎?"
根據測試指標,分析,解答你一開始的疑惑
- 吞吐量: 單位時間事務處理數量, 一般用TPS作為單位
- 響應時間: 完成某個指定請求消耗的時間,取95%,最好將結果繪圖方便理解
- 併發性: 任意時間,同時發生的併發請求,你可以在Sysbench中指定,比如我要求現在併發64請求,然後測試這種環境下的響應速度等指標
- 原則: 設計出你想了解的更多指標,指定可接受範圍
2.3 資料集從那兒來
- 最好的資料就是來自使用者真實使用的資料,你可以選擇記錄一下高峰時段下一小時的請求記錄,為了完全重現服務的狀態,使用多執行緒安排這些請求
- 如果沒有,或者真實記錄非常少,你需要模擬使用者的行為,但是作假也要做的像一點,比如不要均勻分佈請求,請求門類有熱點非熱點的區別
2.4 記錄下執行時的系統狀態
- 記錄下系統測試時的狀態. 常見的系統指標包含 CPU使用率,磁碟IO,網路流量統計等資料記錄狀態的過程可以由Shell指令碼完成並儲存,最好是先記錄最原始的資料稍後在清洗等。
- 抵消影響因素.
- 保證系統狀態一致: 理論上最好保持系統狀態一致,你甚至需要為此單獨重啟預熱系統
- 記憶體&資料碎片度: 為了保證記憶體的碎片度一致,可能需要每次快速格式化硬碟並分割槽
- 其他:
- 修改基準測試引數: 為了達到最優效果,你可能會面臨引數調整的需求,一次修改儘可能少的引數,使用二分法,從而獲得最優引數
- MySQL的預設引數: MySQL的預設配置原則是儘量消耗少資源,為了獲得效能的最大化,你需要逐步挑選出最適合你業務的引數
- 如果出現了奇怪的資料,不要輕易丟棄: 嘗試分析/復現一下奇怪資料,會有一些新的發現,這可能是你程式碼上或者測試設計的有問題。沒有搞清楚前不要公佈測試結果
2.5 嘗試分析測試結果
- 嘗試使用gnuplot繪圖或者R繪圖的方式,結合記錄下的資料繪圖,髒資料不要丟嘗試分析
3. 基準測試工具
3.1 全域性測試工具
- ab : 基於單個URL展開的壓力測試
- http_load: 多個URL中隨機挑選的壓力測試
- JMeter: 更加複雜,甚至可以設定預熱時間,繪圖等
3.2 MySQL測試工具
- sysbench: 多執行緒壓測工具,它可以根據影響資料庫伺服器效能的各種因素,對系統效能評估,這些因素包含:檔案IO,作業系統排程器,記憶體分配等
4. 使用Sysbench測試計算機效能
4.1 sysbench <全域性引數> --test=<測試型別> <測試引數> <行動>
- 全域性引數
- num-threads 指定執行緒數量
- max-request 測試全過程最多發出多少請求
- max-time 超時設定
- report-interval 每隔多久列印一次測試概況
- mysql-host/port/socket/user/password/db
- 測試型別
- fileio / cpu / memory / threads / mutex / oltp / 指定指令碼
- 行動
- preprare 準備測試所需資料
- run 開始行動
- cleanup 清理測試資料
4.2 fileio 型測試
sysbench --test=fileio <測試型別 - fileio測試>
--file-num=10 <生成10個測試使用的檔案>
--file-total-size=5G <所有檔案的一共5G>
prepare <fileio測試 - 行動:準備檔案>
sysbench --max-time=180 <超時時間180秒>
--max-requests=100000000 <最多10000000請求>
--num-threads=16 <測試使用16執行緒>
--init-rng=on <使用隨機數生成器>
--test=fileio <測試型別 - fileio測試>
--file-total-size=5G <所有檔案的一共5G>
--file-test-mode=rndrw <測試型別 - 隨機寫>
--file-num=10 <生成10個測試使用的檔案>
run <行動型別 - 執行測試>
sysbench --test=fileio <測試型別 - fileio測試>
--file-num=10 <生成10個測試使用的檔案>
--file-total-size=5G <所有檔案的一共5G>
cleanup <行動型別 - 清除測試資料>
複製程式碼
sysbench --test=fileio <測試型別 - fileio測試>
--file-num=10 <生成10個測試使用的檔案>
--file-total-size=5G <所有檔案的一共5G>
prepare <fileio測試 - 行動:準備檔案>
sysbench --max-time=180 <超時時間180秒>
--max-requests=100000000 <最多10000000請求>
--num-threads=16 <測試使用16執行緒>
--init-rng=on <使用隨機數生成器>
--test=fileio <測試型別 - fileio測試>
--file-total-size=5G <所有檔案的一共5G>
--file-test-mode=rndrw <測試型別 - 隨機寫>
--file-num=10 <生成10個測試使用的檔案>
run <行動型別 - 執行測試>
sysbench --test=fileio <測試型別 - fileio測試>
--file-num=10 <生成10個測試使用的檔案>
--file-total-size=5G <所有檔案的一共5G>
cleanup <行動型別 - 清除測試資料>
複製程式碼
4.3 CPU效能測試
sysbench --test=cpu --cpu-max-prime=20000 run <計算2萬以內最大素數>複製程式碼
假設現在針對兩臺電腦直接展開這樣的測試是不公平的,因為這裡執行緒數量被設定成1, 為了能表現出CPU的最大威力,我們應該如下設定執行緒數量
sysbench --test=cpu
--num-threads=`grep "processor" /proc/cpuinfo | wc -l` <使用全部核心>
--cpu-max-prime=20000
run複製程式碼
4.4 記憶體連續讀寫效能測試
sysbench --test=memory <測試記憶體>
--memory-block-size=8K <測試記憶體塊大小為8k>
--memory-total-size=1G <總共資料傳輸大小1G>
--num-threads=16 <執行緒數量16>
run複製程式碼
5. 使用Sysbench 測試資料庫效能
5.1 測試例項
sysbench
--mysql-host=127.0.0.1 <指定資料庫相關引數>
--mysql-port=3166
--mysql-user=root
--mysql-password=123456
--test=oltp <測試型別為資料庫相關測試>
--oltp_tables_count=1 <生成一張表>
--oltp-table-size=1000000 <表裡有這些資料>
--rand-init=on
prepare <行動: 準備對應資料>
sysbench
--mysql-host=127.0.0.1
--mysql-port=3166
--mysql-user=root
--mysql-password=123456
--test=tests/db/oltp.lua
--oltp_tables_count=1
--oltp-table-size=1000000
--num-threads=128
--oltp-read-only=off
--report-interval=10
--rand-type=uniform
--max-time=60
--max-requests=10000000
run# 使用128執行緒測試60秒,每隔10秒傳送一次測試情況報告複製程式碼
5.2 Lua指令碼分析
local stmt_defs = {
point_selects = {
"SELECT c FROM sbtest%u WHERE id=?",
t.INT},
simple_ranges = {
"SELECT c FROM sbtest%u WHERE id BETWEEN ? AND ?",
t.INT, t.INT},
sum_ranges = {
"SELECT SUM(k) FROM sbtest%u WHERE id BETWEEN ? AND ?",
t.INT, t.INT},
order_ranges = {
"SELECT c FROM sbtest%u WHERE id BETWEEN ? AND ? ORDER BY c",
t.INT, t.INT},
distinct_ranges = {
"SELECT DISTINCT c FROM sbtest%u WHERE id BETWEEN ? AND ? ORDER BY c",
t.INT, t.INT},
index_updates = {
"UPDATE sbtest%u SET k=k+1 WHERE id=?",
t.INT},
non_index_updates = {
"UPDATE sbtest%u SET c=? WHERE id=?",
{t.CHAR, 120}, t.INT},
deletes = {
"DELETE FROM sbtest%u WHERE id=?",
t.INT},
inserts = {
"INSERT INTO sbtest%u (id, k, c, pad) VALUES (?, ?, ?, ?)",
t.INT, t.INT, {t.CHAR, 120}, {t.CHAR, 60}},
}複製程式碼
上面是真的開始執行的時候,sysbench會去執行的命令
CREATE TABLE sbtest%d(
id %s,
k INTEGER DEFAULT '0' NOT NULL,
c VARCHAR(500) DEFAULT '' NOT NULL,
pad CHAR(60) DEFAULT '' NOT NULL,
%s (id)
) %s %s]]
複製程式碼
CREATE TABLE sbtest%d(
id %s,
gmt_create datetime not null,
gmt_modified datetime not null,
k INTEGER DEFAULT '0' NOT NULL,
c VARCHAR(500) DEFAULT '' NOT NULL,
pad CHAR(60) DEFAULT '' NOT NULL,
is_used INTEGER DEFAULT '0' NOT NULL,
%s (id)
) %s %s]]複製程式碼
這個則是在prepare階段會去做的事,建立一張這樣的表,你也可以修改成你這樣,然後對應的修改 run的時候所要操作的指令,然後 prepare - run - cleanup 就可以了