主頁 > 資料庫 > MySQL 性能壓測工具-sysbench,從入門到自定義測驗項

MySQL 性能壓測工具-sysbench,從入門到自定義測驗項

2022-12-07 12:06:19 資料庫

sysbench是一個開源的、基于LuaJIT(LuaJIT 是 Lua 的即時編譯器,可將代碼直接翻譯成機器碼,性能比原生 lua 要高) 的、可自定義腳本的多執行緒基準測驗工具,也是目前用得最多的 MySQL 性能壓測工具,

基于 sysbench,我們可以對比 MySQL 在不同版本、不同硬體配置、不同引數(作業系統和資料庫)下的性能差異,

下面會從 sysbench 的基本用法出發,逐漸延伸到 sysbench 的一些高級玩法,譬如如何閱讀自帶的測驗腳本、如何自定義測驗項等,除此之外,使用 sysbench 對 CPU 進行測驗,網上很多資料都語焉不詳,甚至是錯誤的,所以這次也會從原始碼的角度分析 CPU 測驗的實作邏輯及 --cpu-max-prime 選項的具體含義,

本文主要包括以下幾部分:

  1. 安裝sysbench
  2. sysbench用法講解
  3. 對MySQL進行基準測驗的基本步驟
  4. 如何分析MySQL基準測驗結果
  5. 如何使用sysbench對服務器進行測驗
  6. MySQL常見測驗場景及對應的 SQL 陳述句
  7. 如何自定義sysbench測驗腳本

 

安裝 sysbench

下面是 sysbench 原始碼包的安裝步驟,

# yum -y install make automake libtool pkgconfig libaio-devel openssl-devel mysql-devel
# cd /usr/src/
# wget https://github.com/akopytov/sysbench/archive/refs/tags/1.0.20.tar.gz
# tar xvf 1.0.20.tar.gz
# cd sysbench-1.0.20/
# ./autogen.sh
# ./configure
# make -j
# make install

安裝完成后,壓測腳本默認會安裝在 /usr/local/share/sysbench 目錄下,

我們看看該目錄的內容,

# ls /usr/local/share/sysbench/
bulk_insert.lua  oltp_insert.lua        oltp_read_write.lua        oltp_write_only.lua       tests
oltp_common.lua  oltp_point_select.lua  oltp_update_index.lua      select_random_points.lua
oltp_delete.lua  oltp_read_only.lua     oltp_update_non_index.lua  select_random_ranges.lua

除了oltp_common.lua是個公共模塊,其它每個 lua 腳本都對應一個測驗場景,

 

sysbench 用法講解

sysbench 命令語法如下:

sysbench [options]... [testname] [command]

命令中的testname是測驗項名稱,sysbench 支持的測驗項包括:

  • *.lua:資料庫性能基準測驗,

  • fileio:磁盤 IO 基準測驗,

  • cpu:CPU 性能基準測驗,

  • memory:記憶體訪問基準測驗,

  • threads:基于執行緒的調度程式基準測驗,

  • mutex:POSIX 互斥量基準測驗,

command是 sysbench 要執行的命令,支持的選項有:prepareprewarmruncleanuphelp,注意,不是所有的測驗項都支持這些選項,

options是配置項,sysbench 中的配置項主要包括以下兩部分:

1.  通用配置項,這部分配置項可通過 sysbench --help 查看,例如,

# sysbench --help
...
General options:
  --threads=N                     number of threads to use [1]
  --events=N                      limit for total number of events [0]
  --time=N                        limit for total execution time in seconds [10]
 ...

2.  測驗項相關的配置項,各個測驗項支持的配置項可通過 sysbench testname help 查看,例如,

# sysbench memory help
sysbench 1.0.20 (using bundled LuaJIT 2.1.0-beta2)

memory options:
  --memory-block-size=SIZE    size of memory block for test [1K]
  --memory-total-size=SIZE    total size of data to transfer [100G]
  --memory-scope=STRING       memory access scope {global,local} [global]
  --memory-hugetlb[=on|off]   allocate memory from HugeTLB pool [off]
  --memory-oper=STRING        type of memory operations {read, write, none} [write]
  --memory-access-mode=STRING memory access mode {seq,rnd} [seq]

 

對 MySQL 進行基準測驗的基本步驟

下面以oltp_read_write為例,看看使用 sysbench 對 MySQL 進行基準測驗的四個標準步驟:

prepare

生成壓測資料,默認情況下,sysbench 是通過 INSERT INTO 命令來匯入測驗資料的,如果是使用 LOAD DATA LOCAL INFILE 命令來匯入,sysbench 導數速度能提升30%,具體可參考:使用 LOAD DATA LOCAL INFILE,sysbench 導數速度提升30%

# sysbench oltp_read_write --mysql-host=10.0.0.64 --mysql-port=3306 --mysql-user=admin --mysql-password=Py@123456 --mysql-db=sbtest --tables=30 --table-size=1000000 --threads=30 prepare

