はじめに

こんにちは、株式会社スマートスタイルの中野です。

この記事は、以前投稿した『さくらの専用サーバでベンチマークを実施してみた ~ スコア編 ~』で実施したベンチマークの手順や注意点を紹介するものです。今後、MySQLのベンチマーク試験を実施しようと思っている方の参考になれば幸いです。

試験全体の流れ

前回の記事にも記載しましたが、今回のベンチマーク試験は以下のような流れで実施しています。

1. Flashストレージのマウント、カーネル設定の変更(専用サーバのみ)
2. DBサーバに MySQL5.7.18 と Percona XtraBackup2.4.8 をインストール
3. 計測サーバに Sysbench 1.0 をインストール
4. Sysbenchのデータロード実行
5. XtraBackupで全体バックアップを取得
6. ベンチマーク用のmy.cnfを設定
7. Sysbenchのベンチマークを実行
8. MySQLを停止し、XtraBackupの全体バックアップをリストア
9. 6.に戻る/strong>

それでは、ステップ単位で切り取って詳細を見ていきましょう。

1. Flashストレージのマウント、カーネル設定の変更(専用サーバのみ)

※以下は専用サーバのみで実施した手順となります

最初に、用意して頂いたFlashストレージの設定(マウント)を行います。
今回の環境では、/data/にマウントしてその配下にMySQLのデータディレクトリを作成します。

# fdisk -c -u /dev/nvme0n1 

Command (m for help): n     ### "n" を入力
Command action              ### "p" を入力、以下デフォルトで設定
   e   extended
   p   primary partition (1-4)  
... omitted ...
Command (m for help): w
The partition table has been altered!

# yum install -y xfsprogs
# mkfs.xfs -b size=4k /dev/nvme0n1p1     ### xfsでファイルシステムを作成
# mkdir /data/
# mount -o nobarrier,noatime,discard /dev/nvme0n1p1 /data           ### マウントオプションは任意
# mount
... omitted ...
/dev/nvme0n1p1 on /data type xfs (rw,noatime,nobarrier,discard)     ### 正常にマウントされていることを確認

次にFlashストレージの性能を最大限引き出すため、一部のカーネル設定を変更します。

(1) CPUガバナーの変更

CPUの電力消費(クロック数)と発生熱量、ひいてはパフォーマンスを制御するLinux側のパラメータ。

# yum install -y cpufrequtils

# cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor     ### デフォルトは"ondemand"
ondemand
ondemand
... omitted ...

# for i in `seq 0 39` \
 do \
   cpufreq-set -c $i -g performance \
 done

# cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor     ### すべて"performance"に変更されたことを確認
performance
performance
... omitted ...

(2) I/Oスケジューラの変更

アプリケーション(MySQL)から発行されたI/O命令を並び替える(スケジューリング)する時のルールを決める機能。

# cat /sys/block/sda/queue/scheduler     ### デフォルトは"cfq"
noop anticipatory deadline [cfq] 

# echo "noop" | tee /sys/block/sda/queue/scheduler     ### "noop" もしくは "deadlineに変更"
noop

# cat /sys/block/sda/queue/scheduler                       
[noop] anticipatory deadline cfq

2. DBサーバに MySQL5.7.18 と Percona XtraBackup2.4.8 をインストール

※ここからは専用サーバ、クラウドサーバ共通の手順となります。

ベンチマークの対象となるDBサーバに、MySQL5.7.18をインストールします。以下はCentOS6.9のDBサーバを想定した手順ですが、使用するディストリビューションやバージョンによって使用するリポジトリなどは変更してください。

# yum remove -y mysql-libs     ### プリインストールされているMySQLを削除する
# yum install http://dev.mysql.com/get/mysql57-community-release-el6-11.noarch.rpm     ### 6系向けのMySQLリポジトリをインストール
# yum install -y mysql-community-server mysql-community-libs-compat perl-DBD-MySQL
... omitted ...
Installed:
  mysql-community-libs-compat.x86_64 0:5.7.18-1.el6                                 
  mysql-community-server.x86_64 0:5.7.18-1.el6                                      
  perl-DBD-MySQL.x86_64 0:4.013-3.el6                                               

Dependency Installed:
  mysql-community-client.x86_64 0:5.7.18-1.el6                                      
  mysql-community-common.x86_64 0:5.7.18-1.el6                                      
  mysql-community-libs.x86_64 0:5.7.18-1.el6 

次に、MySQLのバックアップを取得するためのツール Percona XtraBackup をインストールします。

# yum install -y epel-release     ### epelのリポジトリ
# yum install -y http://www.percona.com/downloads/percona-release/redhat/0.1-4/percona-release-0.1-4.noarch.rpm     ### Perconaのリポジトリ
# yum install -y percona-xtrabackup-24
... omitted ...
Installed:
  percona-xtrabackup-24.x86_64 0:2.4.7-1.el6

Dependency Installed:
  libev.x86_64 0:4.03-3.el6

また、多くの同時接続数のベンチマークを実行する場合は、同時接続に耐えられるよう一部のカーネル設定を調整します(設定値は目安)。

