Sysbench使用總結
實踐環境
CentOS 7.8
Sysbench 1.0.20
下載地址:https://github.com/akopytov/sysbench/archive/refs/tags/1.0.20.tar.gz
用法介紹
sysbench [options]... [testname] [command]
具體說明:
-
testname
可選的內置測試類型名稱、或者是和工具捆綁的
lua
腳本名稱(不帶后綴.lua
),形如oltp_read_only
,或者是指定lua
腳本的路徑,形如sysbench-1.0.20/tests/include/oltp_legacy/oltp.lua
,可選內置測試名稱如下:fileio
文件I/O測試cpu
CPU性能測試memory
內存測試threads
POSIX線程性能測試mutex
執行Mutext
性能測試(調度程序性能測試)說明:當
testname
指定為lua
腳本名稱時,實際執行時,會到sysbench_installation_home/share/sysbench
目錄下查找對應名稱的腳本,找到后再執行腳本。可通過
sysbench <testname> help
查看每種測試支持的選項問題:如果
testname
為lua
腳本名稱、lua
腳本路徑時,咋知道該腳本支持的選項有哪些,選項參數默認值為多少呢?解答:這個就要看
testname
對應腳本引用的common.lua
腳本文件,該文件中定義的set_vars
函數定義了命令支持的選項,以及對應的默認值,具體參見下文。然后,分析待執行的腳本中用到了哪些選項。 -
command
命令會被傳遞給內置測試名稱或者由testname
指定的腳本,其定義了測試必須執行的動作。可用命令列表取決於特定的測試,有些測試也實現了自己的命令。以下為典型的測試命令的描述:-
prepare
測試前的准備操作,比如為fileio
測試創建必要的文件,或者為數據庫測試基線填充測試數據庫。 -
run
運行由testname參數指定的測試。所有測試都支持該命令。 -
cleanup
測試運行完成后,移除測試創建的臨時數據,比如刪除創建的表 -
help
顯示testname
使用幫助
-
-
options
可選項,常見選項許下常用一般命令行選項
--threads
需要創建的worker線程數量 默認值 1--events=N
設置期望執行的事件總數。0表示不限制 默認值 0--time=N
設置總執行時間,單位秒。0表示不限制。 默認值 10--forced-shutdown=STRING
超過--time
限制后,關閉程序之前需要等待的秒數,如果設置為off則表示不啟用。 默認值 off--rate=N
平均事務速率。 0表示不限制。默認值 0
--report-interval=N
設置定期報告中間統計的時間間隔為N,單位為秒 。 0表示不設置。默認值 0注意:
- 如果運行程序命令時,如果當前總執行時間已經達到
--time
選項參數值(默認10秒),不管當前已執行事件總數是否達到--events
選項參數值,都會停止運行程序,所以如果需要為程序命令顯示指定--events
選項時,需要合理的設置--time
選項參數值。 - 如果運行程序命令時,如果當前已執行事件總數已達到
--events
選項參數值,不管當前總執行時間是否達到--time
選項參數值,都會停止測試
常用日志選項
--verbosity=N
日志詳細級別 {5 - debug, 0 - 僅critical messages} 默認值 3--percentile=N
延時統計(latency statistics)中,需要計算的百分比 (1-100)。設置為0表示禁用百分比值計算。 Use the special常用數據庫選項
--db-driver=STRING
設置程序使用的數據庫驅動。默認值 mysql常用mysql 選項:
--mysql-host=host
mysql服務主機地址 默認localhost
--mysql-port=3306
mysql服務端口 默認值 3306
--mysql-user=STRING
mysql用戶名稱 默認值 sbtest
--mysql-password=STRING
mysql密碼,默認值 []
--mysql-db=STRING
mysql數據庫名稱 默認 sbtest - 如果運行程序命令時,如果當前總執行時間已經達到
應用實踐
mysql數據庫性能基准測試
創建數據庫
CREATE DATABASE `sbtest` DEFAULT CHARACTER SET utf8;
注意:如果不事先創建數據庫,則運行一下測試腳本時,會報錯:FATAL: error 1049: Unknown database 'sbtest'
插入數據測試
運行壓測准備命令
# sysbench --oltp-tables-count=5 --oltp_table_size=0 --mysql-host=10.118.80.88 --mysql-user=testacc --mysql-password=test1234 sysbench-1.0.20/tests/include/oltp_legacy/insert.lua prepare
說明:
1、執行以上命令后,會自動創建5張空表
2、sysbench-1.0.20/tests/include/oltp_legacy/insert.lua
是sysbench
工具壓縮包中自帶腳本,下文所用到的腳本皆非自定義腳本,不再贅述
運行插入數據測試
# sysbench --threads=80 --time=600 --events=50000000 --oltp-tables-count=5 --oltp_table_size=10000000 --mysql-host=10.118.80.88 --mysql-user=testacc --mysql-password=test1234 sysbench-1.0.20/tests/include/oltp_legacy/insert.lua run > result.txt
查看運行結果
略
混合操作測試
# sysbench --threads=300 --time=1200 --oltp-tables-count=5 --oltp_table_size=10000000 mysql-host=10.118.80.88 --mysql-user=testacc --mysql-password=test1234 sysbench-1.0.20/tests/include/oltp_legacy/oltp.lua run > result.txt
運行清理命令
# sysbench --oltp-tables-count=5 --mysql-host=10.118.80.88 --mysql-user=testacc --mysql-password=test1234 sysbench-1.0.20/tests/include/oltp_legacy/insert.lua cleanup
注意:執行prepare
和cleanup
命令時的--oltp-tables-count
選項參數值要保持一致
lua
腳本分析
sysbench-1.0.20/tests/include/oltp_legacy/oltp.lua
具體分析參見中文注釋
pathtest = string.match(test, "(.*/)") # 首先,正則匹配當前測試名稱(sysbench命令行提供的testname)
if pathtest then # 如果測試名稱正則匹配 .*/
# 說明測試名稱為腳本,形如sysbench-1.0.20/tests/include/oltp_legacy/oltp.lua,因為測試腳本和common.lua位於同一層級目錄,所以,拼接腳本所在目錄路徑和"common.lua"得到common.lua文件路徑,然后,加載文件
dofile(pathtest .. "common.lua")
else # 否則,加載工具捆綁的common腳本,即sysbench_installation_home/share/sysbench/common.lua
require("common")
end
function thread_init() # 線程初始化函數定義
set_vars() # 調用common中的set_vars函數設置變量
# 如果數據庫驅動為mysql、attachsql,並且mysql表引擎為myisam
if (((db_driver == "mysql") or (db_driver == "attachsql")) and mysql_table_engine == "myisam") then
# 則走下述邏輯
local i
local tables = {}
# 根據命令行oltp_tables_count參數值,初始化tables數組元素為表名,格式形如sbtestN WRITE,其中N從1開始,最大值等於oltp_tables_count,即表數量
for i=1, oltp_tables_count do
tables[i] = string.format("sbtest%i WRITE", i)
end
begin_query = "LOCK TABLES " .. table.concat(tables, " ,")
commit_query = "UNLOCK TABLES"
else # 否則定義事務起始查詢語句為 begin_query為BEGIN,結束查詢語句為 COMMIT
begin_query = "BEGIN"
commit_query = "COMMIT"
end
end
# 定義函數 用於獲取查詢條件
function get_range_str()
local start = sb_rand(1, oltp_table_size) # 隨機獲取 [1, 單表記錄總數] 范圍內的整數,作為范圍查詢條件起始值
return string.format(" WHERE id BETWEEN %u AND %u",
start, start + oltp_range_size - 1) # 返回查詢條件WHERE id BETWEEN start AND (start + 99) (oltp_range_size默認為100
end
定義待執行的“事件”函數
function event()
local rs # 查詢返回結果
local i
local table_name
# 以下變量用於存放字段值和查詢
local c_val
local pad_val
local query
table_name = "sbtest".. sb_rand_uniform(1, oltp_tables_count) # 隨機獲取表名,格式形如 sbtestN,其中N為從[1,表數量]范圍內的隨機整數
if not oltp_skip_trx then # 如果不跳過事務,
db_query(begin_query) # 則執行do_query(oltp_skip_trx默認為false,所以這里會執行do_query),即標記事務開始
end
if not oltp_write_only then # 如果not oltp_write_only為真(oltp_write_only默認為false)
# 則執行以下for循環(oltp_point_selects默認為10次,所以,會執行10次for循環查詢,查詢語句為:
# SELECT c FROM table_name WHERE id=id_value
# 說明:
# table_name 上述獲取的隨機表名,下同,不再贅述
# c 非索引列
# id 主鍵列
# id_value 目標id值,隨機獲取已存在記錄ID
for i=1, oltp_point_selects do
rs = db_query("SELECT c FROM ".. table_name .." WHERE id=" ..
sb_rand(1, oltp_table_size))
end
if oltp_range_selects then # 如果oltp_range_selects為true,(oltp_range_selects默認為true)
# 執行按范圍簡單查詢 1次(oltp_simple_ranges默認為1次,所以只會執行1次for循環查詢)
# SQL語句為:
# SELECT c FROM table_name WHERE id BETWEEN id_value1 AND id_value2
# 說明:
# id_value1 隨機獲取已存在記錄ID,下同,不再贅述
# id_value2 id_value1 + 99,下同,不再贅述
for i=1, oltp_simple_ranges do
rs = db_query("SELECT c FROM ".. table_name .. get_range_str())
end
# 執行 按范圍sum查詢 1次 (oltp_sum_ranges默認值為 1,所以只會執行1次for循環查詢)
# SQL語句為:
# SELECT sum(c) FROM table_name WHERE id BETWEEN id_value1 AND id_value2
for i=1, oltp_sum_ranges do
rs = db_query("SELECT SUM(K) FROM ".. table_name .. get_range_str())
end
# 執行 按范圍排序查詢 1次 (oltp_order_ranges默認值為 1,所以只會執行1次for循環查詢)
# SQL語句為:
# SELECT c FROM table_name WHERE id BETWEEN id_value1 AND id_value2 ORDER BY c
for i=1, oltp_order_ranges do
rs = db_query("SELECT c FROM ".. table_name .. get_range_str() ..
" ORDER BY c")
end
# 執行 DISTINCT 排序查詢 1次 (oltp_distinct_ranges默認值為 1,所以只會執行1次for循環查詢)
# SQL語句為:
# SELECT DISTINCT c FROM table_name WHERE id BETWEEN id_value1 AND id_value2 ORDER BY c
for i=1, oltp_distinct_ranges do
rs = db_query("SELECT DISTINCT c FROM ".. table_name .. get_range_str() ..
" ORDER BY c")
end
end
end
if not oltp_read_only then # not oltp_read_only為真(oltp_read_only默認為false)
# 執行 更新索引列字段操作 1次 (oltp_index_updates默認值為 1,所以只會執行1次for循環查詢)
# SQL語句為:
# UPDATE table_name SET k=k+1 WHERE id=id_value
# 說明:
# k為索引列字段
for i=1, oltp_index_updates do
rs = db_query("UPDATE " .. table_name .. " SET k=k+1 WHERE id=" .. sb_rand(1, oltp_table_size))
end
# 執行 更新非索引列字段操作 1次 (oltp_index_updates默認值為 1,所以只會執行1次for循環查詢)
# SQL語句為:
# UPDATE table_name SET c="c_val" WHERE id=id_value
# 說明:
# c_val 長度為119位字符的隨機字符串
for i=1, oltp_non_index_updates do
c_val = sb_rand_str("###########-###########-###########-###########-###########-###########-###########-###########-###########-###########") # 長度為119位字符的隨機字符串
query = "UPDATE " .. table_name .. " SET c='" .. c_val .. "' WHERE id=" .. sb_rand(1, oltp_table_size)
rs = db_query(query)
if rs then
print(query) # 打印查詢結果
end
end
# 執行 刪除指定記錄操作 1次 (oltp_delete_inserts默認值為 1,所以只會執行1次for循環查詢)
# SQL語句為:
# DELETE FROM table_name WHERE id=id_value1
for i=1, oltp_delete_inserts do
i = sb_rand(1, oltp_table_size)
rs = db_query("DELETE FROM " .. table_name .. " WHERE id=" .. i)
c_val = sb_rand_str([[
###########-###########-###########-###########-###########-###########-###########-###########-###########-###########]])
pad_val = sb_rand_str([[
###########-###########-###########-###########-###########]]) # 64位隨機字符串
# 執行 插入數據操作 1次
# SQL語句為:
# INSERT INTO table_name(id, K, c, pad)VALUES(id_value, num, field_value1, field_value2 )
# 說明:
# num [1,表記錄數] 范圍內的隨機整數
# field_value1 119位隨機字符串
# field_value2 64位隨機字符串
rs = db_query("INSERT INTO " .. table_name .. " (id, k, c, pad) VALUES " .. string.format("(%d, %d, '%s', '%s')",i, sb_rand(1, oltp_table_size) , c_val, pad_val))
end
end -- oltp_read_only
if not oltp_skip_trx then
db_query(commit_query)
end
end
sysbench-1.0.20/tests/include/oltp_legacy/common.lua
具體分析參見中文注釋
-- Input parameters
-- oltp-tables-count - number of tables to create
-- oltp-secondary - use secondary key instead PRIMARY key for id column
--
--
# 定義插入函數
function create_insert(table_id)
local index_name
local i
local j
local query
if (oltp_secondary) then
index_name = "KEY xid"
else
index_name = "PRIMARY KEY"
end
if (pgsql_variant == 'redshift') then
auto_inc_type = "INTEGER IDENTITY(1,1)"
else
auto_inc_type = "SERIAL"
end
i = table_id
print("Creating table 'sbtest" .. i .. "'...")
# 根據不同驅動,執行對應建表語句,表名格式 sbtestN,其中N從1開始,最大值為oltp_tables_count
if ((db_driver == "mysql") or (db_driver == "attachsql")) then
query = [[
CREATE TABLE sbtest]] .. i .. [[ (
id INTEGER UNSIGNED NOT NULL ]] ..
((oltp_auto_inc and "AUTO_INCREMENT") or "") .. [[,
k INTEGER UNSIGNED DEFAULT '0' NOT NULL,
c CHAR(120) DEFAULT '' NOT NULL,
pad CHAR(60) DEFAULT '' NOT NULL,
]] .. index_name .. [[ (id)
) /*! ENGINE = ]] .. mysql_table_engine ..
" MAX_ROWS = " .. myisam_max_rows .. " */ " ..
(mysql_table_options or "")
elseif (db_driver == "pgsql") then
query = [[
CREATE TABLE sbtest]] .. i .. [[ (
id ]] .. auto_inc_type .. [[ NOT NULL,
k INTEGER DEFAULT '0' NOT NULL,
c CHAR(120) DEFAULT '' NOT NULL,
pad CHAR(60) DEFAULT '' NOT NULL,
]] .. index_name .. [[ (id)
) ]]
elseif (db_driver == "drizzle") then
query = [[
CREATE TABLE sbtest (
id INTEGER NOT NULL ]] .. ((oltp_auto_inc and "AUTO_INCREMENT") or "") .. [[,
k INTEGER DEFAULT '0' NOT NULL,
c CHAR(120) DEFAULT '' NOT NULL,
pad CHAR(60) DEFAULT '' NOT NULL,
]] .. index_name .. [[ (id)
) ]]
else
print("Unknown database driver: " .. db_driver)
return 1
end
db_query(query)
print("Inserting " .. oltp_table_size .. " records into 'sbtest" .. i .. "'")
if (oltp_auto_inc) then
db_bulk_insert_init("INSERT INTO sbtest" .. i .. "(k, c, pad) VALUES")
else
db_bulk_insert_init("INSERT INTO sbtest" .. i .. "(id, k, c, pad) VALUES")
end
local c_val
local pad_val
# for循環,往表插入數據,直到插入oltp_table_size條記錄
for j = 1,oltp_table_size do
c_val = sb_rand_str([[
###########-###########-###########-###########-###########-###########-###########-###########-###########-###########]])
pad_val = sb_rand_str([[
###########-###########-###########-###########-###########]])
if (oltp_auto_inc) then
db_bulk_insert_next("(" .. sb_rand(1, oltp_table_size) .. ", '".. c_val .."', '" .. pad_val .. "')")
else
db_bulk_insert_next("("..j.."," .. sb_rand(1, oltp_table_size) .. ",'".. c_val .."', '" .. pad_val .. "' )")
end
end
db_bulk_insert_done()
if oltp_create_secondary then
print("Creating secondary indexes on 'sbtest" .. i .. "'...")
db_query("CREATE INDEX k_" .. i .. " on sbtest" .. i .. "(k)")
end
end
# 定義執行prepare命令時調用的函數
function prepare()
local query
local i
local j
set_vars() # 設置變量
db_connect() # 連接數據庫
# for循環插入數據,循環次數為 oltp_tables_count,
for i = 1,oltp_tables_count do
create_insert(i)
end
return 0
end
# 定義執行clean命令時調用的函數
function cleanup()
local i
set_vars() # 調用set_vars函數,設置變量
for i = 1,oltp_tables_count do
print("Dropping table 'sbtest" .. i .. "'...")
db_query("DROP TABLE IF EXISTS sbtest".. i ) # 刪除表sbtestN,其中N從1~ oltp_tables_count,即表數量
end
end
function set_vars()
# 以下非本地變量的默認值都為 nil
oltp_table_size = tonumber(oltp_table_size) or 10000 # 單表記錄總數 默認值10000
oltp_range_size = tonumber(oltp_range_size) or 100 # between and 范圍查詢 默認值100
oltp_tables_count = tonumber(oltp_tables_count) or 1 # 表數量 默認值 1
oltp_point_selects = tonumber(oltp_point_selects) or 10 # 按點查詢次數(where id=) 默認值 10
oltp_simple_ranges = tonumber(oltp_simple_ranges) or 1 # 簡單查詢次數 默認值 1
oltp_sum_ranges = tonumber(oltp_sum_ranges) or 1 # sum查詢次數 默認值 1
oltp_order_ranges = tonumber(oltp_order_ranges) or 1 # order by排序查詢次數 默認值 1
oltp_distinct_ranges = tonumber(oltp_distinct_ranges) or 1 # distinct范圍查詢次數 默認值 1
oltp_index_updates = tonumber(oltp_index_updates) or 1 # 更新索引列操作次數 默認值 1
oltp_non_index_updates = tonumber(oltp_non_index_updates) or 1 # 更新索引列字段操作次數 默認值 1
oltp_delete_inserts = tonumber(oltp_delete_inserts) or 1 # 執行刪除記錄操作次數 默認值 1
if (oltp_range_selects == 'off') then
oltp_range_selects = false
else
oltp_range_selects = true
end
if (oltp_auto_inc == 'off') then
oltp_auto_inc = false
else
oltp_auto_inc = true
end
if (oltp_read_only == 'on') then
oltp_read_only = true
else
oltp_read_only = false
end
if (oltp_write_only == 'on') then
oltp_write_only = true
else
oltp_write_only = false
end
if (oltp_read_only and oltp_write_only) then
error("--oltp-read-only and --oltp-write-only are mutually exclusive")
end
if (oltp_skip_trx == 'on') then
oltp_skip_trx = true
else
oltp_skip_trx = false
end
if (oltp_create_secondary == 'off') then
oltp_create_secondary = false
else
oltp_create_secondary = true
end
if (pgsql_variant == 'redshift') then
oltp_create_secondary = false
oltp_delete_inserts = 0
end
end
運行結果說明
混合操作壓測結果為例
# cat result.txt
sysbench 1.0.20 (using bundled LuaJIT 2.1.0-beta2)
Running the test with following options:
Number of threads: 300
Initializing random number generator from current time
Initializing worker threads...
Threads started!
SQL statistics:
queries performed:
read: 34507228
write: 9859208
other: 4929604
total: 49296040
transactions: 2464802 (2053.74 per sec.)
queries: 49296040 (41074.74 per sec.)
ignored errors: 0 (0.00 per sec.)
reconnects: 0 (0.00 per sec.)
General statistics:
total time: 1200.1525s
total number of events: 2464802
Latency (ms):
min: 129.86
avg: 146.06
max: 806.70
95th percentile: 155.80
sum: 360014005.42
Threads fairness:
events (avg/stddev): 8216.0067/329.90
execution time (avg/stddev): 1200.0467/0.04
結果項說明:
SQL statistics:
queries performed: 執行的SQL查詢:
read: 讀請求次數
write: 寫請求次數
other: 其它請求次數
total: 總請求次數
transactions: 執行的事務總數 (每秒事務數.)
queries: 執行的查詢總次數 (每秒查詢次數.)
ignored errors: 忽略錯誤數 (每秒忽略錯誤次數.)
reconnects: 數據庫重連次數 (每秒重連次數.)
General statistics:
total time: 總運行時間,以秒為單位
total number of events: 總執行事件數
Latency (毫秒為單位):
min: 最小請求響應時間
avg: 平均請求響應時間
max: 最大請求響應時間
95th percentile: 95%的請求響應時間
sum: 總請求響應時間
Threads fairness:
events (avg/stddev): 執行的事件總數(平均每個線程執行的事件總數/標准差)
execution time (avg/stddev): 執行耗時(平均每個線程執行事件耗時/標准差)
參考連接
https://github.com/akopytov/sysbench#general-command-line-options