命令中各個選項的具體含義如下:

  • oltp_read_write:測驗項,對應的是/usr/local/share/sysbench/oltp_read_write.lua,這里也可指定腳本的絕對路徑名,
  • --mysql-host、--mysql-port、--mysql-user、--mysql-password:分別代表 MySQL 實體的主機名、埠、用戶名和密碼,
  • --mysql-db:庫名,不指定則默認為sbtest
  • --tables :表的數量,默認為 1,
  • --table-size :單表的大小,默認為 10000,
  • --threads :并發執行緒數,默認為 1,注意,匯入時,單表只能使用一個執行緒,
  • prepare:執行準備作業,

oltp_read_write 用來壓測 OLTP 場景,在 sysbench 1.0 之前, 該場景是通過 oltp.lua 這個腳本來測驗的,不過該腳本在 sysbench 1.0 之后就被廢棄了,但為了跟之前的版本兼容,該腳本放到了 /usr/local/share/sysbench/tests/include/oltp_legacy/ 目錄下,

鑒于 oltp_read_write.lua 和 oltp.lua 兩者的壓測內容完全一致,從 sysbench 1.0 開始,壓測 OLTP 場景建議直接使用 oltp_read_write,

prewarm

預熱,主要是將磁盤中的資料加載到記憶體中,

# sysbench oltp_read_write --mysql-host=10.0.0.64 --mysql-port=3306 --mysql-user=admin --mysql-password=Py@123456 --mysql-db=sbtest --tables=30 --table-size=1000000 --threads=30 prewarm

除了需要將命令設定為 prewarm,其它配置與 prepare 中一樣,

run

壓測,

# sysbench oltp_read_write --mysql-host=10.0.0.64 --mysql-port=3306 --mysql-user=admin --mysql-password=Py@123456 --mysql-db=sbtest --tables=30 --table-size=1000000 --threads=64 --time=60 --report-interval=10 run

其中,

  • --time :壓測時間,不指定則默認為 10 秒,除了 --time,也可通過 --events 限制需要執行的 event 的數量,

  • --report-interval=10 :每 10 秒輸出一次測驗結果,默認為 0,不輸出,

cleanup

清理資料,

# sysbench oltp_read_write --mysql-host=10.0.0.64 --mysql-port=3306 --mysql-user=admin --mysql-password=Py@123456 --mysql-db=sbtest --tables=30 cleanup

這里只需指定 --tables ,sysbench 會串行執行 DROP TABLE IF EXISTS sbtest 操作,

 

如何分析 MySQL 基準測驗結果

下面我們分析下 oltp_read_write 場景下的壓測結果,注:右滑可以看到每個指標的具體含義,

Threads started!

[ 10s ] thds: 64 tps: 5028.08 qps: 100641.26 (r/w/o: 70457.59/20121.51/10062.16) lat (ms,95%): 17.32 err/s: 0.00 reconn/s: 0.00
# thds 是并發執行緒數,tps 是每秒事務數,qps 是每秒運算元,等于 r(讀操作)加上 w(寫操作)加上 o(其他操作,主要包括 BEGIN 和 COMMIT),lat 是延遲,(ms,95%) 是 95% 的查詢時間小于或等于該值,單位毫秒,err/s 是每秒錯誤數,reconn/s 是每秒重試的次數,
[ 20s ] thds: 64 tps: 5108.93 qps: 102192.09 (r/w/o: 71533.28/20440.64/10218.17) lat (ms,95%): 17.32 err/s: 0.00 reconn/s: 0.00
[ 30s ] thds: 64 tps: 5126.50 qps: 102505.50 (r/w/o: 71756.30/20496.60/10252.60) lat (ms,95%): 17.32 err/s: 0.00 reconn/s: 0.00
[ 40s ] thds: 64 tps: 5144.50 qps: 102907.20 (r/w/o: 72034.07/20583.72/10289.41) lat (ms,95%): 17.01 err/s: 0.00 reconn/s: 0.00
[ 50s ] thds: 64 tps: 5137.29 qps: 102739.80 (r/w/o: 71916.99/20548.64/10274.17) lat (ms,95%): 17.01 err/s: 0.00 reconn/s: 0.00
[ 60s ] thds: 64 tps: 4995.38 qps: 99896.35 (r/w/o: 69925.98/19979.61/9990.75) lat (ms,95%): 17.95 err/s: 0.00 reconn/s: 0.00
SQL statistics:
    queries performed:
        read:                            4276622 # 讀操作的數量
        write:                           1221892 # 寫操作的數量
        other:                           610946  # 其它操作的數量
        total:                           6109460 # 總的運算元量,total = read + write + other
    transactions:                        305473 (5088.63 per sec.)    # 總的事務數(每秒事務數)
    queries:                             6109460 (101772.64 per sec.) # 總的運算元(每秒運算元)
    ignored errors:                      0      (0.00 per sec.)       # 忽略的錯誤數(每秒忽略的錯誤數)
    reconnects:                          0      (0.00 per sec.)       # 重試次數(每秒重試的次數)

General statistics:
    total time:                          60.0301s  # 總的執行時間
    total number of events:              305473    # 執行的 event 的數量
                                                   # 在 oltp_read_write 中,默認引數下,一個 event 其實就是一個事務

