萬盛學電腦網

 萬盛學電腦網 >> 數據庫 >> mysql教程 >> mysql性能測試工具mysqlslap的使用

mysql性能測試工具mysqlslap的使用

mysqlslap是mysql的一個壓力測試工具了,我們可以利用mysqlslap來測試你配置服務器的一個壓力了,具體的來給各位簡單介紹一下吧。

特別關注下mysqlslap的假並發現象,因為壓力上不去浪費了一些時間。
主要就是–concurrency 參數所指的並發是線程並發,在開頭再??亂槐椤?/p>

1.mysql性能測試工具

mysql的性能測試工具常用的有四種:The MySQL Benchmark Suite、MySQL super-smack、MyBench和自帶的Mysqlslap. 除了第一個為MySQL性能測試工具,其他三個都為壓力測試工具

(1)The MySQL Benchmark Suite : 基於Perl語言和其中的兩個模塊:DBI和Benchmark,因為不支持多CPU而且不是壓力工具,拋棄該軟件

(2)MySQL super-smack 業界口碑較好,安裝出了壓縮包編譯安裝外,還需要yacc以及lex支持,安裝報錯找不到 lex和yacc啊啥的。 linux下使用flex及bison代替,可以用apt-get install bison flex 或類似的命令安裝,問題是還要找能連接外網的機器,能連接外網的機器不一定支持壓力,放棄該軟件

(3)MyBench

也是個perl模塊,雖然安裝方便,但是測試數據的使用比較麻煩,drop it.

(4) Mysqlslap

最終選用了mysqlslap。 安裝成本小:原因是mysql5.1.4 版本自帶,安裝mysql後就可以使用,不需要額外的配置。 場景部署多:帶有多個參數選項,測試數據的使用也方便。通過模擬多個並發客戶端並發訪問MySQL來執行壓力測試, 結果分析全:同時提供了較詳細的SQL執行數據性能報告,並且能很好的對比多個存儲引擎(MyISAM,InnoDB等)在相同環境下的相同並發壓力下的性能差別。

mysqlslap的官方網站: http://dev.mysql.com/doc/refman/5.6/en/mysqlslap.html

2.mysqlslap的安裝

1) 查看當前的mysql版本

./bin/mysql -V

2)如果版本低於5.1.4 請安裝mysql高版本

安裝過程中首先要關閉現在的客戶端。用netstat -pan|grep mysql查看當前mysql 的端口是否在運行。 為避免端口沖突,安裝前最好將mysql的進程關閉

3.mysqlslap的使用

(1) 使用步驟

看下官網對於使用步驟的解釋:

Create schema, table, and optionally any stored programs or data to use for the test. This stage uses a single client connection.

Run the load test. This stage can use many client connections.

Clean up (disconnect, drop table if specified). This stage uses a single client connection

mysqlslap的使用步驟主要是: 1. 創建schema、准備測試語句 (在MySQL中,schema就是database); 2. 運行負載測試,可以使用多個並發客戶端連接;(編寫腳本,可用多進程並發) 3. 測試環境清理 ,關閉進程,清理數據等。

(2) 參數說明
以下是mysqlslap的參數含義

view plaincopy to clipboardprint?
./bin/mysqlslap --help 可以看到幫助的參數解釋,下面介紹一些比較常用的 
 
--no-defaults 表示不使用默認參數文件中的設置. 
--debug-info, -T 打印內存和CPU的信息; 
--auto-generate-sql, <span style="color: purple;">-a</span> 自動生成測試表和數據; 
--auto-generate-sql-load-type=type 測試語句的類型. 取值包括read, key, write, update和mixed(默認); 
--number-char-cols=N, <span style="color: purple;">-x</span>  
N 自動生成的測試表中包含多少個字符類型的列, 默認1; 
--number-int-cols=N, -y N 自動生成的測試表中包含多少個數字類型的列, 默認1; 
--number-of-queries=N 總的測試查詢次數(並發客戶端數×每客戶端查詢次數); 
--query=name,<span style="color: purple;">-q</span> 使用自定義腳本執行測試, 例如可以調用自定義的一個存儲過程或者sql語句來執行測試. 
--create-schema 測試的schema, MySQL 中schema也就是database; 
--commint=N 多少條DML後提交一次; 
--compress, -C 如果服務器和客戶端支持都壓縮, 則壓縮信息傳遞; 
--concurrency=N, <span style="color: purple;">-c</span> N 並發量, 也就是模擬多少個客戶端同時執行select. 可指定多個值, 以逗號或者--delimiter參數指定的值做為分隔符; 
--engine=engine_name, <span style="color: purple;">-e</span> engine_name 創建測試表所使用的存儲引擎, 可指定多個; 
--iterations=N, <span style="color: purple;">-i</span> N 測試執行的迭代次數; 
--detach=N 執行N條語句後斷開重連; 
--only-print 只打印測試語句而不實際執行; 
 
