本文へスキップ
ウェブエンジニア問題集
第13章

MySQL運用入門 — mysqldump・復元テスト・スロークエリログ・my.cnf

約14分
この章の目次開く

MySQLのユーザーと権限までで、アプリケーションを必要最小限の権限で動かせるようになりました。最後に扱うのは、障害が起きたあとに戻すこと、遅くなった原因を見つけること、設定を再現できる形で管理することです。

MySQLは起動しているだけでは運用できているとは言えません。バックアップが復元できるか、遅いクエリを発見できるか、再起動後も意図した設定になるかを、平常時から確認しておく必要があります。

バックアップは「復元できる状態」まで含む

バックアップファイルが存在しても、壊れている、必要なオブジェクトが含まれていない、復元手順が分からないなら役に立ちません。

バックアップの完了条件はファイル作成ではなく、別環境へ復元して必要なデータを確認できることです。

MySQLのバックアップは大きく2種類あります。

種類内容特徴
論理バックアップCREATE TABLE や INSERT などのSQLとして保存内容を確認しやすく、別環境へ移しやすい
物理バックアップデータファイルをバックアップ用ツールで保存大規模DBで高速だが、製品・構成への依存が強い

この章では、小〜中規模のWebアプリケーションで始めやすい mysqldump の論理バックアップを扱います。データ量が増えて取得・復元時間の目標を満たせなくなったら、MySQL Enterprise Backupやクラウドのスナップショットなど、環境に合う物理バックアップも検討します。

mysqldumpでInnoDBを止めずに取得する

InnoDB中心のデータベースでは、--single-transaction と --quick を組み合わせます。

mysqldump \
  --host=db.example.internal \
  --user=backup_reader \
  --password \
  --single-transaction \
  --quick \
  --triggers \
  --no-tablespaces \
  --set-gtid-purged=OFF \
  myapp > myapp.sql
bash

構文: mysqldump [接続オプション] [取得オプション] データベース名 > 出力.sql

オプション説明
--single-transactionREPEATABLE READでトランザクションを開始し、InnoDBの一貫した時点を取得する
--quick全行をメモリへ載せず、行ごとに読み出す
--routinesストアドプロシージャと関数を含める。使う場合だけ追加する
--eventsEvent Schedulerのイベントを含める。使う場合だけ追加する
--triggersトリガーを含める
--no-tablespacestablespace文を出力せず、PROCESS 権限の要求を避ける
--set-gtid-purged=OFF単体環境への復元でGTID情報を書き込まない

出力: スキーマ定義とデータを復元するためのSQLテキストを標準出力へ書く

--password に値を続けず、対話プロンプトで入力します。--password=secret のように書くと、シェル履歴やプロセス一覧へ認証情報が残る可能性があります。自動実行では権限を絞った設定ファイルやシークレット管理を使います。

学習者学習者

mysqldump が終了コード0なら、そのファイルをバックアップとして保管してよいですか?

取得成功は必要条件ですが、十分ではありません。ファイルサイズ、終了コード、暗号化、保管先への転送に加え、復元テストまで自動化します。

専用ユーザーへ必要な権限だけを付ける

基本的なテーブルとビュー、トリガーを取得する専用アカウントの例です。先ほどのコマンドは、この範囲の権限で実行できます。

CREATE USER 'backup_reader'@'10.0.2.15'
  IDENTIFIED BY 'replace-with-a-generated-secret'
  REQUIRE SSL;
 
GRANT SELECT, SHOW VIEW, TRIGGER
ON myapp.*
TO 'backup_reader'@'10.0.2.15';
sql

--events を追加するなら対象DBの EVENT 権限、--routines を追加するならグローバルな SELECT 権限が必要です。--no-tablespaces を外すと PROCESS、GTID設定によっては RELOAD または FLUSH_TABLES も必要になります。エラーのたびに ALL PRIVILEGES を付けず、必要なオブジェクトとオプションから権限を特定します。特にグローバル SELECT は他のデータベースも読めるため、ルーチンを使っていない環境では --routines を付けない方が権限を狭くできます。

バックアップユーザーはデータを読めても、アプリケーションの行を更新・削除できない状態にします。

復元テストで使えることを確かめる

本番とは別のMySQLへ、空のデータベースを作って復元します。