Latency (ms):
         min:                                    5.81 # 最小耗時
         avg:                                   12.57 # 平均耗時
         max:                                  228.87 # 最大耗時
         95th percentile:                       17.32 # 95% event 的執行耗時
         sum:                              3840044.28 # 總耗時

Threads fairness:
    events (avg/stddev):           4773.0156/30.77  # 平均每個執行緒執行 event 的數量
                                                    # stddev 是標準差,值越小,代表結果越穩定,
    execution time (avg/stddev):   60.0007/0.01     # 平均每個執行緒的執行時間

輸出中,重點關注三個指標:

  1. 每秒事務數,即我們常說的 TPS,
  2. 每秒運算元,即我們常說的 QPS,
  3. 95% event 的執行耗時,

TPS 和 QPS 反映了系統的吞吐量,越大越好,執行耗時代表了事務的執行時長,越小越好,在一定范圍內,并發執行緒數指定得越大,TPS 和 QPS 也會越高,

 

使用 sysbench 對服務器進行測驗

除了資料庫基準測驗,sysbench 還能對服務器的性能進行測驗,服務器資源一般包括四大類:CPU、記憶體、IO和網路,sysbench 可對CPU、記憶體和磁盤IO進行測驗,下面我們具體來看看,

cpu

CPU 性能測驗,支持的選項只有一個,即--cpu-max-prime

CPU 測驗的命令如下:

# sysbench cpu --cpu-max-prime=20000 --threads=32 run

輸出中,重點關注events per second,值越大,代表 CPU 的計算性能越強,

CPU speed:
    events per second: 25058.08

下面是 CPU 測驗相關的代碼,可以看到,sysbench 是通過計算--cpu-max-prime范圍內的質數來衡量 CPU 的計算能力的,

質數(prime number)又稱素數,指的是大于 1,且只能被 1 和自身整除的自然數,在代碼實作時,對于自然數 n,一般會用 2 到根號 n 之間的整數去除,如果都無法整除,則意味著 n 是個質數,

int cpu_execute_event(sb_event_t *r, int thread_id)
{
  unsigned long long c;
  unsigned long long l;
  double t;
  unsigned long long n=0;

  (void)thread_id; /* unused */
  (void)r; /* unused */

  // max_prime 即命令列中指定的 --cpu-max-prime
  for(c=3; c < max_prime; c++)
  {
    t = sqrt((double)c);
    for(l = 2; l <= t; l++)
      if (c % l == 0)
        break;
    if (l > t )
      n++;
  }

  return 0;
}

memory

記憶體測驗,支持的選項有:

  • --memory-block-size:記憶體塊的大小,默認為 1KB,測驗時建議設定為 1MB,
  • --memory-total-size:要傳輸的資料的總大小,默認為 100GB,
  • --memory-scope:記憶體訪問范圍,可指定 global、local,默認為 global,
  • --memory-hugetlb:是否從 HugeTLB 池中分配記憶體,默認為 off,
  • --memory-oper:記憶體操作型別,可指定 read、write、none,默認為 write,
  • --memory-access-mode:記憶體訪問模式,可指定 seq(順序訪問)、rnd(隨機訪問),默認為 seq,

記憶體測驗的命令如下:

# sysbench --test=memory --memory-block-size=1M --memory-total-size=100G --num-threads=1 run

輸出中,重點關注以下部分:

102400.00 MiB transferred (23335.96 MiB/sec)

23335.96 MiB/sec 即資料在記憶體中的順序寫入速率,


fileio

磁盤 IO 測驗,支持的選項有:

  • --file-num:需要創建的檔案數,默認為128,
  • --file-block-size:資料塊的大小,默認為16384,即16KB,
  • --file-total-size:需要創建的檔案總大小,默認為2GB,
  • --file-test-mode:測驗模式,可指定 seqwr(順序寫)、seqrewr(順序重寫)、seqrd(順序讀)、rndrd(隨機讀)、rndwr(隨機寫)、rndrw(隨機讀寫),
  • --file-io-mode:檔案的操作模式,可指定 sync(同步 IO)、async(異步 IO)、mmap,默認為 sync,
  • --file-async-backlog:每個執行緒異步 IO 佇列的長度,默認為 128,
  • --file-extra-flags:打開檔案時指定的標志,可指定 sync、dsync、direct,默認為空,沒指定,
  • --file-fsync-freq:指定持久化操作的頻率,默認為 100,即每執行 100 個 IO 請求,則會進行一次持久化操作,
  • --file-fsync-all:在每次寫入操作后執行持久化操作,默認為 off,
  • --file-fsync-end:在測驗結束時執行持久化操作,默認為 on,
  • --file-fsync-mode:持久化操作的模式,可指定 fsync、fdatasync,默認為 fsync,fdatasync 和 fsync類似,只不過 fdatasync 只會更新資料,而 fsync 還會同步更新檔案的屬性,
  • --file-merged-requests:允許合并的最多 IO 請求數,默認為0,不合并,
  • --file-rw-ratio:混合測驗中的讀寫比例,默認為1.5,