連接參數: 

<span style="color: purple;">-u</span>, --user=name User <span style="color: #a52a2a;">for</span> login <span style="color: #a52a2a;">if</span> not current user. 
<span style="color: purple;">-p</span>, --password=name Password to use when connecting to server. 如果密碼沒有給,會通過tty終端請求。 
<span style="color: purple;">-h</span>, --host=name Connect to host. 
-P, --port= Port number to use <span style="color: #a52a2a;">for</span> connection. 

需要說明的是 –concurrency 在實際測試調參中發現,該參數是個假並發參數。 並非是多個客戶端並發,而是一個客戶端進程中指定使用多個線程的參數。 增加該值並不能使壓力上去,也許你發現了。增加線程數,有時候反而會使落到每一台mysql機器上的壓力降下來。

實際測試中如果要壓力上去,需要啟動多個mysqlslap進程進行測試。

(3) 實例說明
在測試前用腳本批量處理了數據,生成不帶cache的select語句

view plaincopy to clipboardprint?
<pre>select SQL_NO_CACHE url_key, value from structqa where url_key <span style="color: #a52a2a;">in</span> (5793176823383938934,1549359593866465909,46398175249572291 39,6858231871203830826);</pre> 

<pre>DB加緩存和不加緩存的壓力大概是1.5倍。</pre> 

<pre>通過監控圖可以看出單進程+cache 和 單進程不加cache的對比:圖中是四台機器的曲線擬合,考慮到dbproxy分片的壓力不均</pre> 
<pre><a href="/wp-content/uploads/2013/06/mysql+cache.png"></a> 
<pre><a href="/wp-content/uploads/2013/06/mysql+cache.png"><img title="mysql+cache" src="/wp-content/uploads/2013/06/mysql+cache-300x160.png" alt="" width="300" height="160"></a>     <a style="font-size: 1.5em;" href="/wp-content/uploads/2013/06/mysql-cache1.png"><img title="mysql-cache" src="/wp-content/uploads/2013/06/mysql-cache1-300x141.png" alt="" width="300" height="141"></a></pre> 
</pre> 

使用時候啟動單個進程的語句如下:

<pre>/home/iknow/local/mysql/bin/mysqlslap  -u***** -p***** -h***.***.***.*** -P3300 --create-schema=**** --query=select_ddbs.sql --concurrency=2 --number-of-queries=6000000 --iterations=2000 --debug-info --engine=innodb ;</pre> 
參數說明: –create-schema 指明要測試的數據庫,否則會報錯 ./bin/mysqlslap: Error when connecting to server: 1045 Auth failed, check your username, password or db

–query 生成的sql語句的文件 –concurrency 使用兩個線程處理 –number-of-queries 本次壓力使用的query數目 –iterations 循環2000次,因為要壓力一段時間,可以手動kill掉 –engine 是innodb的數據庫引擎 –debug-info 會在執行結束的時候打印一些cpu和內存信息。

4. 性能測試

(1)性能因素
1,測試環境

如果是線下機器要盡可能與線上一致

2,測試數據

mysql分為帶緩存和不帶緩存的查詢兩種,線下構造不帶緩存的請求

3,壓力請求

(2)性能指標
【數據庫性能指標】

QPS(TPS):每秒鐘request/事務 數量
並發數: 系統同時處理的request/事務數
響應時間: 一般取平均響應時間

【系統性能指標】

CPU:
idle: 顯示了cpu處在空閒狀態的時間百分比
wa值:wa 列顯示了IO等待所占用的CPU時間的百分比。
這裡wa的參考值為30%,如果wa超過30%,說明IO等待嚴重,這可能是磁盤大量隨機訪問造成的,也可能磁盤或者磁盤訪問控制器的帶寬瓶頸造成的

