今日はなにの日。

気になったこと勉強になったことのメモ。

今日は、前から気になってたmysqlslap を使ってみるの日。

目次

とある日

仕事で、MySQLのデータベースに対してベンチマークをしたいなと思いました。

そこで前々から気になってた「mysqlslap」を試してみました。

今回は、「mysqlslap」を使ってみようという内容です。

mysqlslapとは

mysqlslapMySQL サーバーのクライアント負荷をエミュレートし、各段階のタイミングをレポートする診断プログラムです。

MySQL :: MySQL 8.0 リファレンスマニュアル :: 4.5.8 mysqlslap — ロードエミュレーションクライアント

はじめは、任意のデータベースのテーブルに対してSQLを好きに実行して負荷をかけられるものだと認識していましたが違うみたいです。

mysqlslap専用のデータベースに仮のテーブルを作成してオプションにあったSQLを実行して負荷を計るようです。

mysqlslap は以下の 3 段階で実行されます。

  1. テストに使用するスキーマ、テーブル、およびオプションでストアドプログラムまたはデータを作成します。
  2. 負荷テストを実行します。
  3. クリーンアップ (接続の解除、指定した場合はテーブルの削除) を実行します。

使ってみた

テーブルを作成してSQLを実行することもできるみたいですが、今回はシンプルな使い方をしてみます。

実行環境

docker composeを使って、負荷をかけるコンテナと負荷をかけられるコンテナの2つを用意します。

version: "3"

services:
  slap:
    image: diceone/mysqlslap
    container_name: mysqlslap
  db:
    image: mysql:8.0.33
    container_name: mysqlloadtest
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: test
      MYSQL_USER: docker
      MYSQL_PASSWORD: docker
      TZ: "Asia/Tokyo"
    command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
    volumes:
      - ../../MySQL/settings/my.cnf:/etc/mysql/conf.d/my.cnf
      - ../../MySQL/settings/mylogin.sh:/root/mylogin.sh

手順

  1. MySQL 8.0.33コンテナ起動
  2. mysqlslapコマンドを実行

MySQL 8.0.33コンテナ起動

MySQLLoadTest> docker-compose up -d
[+] Running 2/2
 - Container mysqlloadtest  Running                                                                                                                                                                         0.0s
 - Container mysqlslap      Started                                                                                                                                                                         0.4s
MySQLLoadTest> docker ps
CONTAINER ID   IMAGE                  COMMAND                  CREATED         STATUS        PORTS                       NAMES
3cc2fe3af3ec   mysql:8.0.33           "docker-entrypoint.s…"   3 hours ago     Up 3 hours    3306/tcp, 33060/tcp         mysqlloadtest

この際、IPアドレスをメモっておく。

(dockerのネットワーク見なくてもhostsファイル見ればいいの初めて知りました)

MySQLLoadTest> docker-compose exec db bash
bash-4.4#  cat /etc/hosts
127.0.0.1       localhost
::1     localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
192.168.16.3    3cc2fe3af3ec

このコンテナなのデータベース(192.168.16.3)に対して接続を行います。

mysqlslapコマンドを実行

mysqlslapのコンテナは常時起動しないので起動コマンドと一緒にmysqlslapコマンドを実行します。

(PowerShellで実行しているのでバッククォートで区切ってます)

docker compose run slap `
mysqlslap  --no-defaults --auto-generate-sql `
--engine=innodb --auto-generate-sql-add-autoincrement  `
--host=192.168.16.3 --port=3306 -u root -proot `
--number-int-cols=10  --number-char-cols=10  --iterations=10  --concurrency=50  `
--auto-generate-sql-write-number=10  --number-of-queries=10  --auto-generate-sql-load-type=read

待ってると結果が表示される。

MySQLLoadTest>docker compose run slap `
>> mysqlslap  --no-defaults --auto-generate-sql `
>> --engine=innodb --auto-generate-sql-add-autoincrement  `
>> --host=192.168.16.3 --port=3306 -u root -proot `
>> --number-int-cols=10  --number-char-cols=10  --iterations=10  --concurrency=50  `
>> --auto-generate-sql-write-number=10  --number-of-queries=10  --auto-generate-sql-load-type=read
Benchmark
        Running for engine innodb
        Average number of seconds to run all queries: 0.018 seconds
        Minimum number of seconds to run all queries: 0.016 seconds
        Maximum number of seconds to run all queries: 0.027 seconds
        Number of clients running queries: 50
        Average number of queries per client: 0