CREATE DATABASE myapp_restore
  CHARACTER SET utf8mb4
  COLLATE utf8mb4_0900_ai_ci;
sql
mysql \
  --host=restore-db.example.internal \
  --user=restore_operator \
  --password \
  myapp_restore < myapp.sql
bash

構文: mysql [接続オプション] データベース名 < バックアップ.sql

結果: SQLファイルを順に実行し、指定データベースへオブジェクトとデータを復元する

復元後は「コマンドが成功した」だけで終わらせず、アプリケーションに必要な状態を確認します。

SHOW TABLES FROM myapp_restore;
 
SELECT COUNT(*) FROM myapp_restore.users;
SELECT COUNT(*) FROM myapp_restore.orders;
 
CHECK TABLE
  myapp_restore.users,
  myapp_restore.orders;
sql

確認項目の例です。

  • 必要なテーブル、ビュー、トリガー、ルーチン、イベントが存在する
  • 主要テーブルの件数が取得時の記録と大きくずれていない
  • 代表的な画面やAPIが復元先へ接続して動作する
  • 復元にかかった時間が目標復旧時間内に収まる
  • バックアップファイルを取得担当以外が読み取れない
  • 古いバックアップを保持方針どおり削除できている
復元確認を終えて安心している人のイラスト
障害当日ではなく、平常時の復元訓練で手順と所要時間を確かめる

スロークエリログで遅いSQLを見つける

スロークエリログは、long_query_time 以上かかり、min_examined_row_limit 以上の行を調べた文を記録します。MySQL 8.4では既定で無効、long_query_time の既定は10秒です。

現在の設定を確認します。

SHOW GLOBAL VARIABLES
WHERE Variable_name IN (
  'slow_query_log',
  'slow_query_log_file',
  'long_query_time',
  'min_examined_row_limit',
  'log_output'
);
sql

運用方針で承認された値へ変更する例です。

SET PERSIST slow_query_log = ON;
SET PERSIST long_query_time = 1;
SET PERSIST min_examined_row_limit = 100;
sql

構文: SET PERSIST システム変数 = 値

指定説明
システム変数永続化可能なグローバル変数
値適用する値。変数ごとの型と範囲に従う

結果: 現在のグローバル値を変更し、再起動後にも使う値を mysqld-auto.cnf へ記録する

ログには、実行時間だけでなく次の情報が含まれます。

項目意味
Query_time文の実行時間
Lock_timeロック獲得にかかった時間
Rows_sentクライアントへ返した行数
Rows_examinedサーバー層で調べた行数

Rows_sent が少ないのに Rows_examined が非常に多いSQLは、条件に合うインデックスとEXPLAINを確認する候補です。

ファイル形式のログは mysqldumpslow で似たSQLをまとめられます。

mysqldumpslow -s t -t 10 /var/lib/mysql/mysql-slow.log
bash

構文: mysqldumpslow [-s 並び順] [-t 件数] スローログファイル

オプション説明
-s t平均クエリ時間で並べる
-t 10上位10件を表示する

出力: 値の違いをまとめたクエリパターンごとに、回数や平均時間などを表示する

設定値の適用範囲と永続性を区別する

MySQLのシステム変数は、変更方法によって影響範囲と再起動後の状態が変わります。

方法現在の動作再起動後主な用途
SET SESSION現在の接続だけ変更戻るクエリ単位の一時調整
SET GLOBAL新しい接続などへ反映戻る一時的な運用変更・検証
SET PERSISTグローバル値を変更維持する動的変数の永続変更
SET PERSIST_ONLYその場では変えない維持する起動時だけ変えられる変数
my.cnf再起動まで変わらない維持する構成管理された起動設定

SET PERSIST と SET PERSIST_ONLY は、データディレクトリの mysqld-auto.cnf へ値を保存します。このファイルはMySQL自身に管理させ、手で編集しません。

SELECT
  VARIABLE_NAME,
  VARIABLE_SOURCE,
  VARIABLE_PATH,
  SET_TIME,
  SET_USER,
  SET_HOST
FROM performance_schema.variables_info
WHERE VARIABLE_NAME IN (
  'slow_query_log',
  'long_query_time'
);
sql

不要になった永続設定は次で外せます。

RESET PERSIST IF EXISTS long_query_time;
sql