內存: mysql不用過多關注內存,主要是讀寫操作,涉及到C模塊的要特別關注下,內存洩露最直觀的的表現就是內存隨時間上漲。

IO: 關注下面的指標即可: 上面說的CPu的wa值,以及
util%: 一秒中有百分之多少的時間用於 I/O 操作,或者說一秒中有多少時間 I/O 隊列是非空的.即 delta(use)/s/1000 (因為use的單位為毫秒)如果 %util 接近 100%,說明產生的I/O請求太多,I/O系統已經滿負荷,該磁盤可能存在瓶頸.

(3) 性能場景
綜合性能因素和性能的衡量指標,以及當前的測試目的,構造測試場景 需要模擬線上的場景,本次構造的場景

1,模擬線上小流量

-----簡單壓一下,看當前的系統性能指標,如果小流量都不行,說明系統存在嚴重的性能瓶頸。

2,模擬線上全流量

--- 全流量的模擬要細致,該測試出了測試全流量之外,還可以壓力一晚上,查看系統穩定性,補充穩定性測試。

3, 模擬線上雙倍流量

--考慮到峰值是普通流量的兩倍,以及線上切機房的時候的流量

4,極限壓力測試

需要特別跟DBA和RD確認當前機器沒有對外提供服務,僅供測試使用,而且極限壓力時間不宜過長,一般1~2小時左右

下面來看mysqlslap對MySQL進行壓力測試

我解釋一下一些常用的選項。
這裡要注意的幾個選項:
--concurrency代表並發數量,多個可以用逗號隔開,當然你也可以用自己的分隔符隔開,這個時候要用到--delimiter開關。
--engines代表要測試的引擎,可以有多個,用分隔符隔開。
--iterations代表要運行這些測試多少次。
--auto-generate-sql 代表用系統自己生成的SQL腳本來測試。
--auto-generate-sql-load-type 代表要測試的是讀還是寫還是兩者混合的(read,write,update,mixed)
--number-of-queries 代表總共要運行多少次查詢。每個客戶運行的查詢數量可以用查詢總數/並發數來計算。比如倒數第二個結果2=200/100。
--debug-info 代表要額外輸出CPU以及內存的相關信息。
--number-int-cols 代表示例表中的INTEGER類型的屬性有幾個。
--number-char-cols 意思同上。
--create-schema 代表自己定義的模式(在MySQL中也就是庫)。
--query 代表自己的SQL腳本。
--only-print 如果只想打印看看SQL語句是什麼,可以用這個選項。

現在來看一些我測試的例子。

1、用自帶的SQL腳本來測試。
MySQL版本為5.1.23
[root@localhost ~]# mysqlslap --defaults-file=/usr/local/mysql-maria/my.cnf --concurrency=50,100,200 --iterations=1 --number-int-cols=4 --number-char-cols=35 --auto-generate-sql --auto-generate-sql-add-autoincrement --auto-generate-sql-load-type=mixed --engine=myisam,innodb --number-of-queries=200 --debug-info -uroot -p1 -S/tmp/mysql_3310.sock

Benchmark
        Running for engine myisam
        Average number of seconds to run all queries: 0.063 seconds
        Minimum number of seconds to run all queries: 0.063 seconds
        Maximum number of seconds to run all queries: 0.063 seconds
        Number of clients running queries: 50
        Average number of queries per client: 4

Benchmark
        Running for engine myisam
        Average number of seconds to run all queries: 0.070 seconds
        Minimum number of seconds to run all queries: 0.070 seconds
        Maximum number of seconds to run all queries: 0.070 seconds
        Number of clients running queries: 100
        Average number of queries per client: 2

Benchmark
        Running for engine myisam
        Average number of seconds to run all queries: 0.092 seconds
        Minimum number of seconds to run all queries: 0.092 seconds
        Maximum number of seconds to run all queries: 0.092 seconds
        Number of clients running queries: 200
        Average number of queries per client: 1

Benchmark
        Running for engine innodb
        Average number of seconds to run all queries: 0.115 seconds
        Minimum number of seconds to run all queries: 0.115 seconds
        Maximum number of seconds to run all queries: 0.115 seconds
        Number of clients running queries: 50
        Average number of queries per client: 4