# sysctl -w net.core.somaxconn=3000
# sysctl -w net.ipv4.tcp_max_syn_backlog=3000
# sysctl -p

次に、MySQLを起動します。専用サーバはデータディレクトリがデフォルト(/var/lib/mysql)と異なるため、初期化も必要です。

# mv /etc/my.cnf /etc/my.cnf.org
# cp /tmp/flash_my.cnf /etc/my.cnf
# mkdir -p /data/mysql/data /data/mysql/log
# chown -R mysql:mysql /data/
# mysqld --defaults-file=/etc/my.cnf --initialize --user=mysql
# service mysqld start

※ 使用するmy.cnfは以下の内容です。クラウドサーバでも datadir や ログのPATH 以外は同じものを使用しています。
なお、意図的にあえて低い設定値にしているパラメータ変数もあります

[mysqld]

### General ###
datadir            = /data/mysql/data/
server_id          = 100
max_connections    = 3000
back_log           = 1200
max_allowed_packet = 4M
performance_schema = ON
skip_name_resolve
query_cache_size   = 0
query_cache_type   = OFF
max_prepared_stmt_count = 300000

### Log ###
log_bin         = "/data/mysql/log/mysql-bin"         # comment out when loading test data
log_bin_index   = "/data/mysql/log/mysql-bin-index"   # comment out when loading test data
sync_binlog     = 1
binlog_format   = STATEMENT
max_binlog_size = 1G
slow_query_log  = ON
long_query_time = 1
log_error       = /data/mysql/log/mysqld.err
log_timestamps  = SYSTEM

### InnoDB ###
innodb_io_capacity             = 200
innodb_io_capacity_max         = 2000
skip-innodb_doublewrite
innodb_buffer_pool_size        = 64G
innodb_log_file_size           = 512M     # Small log files, more page flush
innodb_log_files_in_group      = 2
innodb_log_buffer_size         = 8M
innodb_flush_method            = O_DIRECT
innodb_flush_log_at_trx_commit = 1
innodb_file_per_table          = 1
transaction_isolation            = REPEATABLE-READ
innodb_thread_concurrency      = 0
innodb_write_io_threads        = 10
innodb_lru_scan_depth          = 5000
innodb_flush_neighbors         = 0
innodb_read_ahead_threshold    = 0
innodb_purge_threads           = 4
innodb_page_cleaners           = 4
innodb_adaptive_hash_index     = 0
innodb_numa_interleave         = ON
innodb_buffer_pool_dump_at_shutdown = 0
innodb_buffer_pool_load_at_startup  = 0
skip-innodb_doublewrite

### For unifying as Aurora setting ###

core_file
gtid_mode                      = OFF
enforce_gtid_consistency       = OFF
eq_range_index_dive_limit      = 10
explicit_defaults_for_timestamp = ON
host_cache_size                = 128
binlog_checksum                = CRC32
innodb_buffer_pool_instances   = 8
innodb_change_buffering        = none
innodb_checksum_algorithm      = none
innodb_checksums               = OFF
innodb_file_format             = Antelope
innodb_file_format_max         = Antelope
innodb_large_prefix            = OFF
innodb_open_files              = 6000
innodb_purge_batch_size        = 900
innodb_purge_threads           = 3
innodb_read_io_threads         = 16
innodb_strict_mode             = OFF
innodb_use_native_aio          = OFF
key_buffer_size                = 16M
log_output                     = TABLE
log_warnings                   = 1
open_files_limit               = 65535
read_buffer_size               = 256K
read_rnd_buffer_size           = 512K
relay_log_recovery             = ON
relay_log_space_limit          = 1000000000
slave_net_timeout              = 3600
sql_mode                       = ""
table_definition_cache         = 20000
table_open_cache               = 6000
thread_cache_size              = 58

MySQLが問題なくインストールで来たら、sysbench用のデータベース、ユーザを作成しておきます。