コマンドオプション

先程使用したオプション一覧

オプション名 説明
--no-defaults オプションファイルを読み取らない
--auto-generate-sql SQL ステートメントがファイルおよびコマンドオプションを使用して指定されない場合、自動的に生成
--engine テーブルの作成に使用するストレージエンジン
--auto-generate-sql-add-autoincrement AUTO_INCREMENT カラムを自動生成されたテーブルに追加
--host MySQL サーバーがあるホスト
--port 接続用の TCP/IP ポート番号
--user サーバーへの接続時に使用する MySQL ユーザー名
--password サーバーに接続する際に使用するパスワード
--number-int-cols --auto-generate-sql が指定された場合に使用する INT カラムの数
--number-char-cols --auto-generate-sql が指定された場合に使用する VARCHAR カラムの数
--iterations 実行するテストの回数
--concurrency SELECT ステートメントを発行する際、シミュレートするクライアントの数
--auto-generate-sql-write-number 各スレッドで実行する行挿入の回数
--number-of-queries 各クライアントのクエリー数をおよそこの数に制限
--auto-generate-sql-load-type テストの負荷タイプを指定します

オプションの区分け

  • 負荷先の設定
    • --host
    • --port
    • --user
    • --password
  • 負荷をかける環境の設定
    • --engine
  • 負荷設定
    • --iterations
    • --concurrency
    • --auto-generate-sql-load-type
    • --no-defaults
    • --auto-generate-sql
  • 負荷SQLの設定
  • --auto-generate-sql-add-autoincrement
  • --number-int-cols
  • --number-char-cols
  • --auto-generate-sql-write-number
  • --number-of-queries

重要なオプションの解説

--auto-generate-sql-load-type

テストの負荷タイプを指定します。 許可される値は、read (テーブルのスキャン)、write (テーブルに挿入)、key (主キーの読み取り)、update (主キーの更新)、または mixed (挿入とスキャンして選択が半分ずつ) です。 デフォルトは mixed です。

実行されるSQLが異なります。

general_logを取得して確認します。

readの場合

SELECT intcol1,charcol1 FROM t1

writeの場合

INSERT INTO t1 VALUES (NULL,1674308135,'TKiz9ItDX763hOQSRIxHlEKHK5dY8NzTbhSkrLpELw9uCbMftKoXQ8gnDHBDZAi8rBlaOagdWpYbGm616vYPvC41MFEvPx380oaGFEmd3ICB4JC36dS1pY23f9ywyu')

keyの場合

SELECT id from t1

updateとmixedは結果変わらなかったので割愛します。

おそらく実行数が少ないとできないのかなと推測しています。

--concurrency

同時実行数を制御できます。

mysqlslap実行中にprocesslist見れば実行数が確認できます。

ただ、一回のクエリの時間が短いのでこの値を増やすことで確認できます。

(root@localhost) [mysql] 8.0.33 > show full processlist\G;
*************************** 1. row ***************************
     Id: 5
   User: event_scheduler
   Host: localhost
     db: NULL
Command: Daemon
   Time: 13448
  State: Waiting on empty queue
   Info: NULL
*************************** 2. row ***************************
     Id: 2976
   User: root
   Host: localhost
     db: mysql
Command: Query
   Time: 0
  State: init
   Info: show full processlist
*************************** 3. row ***************************
     Id: 6094
   User: root
   Host: 192.168.16.2:39572
     db: mysqlslap