Benchmark
        Running for engine innodb
        Average number of seconds to run all queries: 0.134 seconds
        Minimum number of seconds to run all queries: 0.134 seconds
        Maximum number of seconds to run all queries: 0.134 seconds
        Number of clients running queries: 100
        Average number of queries per client: 2

Benchmark
        Running for engine innodb
        Average number of seconds to run all queries: 0.192 seconds
        Minimum number of seconds to run all queries: 0.192 seconds
        Maximum number of seconds to run all queries: 0.192 seconds
        Number of clients running queries: 200
        Average number of queries per client: 1


User time 0.06, System time 0.15
Maximum resident set size 0, Integral resident set size 0
Non-physical pagefaults 5803, Physical pagefaults 0, Swaps 0
Blocks in 0 out 0, Messages in 0 out 0, Signals 0
Voluntary context switches 8173, Involuntary context switches 528


我來解釋一下結果的含義。
拿每個引擎最後一個Benchmark示例。
對於INNODB引擎,200個客戶端同時運行這些SQL語句平均要花0.192秒。相應的MYISAM為0.092秒。

2、用我們自己定義的SQL 腳本來測試。
這些數據在另外一個MySQL實例上。版本為5.0.45
先看一下這兩個表的相關數據。
1)、總記錄數。
mysql> select table_rows as rows from information_schema.tables where table_schema='t_girl' and table_name='article';
+--------+
| rows   |
+--------+
| 296693 |
+--------+
1 row in set (0.01 sec)

mysql> select table_rows as rows from information_schema.tables where table_schema='t_girl' and table_name='category';
+------+
| rows |
+------+
| 113  |
+------+
1 row in set (0.00 sec)

2)、總列數。
mysql> select count(*) as column_total from information_schema.columns where table_schema = 't_girl' and table_name = 'article';
+--------------+
| column_total |
+--------------+
| 32           |
+--------------+
1 row in set (0.01 sec)

mysql> select count(*) as column_total from information_schema.columns where table_schema = 't_girl' and table_name = 'category';
+--------------+
| column_total |
+--------------+
| 9            |
+--------------+
1 row in set (0.01 sec)


3)、調用的存儲過程
DELIMITER $$

DROP PROCEDURE IF EXISTS `t_girl`.`sp_get_article`$$

CREATE DEFINER=`root`@`%` PROCEDURE `sp_get_article`(IN f_category_id int,
 IN f_page_size int, IN f_page_no int
)
BEGIN
  set @stmt = 'select a.* from article as a inner join ';
  set @stmt = concat(@stmt,'(select a.aid from article as a ');
  if f_category_id != 0 then
    set @stmt = concat(@stmt,' inner join (select cid from category where cid = ',f_category_id,' or parent_id = ',f_category_id,') as b on a.category_id = b.cid');
  end if;
  if f_page_size >0 && f_page_no > 0 then
    set @stmt = concat(@stmt,' limit ',(f_page_no-1)*f_page_size,',',f_page_size);
  end if;
 
  set @stmt = concat(@stmt,') as b on (a.aid = b.aid)');
  prepare s1 from @stmt;
  execute s1;
  deallocate prepare s1;
  set @stmt = NULL;
END$$

DELIMITER ;
4)、我們用mysqlslap來測試
以下得這個例子代表用mysqlslap來測試並發數為25,50,100的調用存儲過程,並且總共調用5000次。
[root@localhost ~]# mysqlslap --defaults-file=/usr/local/mysql-maria/my.cnf --concurrency=25,50,100 --iterations=1 --query='call t_girl.sp_get_article(2,10,1);' --number-of-queries=5000 --debug-info -uroot -p -S/tmp/mysql50.sock
Enter password:
Benchmark
        Average number of seconds to run all queries: 3.507 seconds
        Minimum number of seconds to run all queries: 3.507 seconds
        Maximum number of seconds to run all queries: 3.507 seconds
        Number of clients running queries: 25
        Average number of queries per client: 200
平均每個並發運行200個查詢用了3.507秒。
Benchmark
        Average number of seconds to run all queries: 3.742 seconds
        Minimum number of seconds to run all queries: 3.742 seconds
        Maximum number of seconds to run all queries: 3.742 seconds
        Number of clients running queries: 50
        Average number of queries per client: 100

Benchmark
        Average number of seconds to run all queries: 3.697 seconds
        Minimum number of seconds to run all queries: 3.697 seconds
        Maximum number of seconds to run all queries: 3.697 seconds
        Number of clients running queries: 100
        Average number of queries per client: 50