RESET PERSIST は保存値を削除しますが、現在動いている値はその場で元へ戻しません。必要なら SET GLOBAL で現在値も戻し、再起動後の値と分けて確認します。

my.cnfへ起動設定を書く

Linux環境では一般に my.cnf、Windowsでは my.ini というオプションファイルを使います。読み込むファイルと順序はOS、配布形式、起動方法で異なるため、固定のパスを前提にしません。

[mysqld]
slow_query_log=ON
long_query_time=1
min_examined_row_limit=100
 
[client]
default-character-set=utf8mb4
ini
セクション読み込む主なプログラム
[mysqld]MySQLサーバー
[client]多くのクライアントプログラム共通
[mysql]mysql コマンド
[mysqldump]mysqldump コマンド

どのオプションファイルを探索するかは、対象環境の mysqld --verbose --help で確認します。コンテナやマネージドDBでは、ファイルではなく起動引数やパラメータグループが正本になる場合があります。

変更後は、設定ファイルの内容ではなく実際のサーバー値を確認します。

SHOW GLOBAL VARIABLES LIKE 'long_query_time';
sql
設定ファイルを書いたことではなく、再起動後にサーバーが意図した値で動いていることを確認して変更完了とします。

最低限の状態を定期観測する

障害が起きてから初めて値を見ると、正常時との差が分かりません。まず少数の指標を継続して記録します。

SHOW GLOBAL STATUS
WHERE Variable_name IN (
  'Uptime',
  'Threads_connected',
  'Threads_running',
  'Slow_queries',
  'Aborted_connects'
);
sql
指標見ること
Uptime意図しない再起動がなかったか
Threads_connected接続数が普段より増えていないか
Threads_running同時に処理中の接続が増えていないか
Slow_querieslong_query_time を超えた累計件数の増え方
Aborted_connects認証失敗や接続確立失敗が増えていないか

累計値はサーバー再起動でリセットされます。値そのものだけでなく、一定時間あたりの増加量を監視します。

よくあるハマりどころ

バックアップを本番サーバー内だけに置く

ディスク障害やサーバー削除で、データとバックアップを同時に失います。別の障害領域へ転送し、暗号化・アクセス制御・保持期限を設定します。

復元テストを一度もしていない

不足オプション、権限不足、文字コード差、ファイル破損は、取得時に見つからないことがあります。定期的に新しい環境へ復元し、所要時間も記録します。

single-transactionですべて止まらないと思う

InnoDBの通常の読み書きを大きく止めずに取得できますが、DDLとの同時実行は安全ではありません。バックアップとマイグレーションの時間帯を調整します。

long_query_timeを0にして放置する

すべてのクエリが対象となり、ログI/Oと保存容量を急増させます。短時間の調査で使う場合も、終了条件と戻す値を先に決めます。

SET GLOBALだけで永続化したと思う

SET GLOBAL は再起動すると設定ファイル側の値へ戻ります。永続化するなら、環境の方針に従って SET PERSIST、my.cnf、パラメータグループなどへ反映します。

mysqld-auto.cnfを手で編集する

JSONを壊すとサーバーが起動できなくなる可能性があります。永続設定の追加は SET PERSIST、削除は RESET PERSIST で行います。

ちゃんと使うためのポイント

  • バックアップは別環境へ復元し、必要なデータと所要時間を確認して初めて使える
  • InnoDBの論理バックアップは --single-transaction と --quick を基本にする
  • ルーチン・イベント・トリガーなど、必要なオブジェクトを明示して取得する
  • バックアップ専用ユーザーへ読み取り中心の権限だけを付ける
  • スロークエリログは long_query_time と調査行数を使い、最適化候補を見つける
  • 設定変更はセッション・グローバル・永続・設定ファイルのどこへ効くか区別する
  • mysqld-auto.cnf は直接編集せず、SET PERSIST と RESET PERSIST で管理する
  • 監視値は正常時から記録し、累計値の増加率と再起動を考慮する

これで、接続・テーブル設計・文字コード・InnoDB・インデックス・トランザクション・MySQL固有SQL・Node.js接続・マイグレーション・権限・バックアップと監視まで、一連の基礎がつながりました。必要な章へ戻り、実際のアプリケーションとMySQLの値を照らし合わせながら運用してください。

参考リンク

SQLクイズに挑戦するバックアップ・ログ・設定運用の知識を、4択クイズでアウトプットして定着させよう