磁盤 IO 測驗主要分為以下三步:

# 準備測驗檔案
# sysbench fileio --file-num=1 --file-total-size=10G --file-test-mode=rndrw prepare

# 測驗
# sysbench fileio --file-num=1 --file-total-size=10G --file-test-mode=rndrw run

# 洗掉測驗檔案
# sysbench fileio --file-num=1 --file-total-size=10G --file-test-mode=rndrw cleanup

輸出中,重點關注以下兩部分:

File operations:
    reads/s:                      4978.26
    writes/s:                     3318.84
    fsyncs/s:                     83.07

Throughput:
    read, MiB/s:                  77.79
    written, MiB/s:               51.86

其中,reads/s 加上 writes/s 即我們常說的 IOPS,read, MiB/s 加上 written, MiB/s 即我們常說的吞吐量,

 

MySQL 常見測驗場景及對應的 SQL 陳述句

接下來會列舉 MySQL 常見的測驗場景及各個場景對應的 SQL 陳述句,

為了讓大家清晰的知道 SQL 陳述句的含義,首先我們看看測驗表的表結構,

除了 bulk_insert 會創建單獨的測驗表,其它場景都會使用下面的表結構,

mysql> show create table sbtest.sbtest1\G
*************************** 1. row ***************************
       Table: sbtest1