User time 0.87, System time 0.33
Maximum resident set size 0, Integral resident set size 0
Non-physical pagefaults 1877, Physical pagefaults 0, Swaps 0
Blocks in 0 out 0, Messages in 0 out 0, Signals 0
Voluntary context switches 27218, Involuntary context switches 3100


看一下SHOW PROCESSLIST 結果
mysql> show processlist;
+------+------+--------------------+--------------------+---------+-------+--------------------+------------------------------------------------------------------------------------------------------+
| Id   | User | Host               | db                 | Command | Time  | State              | Info                                                                                                 |
+------+------+--------------------+--------------------+---------+-------+--------------------+------------------------------------------------------------------------------------------------------+
…………
| 3177 | root | %                  | t_girl             | Query   |     0 | NULL               | select a.* from article as a inner join (select a.aid from article as a  inner join (select cid from |
| 3178 | root | %                  | t_girl             | Query   |     0 | NULL               | select a.* from article as a inner join (select a.aid from article as a  inner join (select cid from |
| 3179 | root | %                  | t_girl             | Query   |     0 | NULL               | select a.* from article as a inner join (select a.aid from article as a  inner join (select cid from |
| 3181 | root | %                  | t_girl             | Query   |     0 | NULL               | select a.* from article as a inner join (select a.aid from article as a  inner join (select cid from |
| 3180 | root | %                  | t_girl             | Query   |     0 | NULL               | select a.* from article as a inner join (select a.aid from article as a  inner join (select cid from |
| 3182 | root | %                  | t_girl             | Query   |     0 | NULL               | select a.* from article as a inner join (select a.aid from article as a  inner join (select cid from |
| 3183 | root | %                  | t_girl             | Query   |     0 | NULL               | select a.* from article as a inner join (select a.aid from article as a  inner join (select cid from |
| 3187 | root | %                  | t_girl             | Query   |     0 | removing tmp table | select a.* from article as a inner join (select a.aid from article as a  inner join (select cid from |
| 3186 | root | %                  | t_girl             | Query   |     0 | NULL               | select a.* from article as a inner join (select a.aid from article as a  inner join (select cid from |
| 3194 | root | %                  | t_girl             | Query   |     0 | NULL               | select a.* from article as a inner join (select a.aid from article as a  inner join (select cid from |
| 3203 | root | %                  | t_girl             | Query   |     0 | NULL               | deallocate prepare s1                                                                                |
…………
| 3221 | root | %                  | t_girl             | Query   |     0 | NULL               | select a.* from article as a inner join (select a.aid from article as a  inner join (select cid from |
| 3222 | root | %                  | t_girl             | Query   |     0 | NULL               | select a.* from article as a inner join (select a.aid from article as a  inner join (select cid from |
| 3223 | root | %                  | t_girl             | Query   |     0 | NULL               | select a.* from article as a inner join (select a.aid from article as a  inner join (select cid from |
| 3224 | root | %                  | t_girl             | Query   |     0 | removing tmp table | select a.* from article as a inner join (select a.aid from article as a  inner join (select cid from |
| 3225 | root | %                  | t_girl             | Query   |     0 | NULL               | select a.* from article as a inner join (select a.aid from article as a  inner join (select cid from |
| 3226 | root | %                  | t_girl             | Query   |     0 | NULL               | select a.* from article as a inner join (select a.aid from article as a  inner join (select cid from |
+------+------+--------------------+--------------------+---------+-------+--------------------+------------------------------------------------------------------------------------------------------+
55 rows in set (0.00 sec)

上面的測試語句其實也可以這樣寫

[root@localhost ~]# mysqlslap --defaults-file=/usr/local/mysql-maria/my.cnf --concurrency=25,50,100 --iterations=1 --create-schema='t_girl' --query='call sp_get_article(2,10,1);' --number-of-queries=5000 --debug-info -uroot -p -S/tmp/mysql50.sock

小總結一下。
mysqlslap對於模擬多個用戶同時對MySQL發起“進攻”提供了方便。同時詳細的提供了“高負荷攻擊MySQL”的詳細數據報告。
而且如果你想對於多個引擎的性能。這個工具再好不過了。

copyright © 萬盛學電腦網 all rights reserved