# cat /data/mysql/log/mysqld.err | grep temporary
2017-05-29T19:26:39.654417+09:00 1 [Note] A temporary password is generated for root@localhost: aIY0(gLPiKkJ

# mysql -u root -paIY0(gLPiKkJ -S /data/mysql/data//mysql.sock

mysql> SET PASSWORD = "Password";
mysql> CREATE DATABASE sbtest;
mysql> GRANT ALL ON *.* TO sbuser@`%` IDENTIFIED BY "sbpass"; 
mysql> exit

3. 計測サーバに Sysbench 1.0 をインストール

今回の検証では、DBサーバの他に計測サーバを用意してそこからsysbenchを実行しています。そのため、sysbench1.0は計測サーバにインストールします。なお、計測サーバでは Ubuntu16.04 を使用していますが、CentOSでも問題はありません。

# wget https://repo.percona.com/apt/percona-release_0.1-4.$(lsb_release -sc)_all.deb     ### Perconaのリポジトリ
# dpkg -i percona-release_0.1-4.$(lsb_release -sc)_all.deb
# apt-get update
# apt-get install -y sysbench     ### sysbench1.0系の最新版がインストールされる
... omitted ...

また、sysbenchが使用するMySQLクライアントと、ベンチマークの実行時に便利なscreenも併せてインストールします。
以降の作業は、screen(仮想コンソール)上で実施します。

# apt-get install -y mysql-client screen
# screen     ### 仮想コンソールで作業すれば、不慮の接続断があっても処理が継続できる

4. Sysbenchのデータロード実行

sysbenchのデータロードを実行します。専用サーバで実行した場合は、およそ300分(=5時間)ほどかかりました。

# sysbench /usr/share/sysbench/oltp_read_write.lua --db-driver=mysql \
   --table-size=25000000 --tables=60 --mysql-host=192.168.20.20 \
   --mysql-user=sbuser --mysql-password=sbpass prepare
... omitted ...

5. XtraBackupで全体バックアップを取得

データロード直後の状態の全体バックアップを取得します。こちらも専用サーバで実行した場合は、およそ40分ほどかかりました。

# mkdir -p /data/backup_0606
# time innobackupex --user=root --password=Password \
   /data/backup_0606 --no-timestamp
... omitted ...
# innobackupex --apply-log /data/backup_0606
... omitted ...

また、このバックアップをそのままクラウドサーバに転送することで「同じデータ」を用いたベンチマークが可能となります。

テストを自動実行するスクリプトを作成

ここまでの作業でベンチマークの準備はできましたので、これ以降はひたすらsysbenchの実行を繰り返していきます。そのため、以下の手順については自動実行するスクリプトを作成し、計測サーバ上に配置します。

6. ベンチマーク用のmy.cnfを設定
7. Sysbenchのベンチマークを実行
8. MySQLを停止し、XtraBackupの全体バックアップをリストア
9. 6.に戻る/strong>

スクリプトの注意点としては、DBサーバで実行する必要があるコマンド(XtraBackupのリストアなど)は、ssh経由でDBサーバ上のユーザとして実行しています。その際、パスワード認証をスルーするため sshpass を利用していますが、こちらはパスワード認証無しのSSH鍵認証などでも問題はありません。

【スクリプトの実行方法】
以下3つの引数を指定して、スクリプトファイルを実行して下さい。その際、標準出力+エラー出力を別途ログにリダイレクトすると何か問題が発生した時の調査がしやすくなります。この引数で指定した内容に合わせた名称で、sysbench の実行結果が/bench_result/ の下に出力されます。

・$1 : 使用するmy.cnfファイルの名前(例:/tmp/default_my.cnf であれば “default”を指定)
・$2 : sysbenchの同時接続数を指定する(今回は 8/16/32/64/128/512 の6パターン実行する)
・$3 : 何回目のテストかを指定する(同じテストを2回ずつ実行する場合は 1 or 2 となる)

# mkdir /bench_result/
# ./auto_sysbench.sh edit 64 2     ### 編集済みのmy.cnfを使い、64接続のsysbenchの、2回目実行

【スクリプトの内容】

#!/bin/bash -eu

cnf=$1
thread=$2
count=$3

echo -e "Start shell script !\n"
date

echo -e "Start restore backup.\n"

sshpass -p 'rootpass' ssh root@ rm -rf /data/mysql/data/*
sshpass -p 'rootpass' ssh root@ time innobackupex --copy-back /data/backup_0606/
sshpass -p 'rootpass' ssh root@ chown -R mysql:mysql /data/mysql/data/
sshpass -p 'rootpass' ssh root@ cp -f /tmp/${cnf}_my.cnf /etc/my.cnf
sshpass -p 'rootpass' ssh root@ service mysqld start
sleep 10m

echo -e "Finish restore backup !\n"
echo -e "Start sysbench.\n"

function main() {
        trap catch ERR
        sysbench /usr/share/sysbench/oltp_read_write.lua --db-driver=mysql  --table-size=25000000 --tables=60 --mysql-host=  --threads=${thread} --time=1800 --report-interval=30 --mysql-user=sbuser --mysql-password=sbpass run 2>&1 >> /bench_result/result_${cnf}_${thread}_${count}_`date "+%m%d_%H%M"`.log
        return 0
}

function catch() {
        echo -e "sysbench Failed...\n"
}
function finally() {
        echo -e "Finish sysbench !\n"
}

# Entry Point
set -eu
trap catch ERR
trap finally EXIT
main

sshpass -p 'rootpass' ssh root@ service mysqld stop

echo -e "Finish shell script !\n"
date

【スクリプトの内容】

スクリプトでは以下のような処理を行っています。なお、実行時DBサーバのMySQLは停止している必要があります。

(1) DBサーバのデータディレクトリを全て削除
(2) XtraBackupでデータロード時のバックアップをリストア
(3) リストア後のデータディレクトリのパーミッション変更(リストア後は root:root になっています)
(4) 使用する my.cnf を配置
(5) MySQLを起動
(6) sysbenchを実行
(7) MySQLを停止

あとは、必要なシナリオに合わせてスクリプトの実行を繰り返せばベンチマークは終了となります。

最後に

弊社スマートスタイルでも、MySQLに関連する技術情報を発信するためのブログを運営しています。もし興味があれば是非アクセスしてみてください。

スマートスタイル TECH BLOG