推測はやめて計測を:sysbenchによるMySQLとPostgreSQLの負荷テスト

Database tutorial - IT technology blog
Database tutorial - IT technology blog

データベース・スケーリングの盲点

私の経験上、本番環境でのトラブルが単純なロジックエラーに起因することは稀です。通常、それは負荷に耐えきれなくなったデータベースが原因です。開発中に5msで実行されるクエリも、200人の同時実行ユーザーが同じエンドポイントにアクセスすると、簡単に2,000msまで膨れ上がります。多くのチームは、データベースのキャパシティを「推測」で扱っています。サーバーが遅く「感じる」からという理由で、確かなデータに基づかずに大きなインスタンスへスケールアップしてしまうのです。

真の原因は、ベースラインの欠如にあります。負荷テストを行わなければ、ボトルネックがディスクI/Oなのか、CPUの競合なのか、あるいはバッファプールの設定ミスなのかを判断することはできません。ベンチマークはこの状況を一変させます。制御された環境でデータベースを限界まで追い込むことで、性能の限界(天井)がどこにあるのかを正確に特定できるようになります。

ベンチマーク戦略の選択

コマンドを実行する前に、すべてのベンチマークが同じ目的を果たすわけではないことを覚えておいてください。私は通常、ベンチマークを以下の3つのアプローチに分類しています。

1. 合成ベンチマーク (sysbench)

この手法では、標準化されたスクリプトを使用してOLTP(オンライン・トランザクション処理)ワークロードをシミュレートします。AWSのgp2からgp3ボリュームへの移行がコストに見合うかどうかのテストや、クリーンな環境での設定パラメータの微調整など、ハードウェアの比較におけるゴールドスタンダードです。

2. アプリケーションレベル의 負荷テスト (K6/JMeter)

これらのツールは、APIレイヤーからORMに至るまで、スタック全体をテストします。これは実際のユーザー体験を反映しますが、データベースのパフォーマンスのみを分離して評価するのは困難です。ネットワークのオーバーヘッドやアプリケーションロジックが結果を曖昧にすることが多いためです。

3. トラフィックリプレイ

本番環境の実際のクエリをキャプチャし、ステージング環境で再現する手法です。最も正確な方法ですが、セットアップの複雑さが高く、専門的なツールが必要になることがよくあります。

私は90%のシナリオでsysbenchを採用します。新しいRDSインスタンスの検証であれ、カスタムのPostgreSQL設定であれ、客観的な判断を下すために必要な、スクリプト化可能な生のメトリクスを提供してくれるからです。

sysbench のメリットとデメリット

  • メリット: 2分以内にセットアップ可能です。MySQL、PostgreSQL、さらにはOracleもサポートしています。最も重要なのは、平均値では隠れてしまいがちな詳細なレイテンシのパーセンタイル(95thや99th)を提供してくれる点です。
  • デメリット: デフォルトのスクリプトは汎用的です。特定の12テーブル結合や、アプリが依存している複雑な再帰的CTEなどをシミュレートすることはできません。

理想的なテスト環境

本番環境のデータベースに対して負荷テストを実行してはいけません。ユーザーのリソースを奪うことになります。代わりに、本番環境のハードウェアを正確に模倣した隔離されたインスタンスを立ち上げてください。AWSを使用している場合は、インスタンスクラス(例:db.m5.large)とEBSボリュームの設定(例:3,000プロビジョンドIOPS)を一致させます。

データの管理も重要です。セットアップ中にCSVデータセットを構成マッピング用のJSONに素早く変換する必要がある場合、私は toolcraft.app/ja/tools/data/csv-to-json を使用しています。ブラウザ内ですべてを処理するため、機密性の高い構成データがマシンから流出することはありません。

実装ガイド:MySQLの負荷テスト

負荷を生成するだけで数個のCPUコアを消費することがあるため、sysbenchは専用のテスト実行用マシンにインストールしてください。データベースサーバー自体で実行してはいけません。

# Ubuntu/Debianの場合
sudo apt-get update
sudo apt-get install sysbench

ステップ1:データの準備