Create Table: CREATE TABLE `sbtest1` (
  `id` int NOT NULL AUTO_INCREMENT,
  `k` int NOT NULL DEFAULT '0',
  `c` char(120) NOT NULL DEFAULT '',
  `pad` char(60) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`),
  KEY `k_1` (`k`)
) ENGINE=InnoDB AUTO_INCREMENT=1000001 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.00 sec)

bulk_insert

批量插入測驗,

# sysbench bulk_insert --mysql-host=10.0.0.64 --mysql-port=3306 --mysql-user=admin --mysql-password=Py@123456 --mysql-db=sbtest --tables=30 --table-size=1000000 --threads=64 --time=60 --report-interval=10 run

下面是 bulk_insert 場景下創建的測驗表,

mysql> show create table sbtest.sbtest1\G
*************************** 1. row ***************************
       Table: sbtest1
Create Table: CREATE TABLE `sbtest1` (
  `id` int NOT NULL,
  `k` int NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.01 sec)

測驗對應的 SQL 陳述句如下:

INSERT INTO sbtest1 VALUES(?, ?),(?, ?),(?, ?),(?, ?)...

oltp_delete

洗掉測驗,

# sysbench oltp_delete --mysql-host=10.0.0.64 --mysql-port=3306 --mysql-user=admin --mysql-password=Py@123456 --mysql-db=sbtest --tables=30 --table-size=1000000 --threads=64 --time=60 --report-interval=10 run

基于主鍵進行洗掉,測驗對應的 SQL 陳述句如下:

DELETE FROM sbtest1 WHERE id=?

oltp_insert

插入測驗,

# sysbench oltp_insert --mysql-host=10.0.0.64 --mysql-port=3306 --mysql-user=admin --mysql-password=Py@123456 --mysql-db=sbtest --tables=30 --table-size=1000000 --threads=64 --time=60 --report-interval=10 run

測驗對應的 SQL 陳述句如下:

INSERT INTO sbtest1 (id, k, c, pad) VALUES (?, ?, ?, ?)

oltp_point_select

基于主鍵進行查詢,

# sysbench oltp_point_select --mysql-host=10.0.0.64 --mysql-port=3306 --mysql-user=admin --mysql-password=Py@123456 --mysql-db=sbtest --tables=30 --table-size=1000000 --threads=64 --time=60 --report-interval=10 run

測驗對應的 SQL 陳述句如下:

SELECT c FROM sbtest1 WHERE id=?

oltp_read_only

只讀測驗,

# sysbench oltp_read_only --mysql-host=10.0.0.64 --mysql-port=3306 --mysql-user=admin --mysql-password=Py@123456 --mysql-db=sbtest --tables=30 --table-size=1000000 --threads=64 --time=60 --report-interval=10 run

測驗對應的 SQL 陳述句如下:

SELECT c FROM sbtest1 WHERE id=? # 默認會執行 10 次,由 --point_selects 選項控制,
SELECT c FROM sbtest1 WHERE id BETWEEN ? AND ?
SELECT SUM(k) FROM sbtest1 WHERE id BETWEEN ? AND ?
SELECT c FROM sbtest1 WHERE id BETWEEN ? AND ? ORDER BY c
SELECT DISTINCT c FROM sbtest1 WHERE id BETWEEN ? AND ? ORDER BY c

oltp_read_write

讀寫測驗,

測驗對應的 SQL 陳述句如下:

SELECT c FROM sbtest1 WHERE id=? # 默認會執行 10 次,由 --point_selects 選項控制,
SELECT c FROM sbtest1 WHERE id BETWEEN ? AND ?
SELECT SUM(k) FROM sbtest1 WHERE id BETWEEN ? AND ?
SELECT c FROM sbtest1 WHERE id BETWEEN ? AND ? ORDER BY c
SELECT DISTINCT c FROM sbtest1 WHERE id BETWEEN ? AND ? ORDER BY c
UPDATE sbtest1 SET k=k+1 WHERE id=?
UPDATE sbtest1 SET c=? WHERE id=?
DELETE FROM sbtest1 WHERE id=?
INSERT INTO sbtest1 (id, k, c, pad) VALUES (?, ?, ?, ?)

oltp_update_index

基于主鍵進行更新,更新的是索引欄位,

# sysbench oltp_update_index --mysql-host=10.0.0.64 --mysql-port=3306 --mysql-user=admin --mysql-password=Py@123456 --mysql-db=sbtest --tables=30 --table-size=1000000 --threads=64 --time=60 --report-interval=10 run

測驗對應的 SQL 陳述句如下:

UPDATE sbtest1 SET k=k+1 WHERE id=?

oltp_update_non_index

基于主鍵進行更新,更新的是非索引欄位,

# sysbench oltp_update_non_index --mysql-host=10.0.0.64 --mysql-port=3306 --mysql-user=admin --mysql-password=Py@123456 --mysql-db=sbtest --tables=30 --table-size=1000000 --threads=64 --time=60 --report-interval=10 run

測驗對應的 SQL 陳述句如下:

UPDATE sbtest1 SET c=? WHERE id=?

oltp_write_only

只寫測驗,

# sysbench oltp_write_only --mysql-host=10.0.0.64 --mysql-port=3306 --mysql-user=admin --mysql-password=Py@123456 --mysql-db=sbtest --tables=30 --table-size=1000000 --threads=64 --time=60 --report-interval=10 run

測驗對應的 SQL 語句如下:

UPDATE sbtest1 SET k=k+1 WHERE id=?
UPDATE sbtest1 SET c=? WHERE id=?
DELETE FROM sbtest1 WHERE id=?
INSERT INTO sbtest1 (id, k, c, pad) VALUES (?, ?, ?, ?)

select_random_points

基于索引進行隨機查詢,

# sysbench select_random_points --mysql-host=10.0.0.64 --mysql-port=3306 --mysql-user=admin --mysql-password=Py@123456 --mysql-db=sbtest --tables=30 --table-size=1000000 --threads=64 --time=60 --report-interval=10 run

測驗對應的 SQL 陳述句如下:

SELECT id, k, c, pad
          FROM sbtest1
          WHERE k IN (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)

select_random_ranges

基于索引進行隨機范圍查詢,

# sysbench select_random_ranges --mysql-host=10.0.0.64 --mysql-port=3306 --mysql-user=admin --mysql-password=Py@123456 --mysql-db=sbtest --tables=30 --table-size=1000000 --threads=64 --time=60 --report-interval=10 run

測驗對應的 SQL 陳述句如下:

SELECT count(k)
          FROM sbtest1
          WHERE k BETWEEN ? AND ? OR k BETWEEN ? AND ? OR k BETWEEN ? AND ? OR k BETWEEN ? AND ? OR k BETWEEN ? AND ? OR k BETWEEN ? AND ? OR k BETWEEN ? AND ? OR k BETWEEN ? AND ? OR k BETWEEN ? AND ? OR k BETWEEN ? AND ?

 

如何自定義 sysbench 測驗腳本

下面通過 bulk_insert.lua 和 oltp_point_select.lua 這兩個腳本分析下 sysbench 測驗腳本的實作邏輯,

首先看看 bulk_insert.lua,

# cat bulk_insert.lua
#!/usr/bin/env sysbench

cursize=0
function thread_init()
   drv = sysbench.sql.driver()
   con = drv:connect()
end

function prepare()
   local i

   local drv = sysbench.sql.driver()
   local con = drv:connect()

   for i = 1, sysbench.opt.threads do
      print("Creating table 'sbtest" .. i .. "'...")
      con:query(string.format([[
        CREATE TABLE IF NOT EXISTS sbtest%d (
          id INTEGER NOT NULL,
          k INTEGER DEFAULT '0' NOT NULL,
          PRIMARY KEY (id))]], i))
   end
end

function event()
   if (cursize == 0) then
      con:bulk_insert_init("INSERT INTO sbtest" .. thread_id+1 .. " VALUES")
   end

   cursize = cursize + 1

   con:bulk_insert_next("(" .. cursize .. "," .. cursize .. ")")
end

function thread_done(thread_9d)
   con:bulk_insert_done()
   con:disconnect()
end

function cleanup()
   local i

   local drv = sysbench.sql.driver()
   local con = drv:connect()

   for i = 1, sysbench.opt.threads do
      print("Dropping table 'sbtest" .. i .. "'...")
      con:query("DROP TABLE IF EXISTS sbtest" .. i )
   end
end

下面,我們看看這幾個函式的具體作用:

  • thread_init():執行緒初始化時呼叫,這個函式常用來創建資料庫連接,
  • prepare():指定 prepare 時呼叫,這個函式常用來創建測驗表,生成測驗資料,
  • event():指定 run 時呼叫,這個函式會定義需要測驗的 SQL 陳述句,
  • thread_done():執行緒退出時呼叫,這個函式常用來關閉 Prepared Statements 和資料庫連接,
  • cleanup():指定 cleanup 時呼叫,這個函式常用來洗掉測驗表,

如果我們要自定義測驗腳本,只需實作這幾個函式即可,

如果我們要基于 sbtest 表自定義測驗項,就要分析 oltp*.lua 腳本的實作邏輯,

下面,以 oltp_point_select.lua 腳本為例,

#!/usr/bin/env sysbench
...
require("oltp_common")

function prepare_statements()
   -- point_selects 是 oltp_point_select 中支持的選項,默認為 10,這里調整為了 1,
   sysbench.opt.point_selects=1

   prepare_point_selects()
end

function event()
   execute_point_selects()
end

與 bulk_insert.lua 不一樣的是,oltp_point_select.lua 只簡單的定義了兩個函式:prepare_statements()event(),實際上,不僅僅是 oltp_point_select.lua,其它 oltp*.lua 腳本也只定義了這兩個函式,

雖然只定義了這兩個函式,但腳本匯入了 oltp_common 模塊,所以實際上,腳本中的 prepare_point_selects(),execute_point_selects() 以及 bulk_insert.lua 中的 thread_init(),prepare(),thread_done(),cleanup() 都是在oltp_common.lua這個公共模塊中定義的,

接下來,我們看看 prepare_point_selects() 和 execute_point_selects() 這兩個函式的實作邏輯,

首先看看prepare_point_selects()

它呼叫的是prepare_for_each_table(),prepare_for_each_table()是一個基礎函式,所有prepare 相關的函式都會呼叫prepare_for_each_table(), 只不過不同的 prepare 函式會傳入不同的引數名,

prepare_for_each_table()會填充兩張表(Lua 中的表既可用來表示陣列,也可用來表示集合):stmt 和 param,其中,stmt 用來存盤 Prepared Statements 陳述句,param 用來存盤 Prepared Statements 陳述句相關的引數型別,

填充完畢后,最后再通過 bind_param 函式將兩者系結在一起,

可以看到,無論是 Prepared Statements 陳述句還是相關的引數型別,都是在 stmt_defs 定義的,

function prepare_point_selects()
   prepare_for_each_table("point_selects")
end

function prepare_for_each_table(key)
   for t = 1, sysbench.opt.tables do
      -- t 是表的序號,key 是測驗項的名字
      stmt[t][key] = con:prepare(string.format(stmt_defs[key][1], t))
    
      local nparam = #stmt_defs[key] - 1

      if nparam > 0 then
         param[t][key] = {}
      end

      for p = 1, nparam do
         local btype = stmt_defs[key][p+1]
         local len

         if type(btype) == "table" then
            len = btype[2]
            btype = btype[1]
         end
         if btype == sysbench.sql.type.VARCHAR or
            btype == sysbench.sql.type.CHAR then
               param[t][key][p] = stmt[t][key]:bind_create(btype, len)
         else
            param[t][key][p] = stmt[t][key]:bind_create(btype)
         end
      end

      if nparam > 0 then
         stmt[t][key]:bind_param(unpack(param[t][key]))
      end
   end
end

接下來,我們看看 stmt_defs 的內容,

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}},
}

可以看到,stmt_defs 是一張表,里面定義了不同測驗項對應的 Prepared Statements 陳述句和引數型別,

具體到 point_selects 這個測驗項,它對應的 Prepared Statements 陳述句是SELECT c FROM sbtest%u WHERE id=?,對應的引數型別是t.INT

梳理完 prepare_point_selects() 函式的實作邏輯,最后我們看看execute_point_selects()函式的實作邏輯,

function execute_point_selects()
   local tnum = get_table_num()
   local i
   -- point_selects 對應命令列中的 --point_selects 選項,默認為 10,
   for i = 1, sysbench.opt.point_selects do
      param[tnum].point_selects[1]:set(get_id())

      stmt[tnum].point_selects:execute()
   end
end

邏輯也非常簡單,先賦值,最后執行,

所以如果我們要基于 sbtest 表自定義測驗項,最關鍵的一步其實就是在 stmt_defs 中定義 Prepared Statements 陳述句和相關的引數型別,至于 prepare_xxx 和 execute_xxx 函式,實作起來都非常簡單,

 

總結

1. 基準測驗一般會關注三個指標:TPS/QPS、回應耗時和并發量,

2. 只有進行全鏈路壓測,我們才知道系統的瓶頸在哪里,不能想當然的以為,資料庫不容易橫向擴展,系統瓶頸就一定會出在資料庫層,事實上,很多系統在設計之初就引入了快取,而快取會分擔很大一部分讀流量,這種架構下的資料庫壓力其實并不大,

3. 不能簡單的將 sysbench 的測驗結果(TPS/QPS) 作為業務系統的吞吐量指標,因為兩者的業務模型并不一致,

4. 如果要自定義測驗腳本,實作的方式有兩種:

  • 自己實作測驗相關的所有函式,具體實作細節可參考 bulk_insert.lua,
  • 基于 sbtest 表自定義測驗項,實作程序中最關鍵的一步是在 stmt_defs 中定義 Prepared Statements 陳述句和相關的引數型別,

轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/539389.html

標籤:MySQL

上一篇:糟糕,資料庫例外不可用怎么辦?

下一篇:《MySQL必知必會》知識匯總四

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • GPU虛擬機創建時間深度優化

    **?桔妹導讀:**GPU虛擬機實體創建速度慢是公有云面臨的普遍問題,由于通常情況下創建虛擬機屬于低頻操作而未引起業界的重視,實際生產中還是存在對GPU實體創建時間有苛刻要求的業務場景。本文將介紹滴滴云在解決該問題時的思路、方法、并展示最終的優化成果。 從公有云服務商那里購買過虛擬主機的資深用戶,一 ......

    uj5u.com 2020-09-10 06:09:13 more
  • 可編程網卡芯片在滴滴云網路的應用實踐

    **?桔妹導讀:**隨著云規模不斷擴大以及業務層面對延遲、帶寬的要求越來越高,采用DPDK 加速網路報文處理的方式在橫向縱向擴展都出現了局限性。可編程芯片成為業界熱點。本文主要講述了可編程網卡芯片在滴滴云網路中的應用實踐,遇到的問題、帶來的收益以及開源社區貢獻。 #1. 資料中心面臨的問題 隨著滴滴 ......

    uj5u.com 2020-09-10 06:10:21 more
  • 滴滴資料通道服務演進之路

    **?桔妹導讀:**滴滴資料通道引擎承載著全公司的資料同步,為下游實時和離線場景提供了必不可少的源資料。隨著任務量的不斷增加,資料通道的整體架構也隨之發生改變。本文介紹了滴滴資料通道的發展歷程,遇到的問題以及今后的規劃。 #1. 背景 資料,對于任何一家互聯網公司來說都是非常重要的資產,公司的大資料 ......

    uj5u.com 2020-09-10 06:11:05 more
  • 滴滴AI Labs斬獲國際機器翻譯大賽中譯英方向世界第三

    **桔妹導讀:**深耕人工智能領域,致力于探索AI讓出行更美好的滴滴AI Labs再次斬獲國際大獎,這次獲獎的專案是什么呢?一起來看看詳細報道吧! 近日,由國際計算語言學協會ACL(The Association for Computational Linguistics)舉辦的世界最具影響力的機器 ......

    uj5u.com 2020-09-10 06:11:29 more
  • MPP (Massively Parallel Processing)大規模并行處理

    1、什么是mpp? MPP (Massively Parallel Processing),即大規模并行處理,在資料庫非共享集群中,每個節點都有獨立的磁盤存盤系統和記憶體系統,業務資料根據資料庫模型和應用特點劃分到各個節點上,每臺資料節點通過專用網路或者商業通用網路互相連接,彼此協同計算,作為整體提供 ......

    uj5u.com 2020-09-10 06:11:41 more
  • 滴滴資料倉庫指標體系建設實踐

    **桔妹導讀:**指標體系是什么?如何使用OSM模型和AARRR模型搭建指標體系?如何統一流程、規范化、工具化管理指標體系?本文會對建設的方法論結合滴滴資料指標體系建設實踐進行解答分析。 #1. 什么是指標體系 ##1.1 指標體系定義 指標體系是將零散單點的具有相互聯系的指標,系統化的組織起來,通 ......

    uj5u.com 2020-09-10 06:12:52 more
  • 單表千萬行資料庫 LIKE 搜索優化手記

    我們經常在資料庫中使用 LIKE 運算子來完成對資料的模糊搜索,LIKE 運算子用于在 WHERE 子句中搜索列中的指定模式。 如果需要查找客戶表中所有姓氏是“張”的資料,可以使用下面的 SQL 陳述句: SELECT * FROM Customer WHERE Name LIKE '張%' 如果需要 ......

    uj5u.com 2020-09-10 06:13:25 more
  • 滴滴Ceph分布式存盤系統優化之鎖優化

    **桔妹導讀:**Ceph是國際知名的開源分布式存盤系統,在工業界和學術界都有著重要的影響。Ceph的架構和演算法設計發表在國際系統領域頂級會議OSDI、SOSP、SC等上。Ceph社區得到Red Hat、SUSE、Intel等大公司的大力支持。Ceph是國際云計算領域應用最廣泛的開源分布式存盤系統, ......

    uj5u.com 2020-09-10 06:14:51 more
  • es~通過ElasticsearchTemplate進行聚合~嵌套聚合

    之前寫過《es~通過ElasticsearchTemplate進行聚合操作》的文章,這一次主要寫一個嵌套的聚合,例如先對sex集合,再對desc聚合,最后再對age求和,共三層嵌套。 Aggregations的部分特性類似于SQL語言中的group by,avg,sum等函式,Aggregation ......

    uj5u.com 2020-09-10 06:14:59 more
  • 爬蟲日志監控 -- Elastc Stack(ELK)部署

    傻瓜式部署,只需替換IP與用戶 導讀: 現ELK四大組件分別為:Elasticsearch(核心)、logstash(處理)、filebeat(采集)、kibana(可視化) 下載均在https://www.elastic.co/cn/downloads/下tar包,各組件版本最好一致,配合fdm會 ......

    uj5u.com 2020-09-10 06:15:05 more
最新发布
  • day02-2-商鋪查詢快取

    功能02-商鋪查詢快取 3.商鋪詳情快取查詢 3.1什么是快取? 快取就是資料交換的緩沖區(稱作Cache),是存盤資料的臨時地方,一般讀寫性能較高。 快取的作用: 降低后端負載 提高讀寫效率,降低回應時間 快取的成本: 資料一致性成本 代碼維護成本 運維成本 3.2需求說明 如下,當我們點擊商店詳 ......

    uj5u.com 2023-04-20 08:33:24 more
  • MySQL中binlog備份腳本分享

    關于MySQL的二進制日志(binlog),我們都知道二進制日志(binlog)非常重要,尤其當你需要point to point災難恢復的時侯,所以我們要對其進行備份。關于二進制日志(binlog)的備份,可以基于flush logs方式先切換binlog,然后拷貝&壓縮到到遠程服務器或本地服務器 ......

    uj5u.com 2023-04-20 08:28:06 more
  • day02-短信登錄

    功能實作02 2.功能01-短信登錄 2.1基于Session實作登錄 2.1.1思路分析 2.1.2代碼實作 2.1.2.1發送短信驗證碼 發送短信驗證碼: 發送驗證碼的介面為:http://127.0.0.1:8080/api/user/code?phone=xxxxx<手機號> 請求方式:PO ......

    uj5u.com 2023-04-20 08:27:27 more
  • 快取與資料庫雙寫一致性幾種策略分析

    本文將對幾種快取與資料庫保證資料一致性的使用方式進行分析。為保證高并發性能,以下分析場景不考慮執行的原子性及加鎖等強一致性要求的場景,僅追求最終一致性。 ......

    uj5u.com 2023-04-20 08:26:48 more
  • sql陳述句優化

    問題查找及措施 問題查找 需要找到具體的代碼,對其進行一對一優化,而非一直把關注點放在服務器和sql平臺 降低簡化每個事務中處理的問題,盡量不要讓一個事務拖太長的時間 例如檔案上傳時,應將檔案上傳這一步放在事務外面 微軟建議 4.啟動sql定時執行計劃 怎么啟動sqlserver代理服務-百度經驗 ......

    uj5u.com 2023-04-20 08:26:35 more
  • 云時代,MySQL到ClickHouse資料同步產品對比推薦

    ClickHouse 在執行分析查詢時的速度優勢很好的彌補了MySQL的不足,但是對于很多開發者和DBA來說,如何將MySQL穩定、高效、簡單的同步到 ClickHouse 卻很困難。本文對比了 NineData、MaterializeMySQL(ClickHouse自帶)、Bifrost 三款產品... ......

    uj5u.com 2023-04-20 08:26:29 more
  • sql陳述句優化

    問題查找及措施 問題查找 需要找到具體的代碼,對其進行一對一優化,而非一直把關注點放在服務器和sql平臺 降低簡化每個事務中處理的問題,盡量不要讓一個事務拖太長的時間 例如檔案上傳時,應將檔案上傳這一步放在事務外面 微軟建議 4.啟動sql定時執行計劃 怎么啟動sqlserver代理服務-百度經驗 ......

    uj5u.com 2023-04-20 08:25:13 more
  • Redis 報”OutOfDirectMemoryError“(堆外記憶體溢位)

    Redis 報錯“OutOfDirectMemoryError(堆外記憶體溢位) ”問題如下: 一、報錯資訊: 使用 Redis 的業務介面 ,產生 OutOfDirectMemoryError(堆外記憶體溢位),如圖: 格式化后的報錯資訊: { "timestamp": "2023-04-17 22: ......

    uj5u.com 2023-04-20 08:24:54 more
  • day02-2-商鋪查詢快取

    功能02-商鋪查詢快取 3.商鋪詳情快取查詢 3.1什么是快取? 快取就是資料交換的緩沖區(稱作Cache),是存盤資料的臨時地方,一般讀寫性能較高。 快取的作用: 降低后端負載 提高讀寫效率,降低回應時間 快取的成本: 資料一致性成本 代碼維護成本 運維成本 3.2需求說明 如下,當我們點擊商店詳 ......

    uj5u.com 2023-04-20 08:24:03 more
  • day02-短信登錄

    功能實作02 2.功能01-短信登錄 2.1基于Session實作登錄 2.1.1思路分析 2.1.2代碼實作 2.1.2.1發送短信驗證碼 發送短信驗證碼: 發送驗證碼的介面為:http://127.0.0.1:8080/api/user/code?phone=xxxxx<手機號> 請求方式:PO ......

    uj5u.com 2023-04-20 08:23:11 more