Command: Query
   Time: 0
  State: waiting for handler commit
   Info: INSERT INTO t1 VALUES (NULL,611402892,64686043,530048534,839439115,1615664209,791065520,1798982550,553597150,776664701,895488819,'S5pGAuJYH512qcYWEeb9FnsTjap5kMc4SPLWCY2LdvNKYoieQHoh5Y2g6sdiEDnaW0xiYr41nJDJ7vxaDd7A2Aq8uJj0YWR2MOduFhn2s1D0w3Q1YPBabtbLCIMkgh','f25GoCxb7hcKhPFzQoPeEsXpEczSKf9zZ67LIwpPePeJqtBHZcngKATQmLuzsvqQ1yfCuSdOm7cS1ndQFO6bRS25powhknzddXhNrJodIOyJBbeQsktJCvGtcDRCsQ','hTpNkhaYAso84rki9cQ3nXq3GQ8jW0ACTrbEY1ejtRrxIRXS3qXiDDeTYmD2nFEG6hMfi1ESK5HeZpySXLBkbpD7RQ9EZGNgplBOePsyW1TvqRODpRxG83NbTOivY5','bMimmLBWJZXoTE8lRx4PD4SSXpsDkPABftxPE0nPaI6vYEY03cH8Ydc3IK9vdJ6G4wZAwKSMfaH3ghvjHCrhhJlsfmfHxlP2Zz4MBYci6umeRhLlm4IJNvBvhqCXST','PtSTFg2kE0e0fxisiKptf4ojzWZ3ttZIntnuPhega8g56EpgQeZ6jEhak6Wd03nfwaPMG4ui4Qn2hcjzF85qMeGylmRlpEGehhspdmXiCIkluJl1KiriL0ZymsjS7r','6gYqTAS0sYISA4gv60Txaip7gcsF4r62XXk0hC0PkAlmEPhKP3AsdzzIbjPXaOP5v95SLxly7WkMoIa5Dkxqcp03YQb7isCT2AxF7aD74qLk0vqDYn38cwB9Me8wXC','PPMMgMwmTsSqTSdJh96cHbYLcmrkaEwzfBDCZ1qumIkFmDaJNYvY7KlbydBZj0YFBeRcfHWPb6gDJEYafJ7eXsEWLPv5PJKSxf4dwQ2NObcch0AKJ9zj25DNM0KgJg','8HB5u7XoMoNqO5qQH2c8lWDqlSq689eGIqL4pltCP82h5t7NnjXY5dMr5CxDDbLYHjS7KDBlMDQJyPil16H6jXxgbutpMEDXpZe1npm9v4StW3XX1oTcCRGnD1Sb7Z','7p7dquJTvEZFzvIWIBBonN73AK4Xo44ntBGjxbCspe8hPIBkWMOHdNDoj9BNDFAyJRiGum9cO9HiJSIhjarKx40g5BwBRy9ePjuCWvomw5SGPex0CgL9kLiiPetkcu','MueG684mm0j788ly9yeM7Fbhp0Jikoc6a6Fg6BIt31sC9d2ARYYRn88c0KAl0fjalq6k1OTxPL9Qq3TAbtdNtdrupuXhZ6FApDmqdFnuSoDJraLRRqiLRP79Jeqkcy')
3 rows in set (0.00 sec)

はじめにイメージしていた使い方ではなかったですが、すごく手軽に試せることがわかりました。

Amazon AuroraにR7gが来たので試してみたいなと思います。

参考記事

実際のワークロードに近いSQLの負荷テストをmysqlslapのような感覚で行う方法を考える - GMOインターネットグループ グループ研究開発本部(次世代システム研究室)

MySQL を使って EC2 r6g.large vs r5.large(mysqlslap 対決)をやってみた - Qiita

Dockerでコンテナの内部IPを調べる - Qiita

MySQL :: MySQL 8.0 リファレンスマニュアル :: 4.5.8 mysqlslap — ロードエミュレーションクライアント

mysqlslapによるmysqlベンチマーク解説 - Qiita

mysqlslap で MySQL の負荷エミュレーションをしてみる - エキサイト TechBlog.