まず、ハードウェアに負荷をかけるのに十分な大きさのデータセットを生成します。少なくとも10個のテーブルを作成し、各テーブルに100万行を含めることをお勧めします。これにより、RAMキャッシュだけでなく、実際のディスクI/Oをテストできるようになります。

sysbench oltp_read_write --db-driver=mysql \
  --mysql-host=your-db-host \
  --mysql-user=admin \
  --mysql-password=yourpassword \
  --mysql-db=test_db \
  --tables=10 \
  --table-size=1000000 \
  prepare

ステップ2:ベンチマークの実行

このコマンドは、16スレッドを使用して5分間の読み書きテストを実行します。16人の同時実行ユーザーが、可能な限り高速にトランザクションをデータベースに叩き込んでいる状態をシミュレートします。

sysbench oltp_read_write --db-driver=mysql \
  --mysql-host=your-db-host \
  --mysql-user=admin \
  --mysql-password=yourpassword \
  --mysql-db=test_db \
  --threads=16 \
  --time=300 \
  --report-interval=10 \
  run

実装ガイド:PostgreSQLの負荷テスト

PostgreSQLのテストも同様の流れですが、接続パラメータが異なります。ソースからビルドする場合は、Postgresドライバーを有効にするために libpq-dev がインストールされていることを確認してください。

# PostgreSQLの準備フェーズ
sysbench oltp_read_write --db-driver=pgsql \
  --pgsql-host=your-db-host \
  --pgsql-user=postgres \
  --pgsql-password=yourpassword \
  --pgsql-db=test_db \
  --pgsql-port=5432 \
  --tables=10 \
  --table-size=1000000 \
  prepare

テストの実行中は、別のターミナルを開いて pg_stat_activity を監視することをお勧めします。wait_event エントリが多数表示される場合は、ロックの競合やI/Oのボトルネックが発生している可能性があります。

# 32スレッド並列でのPostgreSQL実行フェーズ
sysbench oltp_read_write --db-driver=pgsql \
  --pgsql-host=your-db-host \
  --pgsql-user=postgres \
  --pgsql-password=yourpassword \
  --pgsql-db=test_db \
  --threads=32 \
  --time=300 \
  run

結果の解釈

実行が終了したら、細かな数値は無視して、以下の3つのメトリクスに注目してください。

  1. Transactions Per Second (TPS): これは総スループットを測定します。スレッド数を2倍にしてもTPSが横ばいのままであれば、ハードウェアの限界に達しています。
  2. 95th Percentile Latency (95パーセンタイル遅延): 最も重要な数値です。これは、95%のクエリがこの時間内に完了したことを意味します。平均レイテンシが20msであっても、95パーセンタイルが500msであれば、ユーザーは頻繁にストレスを感じる「もたつき」を経験することになります。
  3. Errors and Reconnects (エラーと再接続): ここがゼロでない場合は、データベースが接続をドロップしているか、負荷下で行レベルのロックを処理できていないことを示唆しています。

例えば、16スレッドから32スレッドに増やした際に、95パーセンタイル遅延が30msから400msに跳ね上がる場合、現在の設定ではそのレベルの同時実行を安全に処理できないと判断できます。

正確なベンチマークのためのプロのヒント

長年の経験から、いくつかの教訓を学びました。まず、必ずエンジンを「ウォームアップ」させてください。最初の実行はバッファプールが空のため、通常遅くなります。キャッシュを準備するために60秒間のテストを実行してから、本番の10分間のテストを行ってください。次に、AWSのgp2のようなクラウドストレージを使用している場合は、「バーストバランス」を注意深く監視してください。最初の5分間は素晴らしいパフォーマンスを示しても、IOPSクレジットがなくなると急激に低下することがあります。

最後に、データサイズに注意してください。データセットが innodb_buffer_pool_size (MySQL) や shared_buffers (PostgreSQL) にすべて収まってしまう場合、RAMの速度をテストしているに過ぎません。ディスクを真にテストするには、データセットが利用可能なシステムメモリの少なくとも2倍のサイズであることを確認してください。

ベンチマークは一度きりの作業ではありません。私は大きなアーキテクチャの変更やクラウド移行の前には必ずこれらのテストを実行します。これにより、私たちのインフラが予測されるトラフィックを実際に処理できるという数学的な証明が得られるのです。

Share: