Skip to content
Published on

MySQL 8.4 InnoDBクラスター運用とクエリ最適化ハンドブック

Authors
  • Name
    Twitter
MySQL 8.4 InnoDBクラスター運用とクエリ最適化ハンドブック

MySQL 8.4 LTSが意味するもの

MySQL 8.4はOracleが公式に指定したLong-Term Support(LTS)リリースである。2024年4月のGA以降、2025〜2026年にかけて8.4.4から8.4.8まで着実にパッチがリリースされており、MySQL 8.0は2026年のEOLを控えている。本番環境における8.4への移行は、もはや選択ではなく必須だ。

まず8.4で変わった主要な点を整理する。

主要変更点の要約

  • mysql_native_passwordがデフォルトで無効化:8.4.0からデフォルトでロードされなくなった。caching_sha2_passwordがデフォルトの認証プラグインとなる。レガシーアプリがある場合は--mysql-native-password=ONオプションで明示的に有効化する必要がある。
  • MASTER/SLAVE用語の完全削除CHANGE MASTER TOSTART SLAVESHOW SLAVE STATUSなどが構文エラーを発生させる。CHANGE REPLICATION SOURCE TOSTART REPLICASHOW REPLICA STATUSに切り替える必要がある。
  • mysqlpumpの削除mysqldumpまたはMySQL Shellのdumpユーティリティを使用する。
  • InnoDB Adaptive Hash Index(AHI)がデフォルトで無効化:ワークロードによってパフォーマンスに変化がある可能性がある。必要に応じてinnodb_adaptive_hash_index=ONで手動で有効化する。
  • InnoDB Change Bufferがデフォルトで無効化:SSDベースのストレージでは無効化の方がむしろ有利である。
  • 自動ヒストグラム更新:オプティマイザ統計の精度を高め、クエリ実行計画を改善する。サーバー再起動後もヒストグラムメタデータが維持される。
  • restrict_fk_on_non_standard_key=ONがデフォルト:非ユニークまたは部分キーをFKとして使用することがデフォルトでブロックされる。

InnoDBクラスターアーキテクチャ

InnoDBクラスターは3つのコアコンポーネントで構成される。

  1. MySQL Group Replication:Paxosベースの合意プロトコルを使用する同期レプリケーションレイヤー。データの一貫性と自動フェイルオーバーを保証する。
  2. MySQL Shell(AdminAPI):クラスターの作成、ノードの追加/削除、ステータス監視のための管理インターフェース。
  3. MySQL Router:アプリケーショントラフィックを適切なノードにルーティングするミドルウェア。書き込みをPrimaryに、読み込みをSecondaryに分散する。
┌─────────────────────────────────────────────────┐
Application└──────────────────────┬──────────────────────────┘
              ┌────────▼────────┐
MySQL Router                (R/W split)              └───┬────────┬────┘
         Write    │        │   Read
         ┌────────▼──┐  ┌──▼────────┐
Primary   │  │ Secondary           (node-1) (node-2)         └────────────┘  └───────────┘
                  │           │
              ┌───▼───────────▼───┐
Secondary                  (node-3)              └───────────────────┘
Group Replication (Paxos)

最低3ノード構成が必須であり、最大9ノードまで拡張可能だ。奇数ノード(3、5、7)を使用することで、クォーラム計算においてスプリットブレインを防止できる。

InnoDBクラスター vs NDBクラスター比較

本番環境でどのクラスタリングソリューションを選択するかを判断する際に参考になる比較表だ。

項目InnoDBクラスターNDBクラスター
ストレージエンジンInnoDB(ディスクベース)NDB(インメモリ+ディスク)
レプリケーション方式Group Replication(Paxos)同期2-phase commit
シャーディング非対応(手動パーティショニング必要)自動シャーディング(Node Group)
最大ノード数9255(データノード144)
クエリ実行シングルスレッドデータノードへのpush-down可能
障害許容Nノード中過半数の生存が必要Node Groupごとに1 replicaで運用可能
適合ワークロード汎用OLTP、読み取りスケーリング超低遅延、書き込み集中、通信/金融
運用複雑度低(MySQL Shellで管理)高(Management Nodeが別途必要)
外部キーサポート完全対応限定的
トランザクション分離すべてのレベルに対応READ COMMITTEDのみ

ほとんどのWebサービス、SaaSバックエンド、一般的なOLTPワークロードでは、InnoDBクラスターが運用複雑度と機能面で合理的な選択だ。NDBクラスターは数十万TPS以上の超低遅延が必要な通信・金融リアルタイムシステムに適している。

InnoDBクラスター構築の実践

事前準備

すべてのノードに同じMySQL 8.4バージョンをインストールし、以下の条件を確認する。

  • すべてのテーブルがInnoDBエンジンを使用しているか確認(MyISAMなどは事前に変換)
  • すべてのテーブルにPRIMARY KEYが存在するか確認(Group Replicationの必須条件)
  • GTIDの有効化(gtid_mode=ONenforce_gtid_consistency=ON
  • 各ノードに固有のserver_idを設定
  • /etc/hostsファイルにすべてのノードのホスト名を登録(DNS解決の一貫性を保証)
# 各ノードでMySQL 8.4をインストール(Ubuntu/Debianの例)
sudo apt-get update
sudo apt-get install mysql-server-8.4 mysql-shell mysql-router

# InnoDBエンジンでないテーブルを確認
mysql -u root -p -e "
  SELECT TABLE_SCHEMA, TABLE_NAME, ENGINE
  FROM information_schema.TABLES
  WHERE ENGINE != 'InnoDB'
    AND TABLE_SCHEMA NOT IN ('mysql','information_schema','performance_schema','sys');
"

# PRIMARY KEYのないテーブルを確認
mysql -u root -p -e "
  SELECT t.TABLE_SCHEMA, t.TABLE_NAME
  FROM information_schema.TABLES t
  LEFT JOIN information_schema.TABLE_CONSTRAINTS c
    ON t.TABLE_SCHEMA = c.TABLE_SCHEMA
    AND t.TABLE_NAME = c.TABLE_NAME
    AND c.CONSTRAINT_TYPE = 'PRIMARY KEY'
  WHERE c.TABLE_NAME IS NULL
    AND t.TABLE_SCHEMA NOT IN ('mysql','information_schema','performance_schema','sys')
    AND t.TABLE_TYPE = 'BASE TABLE';
"

my.cnf設定(各ノード共通)

[mysqld]
# 基本設定
server_id=1                          # ノードごとに固有値(1, 2, 3)
bind-address=0.0.0.0
port=3306
datadir=/var/lib/mysql

# GTID有効化
gtid_mode=ON
enforce_gtid_consistency=ON

# Binary Log
log_bin=mysql-bin
binlog_format=ROW
binlog_transaction_dependency_tracking=WRITESET
log_replica_updates=ON

# Group Replication基本設定
plugin_load_add=group_replication.so
group_replication_group_name="aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
group_replication_start_on_boot=OFF
group_replication_local_address="node1:33061"
group_replication_group_seeds="node1:33061,node2:33061,node3:33061"
group_replication_bootstrap_group=OFF

# InnoDBチューニング
innodb_buffer_pool_size=4G           # 物理メモリの70〜80%
innodb_buffer_pool_instances=4       # buffer_pool_size / 1G
innodb_log_file_size=1G
innodb_flush_log_at_trx_commit=1     # データ安全性最優先
innodb_flush_method=O_DIRECT

# 無効化されたデフォルト値のうちワークロードに応じて有効化を検討
# innodb_adaptive_hash_index=ON      # OLTPホットスポットクエリが多い場合に有効化
# innodb_change_buffering=all        # HDD使用時に有効化

# レプリケーション関連
replica_parallel_type=LOGICAL_CLOCK
replica_parallel_workers=4           # 4〜8の範囲を推奨
replica_preserve_commit_order=ON

# ストレージエンジン制限(InnoDB以外の使用を防止)
disabled_storage_engines="MyISAM,BLACKHOLE,FEDERATED,ARCHIVE,MEMORY"

# トランザクション分離レベル(Multi-Primary使用時)
# transaction_isolation=READ-COMMITTED

MySQL Shellでクラスター作成

// MySQL Shell(mysqlsh)に接続
// mysqlsh root@node1:3306

// 1. 各インスタンスの設定確認と自動構成
dba.configureInstance('root@node1:3306', {
  clusterAdmin: 'clusteradmin',
  clusterAdminPassword: 'SecureP@ss!2026',
})
dba.configureInstance('root@node2:3306', {
  clusterAdmin: 'clusteradmin',
  clusterAdminPassword: 'SecureP@ss!2026',
})
dba.configureInstance('root@node3:3306', {
  clusterAdmin: 'clusteradmin',
  clusterAdminPassword: 'SecureP@ss!2026',
})

// 2. 最初のノードでクラスター作成(Bootstrap)
shell.connect('clusteradmin@node1:3306')
var cluster = dba.createCluster('prodCluster', {
  multiPrimary: false, // Single-Primaryモード推奨
  memberWeight: 50,
  expelTimeout: 5,
  autoRejoinTries: 3,
  consistency: 'BEFORE_ON_PRIMARY_FAILOVER',
})

// 3. 残りのノードを追加(Clone方式を推奨)
cluster.addInstance('clusteradmin@node2:3306', {
  recoveryMethod: 'clone',
})
cluster.addInstance('clusteradmin@node3:3306', {
  recoveryMethod: 'clone',
})

// 4. クラスターステータスの確認
cluster.status()

recoveryMethod: 'clone'を指定すると、既存のクラスターメンバーの物理スナップショットを使用して新しいノードのデータを完全に同期する。データ量が多い場合やバイナリログの保持期間が短い場合、Clone方式が安全だ。

MySQL Routerの設定

# Routerブートストラップ(クラスターメタデータを自動設定)
mysqlrouter --bootstrap clusteradmin@node1:3306 \
  --directory /opt/mysqlrouter \
  --user=mysqlrouter \
  --conf-use-sockets \
  --conf-bind-address=0.0.0.0

# Routerの起動
/opt/mysqlrouter/start.sh

# またはsystemdで管理
sudo systemctl enable mysqlrouter
sudo systemctl start mysqlrouter

Routerがブートストラップされると、デフォルトで以下のポートを使用する。

  • 6446:R/Wポート(Primaryにルーティング)
  • 6447:R/Oポート(Secondaryにルーティング、round-robin)
  • 6448:R/W X Protocolポート
  • 6449:R/O X Protocolポート

アプリケーションのDB接続文字列を、Routerが動作するホストの6446(書き込み)または6447(読み取り)ポートに変更すればよい。

クラスター運用とモニタリング

日常運用コマンド

// MySQL Shellでクラスターオブジェクトを取得
shell.connect('clusteradmin@node1:3306')
var cluster = dba.getCluster()

// クラスター全体のステータスを確認
cluster.status({ extended: 1 })

// 特定ノードの詳細ステータスを確認
cluster.status({ extended: 2 })

// ノードの一時削除(メンテナンス)
cluster.removeInstance('clusteradmin@node2:3306', { force: false })

// ノードの再追加
cluster.addInstance('clusteradmin@node2:3306', { recoveryMethod: 'clone' })

// クラスターオプションの確認
cluster.options()

// Primary手動切替(graceful switchover)
cluster.setPrimaryInstance('clusteradmin@node2:3306')

// Router接続ステータスの確認
cluster.listRouters()

重要なモニタリングクエリ

運用中に必ず定期的に確認すべきメトリクスだ。

-- Group Replicationメンバーステータスの確認
SELECT MEMBER_ID, MEMBER_HOST, MEMBER_PORT, MEMBER_STATE, MEMBER_ROLE
FROM performance_schema.replication_group_members;

-- トランザクション適用遅延の確認(各Secondaryで実行)
SELECT
  CHANNEL_NAME,
  COUNT_TRANSACTIONS_IN_QUEUE AS trx_in_queue,
  COUNT_TRANSACTIONS_CHECKED AS trx_checked,
  COUNT_TRANSACTIONS_REMOTE_IN_APPLIER_QUEUE AS remote_queue,
  LAST_CONFLICT_FREE_TRANSACTION
FROM performance_schema.replication_group_member_stats
WHERE CHANNEL_NAME = 'group_replication_applier';

-- Applierワーカーステータスの確認
SELECT
  WORKER_ID, LAST_SEEN_TRANSACTION,
  APPLYING_TRANSACTION, LAST_APPLIED_TRANSACTION
FROM performance_schema.replication_applier_status_by_worker
WHERE CHANNEL_NAME = 'group_replication_applier';

-- InnoDBクラスターメタデータの確認
SELECT * FROM mysql_innodb_cluster_metadata.clusters;
SELECT * FROM mysql_innodb_cluster_metadata.instances;

警告:運用時に必ず注意すべき事項

  1. DDL実行に注意:大規模テーブルのALTER TABLEはGroup Replicationのcertification段階でクラスター全体をブロックする可能性がある。pt-online-schema-changeまたはgh-ostを使用する。
  2. 大量トランザクションの制限group_replication_transaction_size_limit(デフォルト150MB)を超えるトランザクションはロールバックされる。大量のINSERT/UPDATEはバッチ単位で分割する。
  3. ネットワーク遅延:ノード間のネットワークラウンドトリップ遅延が書き込みパフォーマンスに直接影響する。同じデータセンター内への配置を推奨し、クロスリージョン配置の場合はClusterSetを検討する。
  4. バイナリログ管理binlog_expire_logs_secondsを適切に設定してディスク容量を管理する。デフォルトは2592000秒(30日)である。
  5. バックアップはSecondaryで実行:Primaryの負荷を軽減するため、物理バックアップ(xtrabackup、mysqlbackup)はSecondaryノードで実行する。

障害シナリオとリカバリ手順

シナリオ1:Secondaryノード1台の障害

最も一般的な状況だ。3ノードクラスターでSecondary 1台がダウンすると、クラスターは2/3のクォーラムで正常に運用を継続する。

// 障害ノード復旧後の自動再参加を確認
cluster.status()
// MEMBER_STATEがRECOVERING -> ONLINEに変更されるかを確認

// 自動再参加が失敗した場合
cluster.rejoinInstance('clusteradmin@node3:3306')

// データ差が大きい場合はCloneで再参加
cluster.removeInstance('clusteradmin@node3:3306', { force: true })
cluster.addInstance('clusteradmin@node3:3306', { recoveryMethod: 'clone' })

シナリオ2:Primaryノードの障害

Primaryがダウンすると、Group Replicationが自動的に新しいPrimaryを選出する。member_weightが高いノードが優先的に選出される。

// 新しいPrimaryの確認
cluster.status()

// 旧Primary復旧後にSecondaryとして再参加
cluster.rejoinInstance('clusteradmin@node1:3306')

MySQL RouterはPrimaryの変更を自動検知し、書き込みトラフィックを新しいPrimaryにルーティングする。アプリケーションレベルでの再接続ロジック(connection retry)が必要である。

シナリオ3:クォーラム喪失(過半数のノードがダウン)

3ノード中2台が同時にダウンすると、残りの1台はクォーラムを失い、読み取りのみ可能で書き込みが不可能になる。

// 生存ノードから強制クォーラムリカバリ
// 注意:データ損失の可能性あり
cluster.forceQuorumUsingPartitionOf('clusteradmin@node1:3306')

// その後、ダウンしたノードを復旧して再参加
cluster.rejoinInstance('clusteradmin@node2:3306')
cluster.rejoinInstance('clusteradmin@node3:3306')

forceQuorumUsingPartitionOfは最後の手段である。このコマンドは指定したノードのデータを基準にクラスターを再構成するため、他のノードでコミットされたがまだ伝播されていないトランザクションが失われる可能性がある。

シナリオ4:クラスター全体の再起動

計画された全面停止(インフラ点検など)後の再起動時は順序が重要だ。

// 1. 最新のGTIDを持つノードを最初に起動
// 各ノードで確認:
// SELECT @@gtid_executed;

// 2. そのノードからクラスターを再起動
shell.connect('clusteradmin@node1:3306')
var cluster = dba.rebootClusterFromCompleteOutage('prodCluster')

// 3. 残りのノードは自動再参加または手動参加
cluster.rejoinInstance('clusteradmin@node2:3306')
cluster.rejoinInstance('clusteradmin@node3:3306')

クエリ最適化戦略

InnoDBクラスター環境でのクエリ最適化は、単一インスタンスと同じ原則に従うが、Group Replicationの特性を追加で考慮する必要がある。

スロークエリ分析パイプライン

-- 1. スロークエリログの有効化
SET GLOBAL slow_query_log = 1;
SET GLOBAL long_query_time = 1;        -- 1秒以上のクエリを記録
SET GLOBAL log_queries_not_using_indexes = 1;
SET GLOBAL slow_query_log_file = '/var/log/mysql/slow.log';

-- 2. performance_schemaで上位スロークエリを特定
SELECT
  SCHEMA_NAME,
  DIGEST_TEXT,
  COUNT_STAR AS exec_count,
  ROUND(SUM_TIMER_WAIT / 1000000000000, 3) AS total_sec,
  ROUND(AVG_TIMER_WAIT / 1000000000000, 3) AS avg_sec,
  SUM_ROWS_EXAMINED AS rows_examined,
  SUM_ROWS_SENT AS rows_sent,
  ROUND(SUM_ROWS_EXAMINED / NULLIF(SUM_ROWS_SENT, 0), 1) AS exam_to_sent_ratio,
  FIRST_SEEN,
  LAST_SEEN
FROM performance_schema.events_statements_summary_by_digest
WHERE SCHEMA_NAME NOT IN ('mysql', 'performance_schema', 'information_schema', 'sys')
ORDER BY SUM_TIMER_WAIT DESC
LIMIT 20;

exam_to_sent_ratio(検査行数と返却行数の比率)が100以上であれば、インデックスの追加またはクエリの書き直しが必要であるという強いシグナルだ。

# 3. pt-query-digestでスローログを分析(Percona Toolkit)
pt-query-digest /var/log/mysql/slow.log \
  --limit=20 \
  --order-by=Query_time:sum \
  --output report > /tmp/slow_report.txt

EXPLAIN ANALYZEの活用

MySQL 8.4では、EXPLAIN ANALYZEは実際の実行統計を含む実行計画を提供する。

EXPLAIN ANALYZE
SELECT o.order_id, o.order_date, c.customer_name, SUM(oi.quantity * oi.unit_price) AS total
FROM orders o
JOIN customers c ON o.customer_id = c.customer_id
JOIN order_items oi ON o.order_id = oi.order_id
WHERE o.order_date BETWEEN '2026-01-01' AND '2026-03-01'
  AND c.region = 'APAC'
GROUP BY o.order_id, o.order_date, c.customer_name
ORDER BY total DESC
LIMIT 50;

出力で注目すべき項目は以下の通りだ。

  • actual time:実際の所要時間(最初の行の返却〜最後の行の返却)
  • rows:実際に処理された行数(予測値と大きな差がある場合、統計が不正確であることを意味する)
  • loops:そのステージが繰り返し実行された回数
  • Table scan / Index scan:フルテーブルスキャンの有無

インデックス戦略

カバリングインデックス

クエリに必要なすべてのカラムをインデックスに含め、テーブルデータページへのアクセスを排除する戦略だ。

-- 頻繁に実行されるクエリパターン
SELECT customer_id, order_date, status
FROM orders
WHERE customer_id = 12345
  AND status = 'SHIPPED'
ORDER BY order_date DESC;

-- カバリングインデックスの作成
CREATE INDEX idx_orders_covering
  ON orders (customer_id, status, order_date DESC, order_id);

-- EXPLAINでExtra: Using indexを確認
EXPLAIN SELECT customer_id, order_date, status
FROM orders
WHERE customer_id = 12345
  AND status = 'SHIPPED'
ORDER BY order_date DESC;

Invisibleインデックスによる安全なインデックス管理

MySQL 8.4では、インデックスを削除する前にinvisibleに切り替えて影響をテストできる。

-- インデックスをinvisibleに変更(オプティマイザが無視)
ALTER TABLE orders ALTER INDEX idx_old_index INVISIBLE;

-- 一定期間モニタリング後、問題がなければ削除
DROP INDEX idx_old_index ON orders;

-- 問題が発生した場合は即座に復元
ALTER TABLE orders ALTER INDEX idx_old_index VISIBLE;

ヒストグラムの活用

MySQL 8.4の自動ヒストグラム更新を活用しつつ、必要に応じて手動で作成することもできる。

-- カラムにヒストグラムを作成
ANALYZE TABLE orders UPDATE HISTOGRAM ON status, region WITH 100 BUCKETS;

-- ヒストグラム情報の確認
SELECT
  SCHEMA_NAME, TABLE_NAME, COLUMN_NAME,
  JSON_EXTRACT(HISTOGRAM, '$.\"number-of-buckets-specified\"') AS buckets,
  JSON_EXTRACT(HISTOGRAM, '$.\"sampling-rate\"') AS sampling_rate,
  JSON_EXTRACT(HISTOGRAM, '$.\"histogram-type\"') AS hist_type
FROM information_schema.COLUMN_STATISTICS
WHERE TABLE_NAME = 'orders';

ヒストグラムはインデックスのないカラムの選択性(selectivity)をオプティマイザに伝え、結合順序と実行計画の決定に役立つ。カーディナリティが低いカラム(status、region、typeなど)に特に効果的だ。

Group Replication環境特化の最適化

InnoDBクラスターで追加で考慮すべき最適化ポイントがある。

  1. 書き込み最適化:Group Replicationはすべての書き込みトランザクションをグループ全体でcertification(認証)する。トランザクションが小さいほどcertificationの競合(conflict)の可能性が低くなる。大量INSERTは1,000〜5,000行単位のバッチに分割する。

  2. 読み取り分散:MySQL RouterのR/Oポート(6447)を活用して読み取りクエリをSecondaryに分散する。ただし、consistency: 'BEFORE_ON_PRIMARY_FAILOVER'設定時はフェイルオーバー直後に一時的な読み取り遅延が発生する可能性がある。

  3. Multi-Primaryモードの分離レベル:Multi-Primaryモードを使用する場合はtransaction_isolation=READ-COMMITTEDに設定する。REPEATABLE READはMulti-Primaryでcertification競合を増加させる可能性がある。

  4. ホットスポットテーブルの回避:同じ行への同時更新はcertification段階で競合を発生させる。カウンターテーブルなどはアプリケーションレベルでの分散処理(Redisなど)を検討する。

InnoDBバッファプールチューニング

クエリパフォーマンスに最も大きな影響を与える単一の設定はinnodb_buffer_pool_sizeだ。

-- 現在のバッファプールヒット率を確認
SELECT
  (1 - (
    (SELECT VARIABLE_VALUE FROM performance_schema.global_status
     WHERE VARIABLE_NAME = 'Innodb_buffer_pool_reads') /
    (SELECT VARIABLE_VALUE FROM performance_schema.global_status
     WHERE VARIABLE_NAME = 'Innodb_buffer_pool_read_requests')
  )) * 100 AS buffer_pool_hit_rate;

-- 99%以下の場合はbuffer_pool_sizeの増加を検討

-- バッファプールの詳細ステータス
SELECT
  POOL_ID,
  POOL_SIZE,
  FREE_BUFFERS,
  DATABASE_PAGES,
  MODIFIED_DB_PAGES,
  PAGES_MADE_YOUNG,
  PAGES_NOT_MADE_YOUNG
FROM information_schema.INNODB_BUFFER_POOL_STATS;

-- オンラインでバッファプールサイズを変更(再起動不要)
SET GLOBAL innodb_buffer_pool_size = 8 * 1024 * 1024 * 1024;  -- 8GB

バッファプールヒット率を99%以上に維持することが目標だ。ヒット率が95%以下に低下すると、ディスクI/Oが急増し、全体的なクエリパフォーマンスが急激に低下する。

運用チェックリスト

日常運用と障害対応のためのチェックリストだ。

日次点検

  • cluster.status()ですべてのノードがONLINE状態であることを確認
  • replication_group_member_statsCOUNT_TRANSACTIONS_IN_QUEUEが異常に高くないか確認(100以上で警告)
  • スロークエリログに新しいパターンがないか確認
  • ディスク使用量の確認(バイナリログ、リレーログ、データディレクトリ)
  • バッファプールヒット率が99%以上を維持しているか確認

週次点検

  • pt-query-digestでスロークエリのトレンド分析
  • 使用されていないインデックスの確認(sys.schema_unused_indexes
  • 重複インデックスの確認(sys.schema_redundant_indexes
  • テーブル統計の更新(ANALYZE TABLE
  • バイナリログのパージ状態の確認

障害対応準備

  • forceQuorumUsingPartitionOfの使用手順をチーム全体が把握
  • rebootClusterFromCompleteOutageの実行順序(最新GTIDノード優先)をドキュメント化
  • MySQL Routerの再ブートストラップ手順を把握
  • 物理バックアップ(xtrabackup)が少なくとも1日1回Secondaryで実行されているか確認
  • 復旧時間目標(RTO)に合わせたリカバリ手順のリハーサル

アップグレード前の確認

  • util.checkForServerUpgrade()で互換性を検証
  • mysql_native_password依存関係の削除を確認
  • MASTER/SLAVE用語を使用するコードの検索と置換
  • mysqlpump使用スクリプトをmysqldumpまたはMySQL Shell dumpに置換
  • 非ユニークキーFK使用の有無を確認(restrict_fk_on_non_standard_keyへの備え)
  • ローリングアップグレード順序:Secondary -> Secondary -> Primary(switchover後)

パフォーマンスベンチマーク参考値

8.4 LTS環境でのおおよそのパフォーマンス期待値を整理する。ハードウェアとワークロードによって大きく異なるため、参考レベルでのみ活用すること。

構成単一インスタンスInnoDBクラスター3ノード(Single-Primary)
書き込みTPS(sysbench oltp_write_only)約15,000約10,000〜12,000(certificationオーバーヘッド)
読み取りQPS(sysbench oltp_read_only)約50,000約120,000(3ノード合計、R/O分散)
フェイルオーバー時間N/A5〜30秒(expelTimeout+選出時間)
Cloneリカバリ時間(100GBデータ)N/A10〜30分(ネットワーク帯域幅に依存)

Group Replicationのcertificationオーバーヘッドにより、単一ノードと比較して書き込みTPSが20〜30%減少するのは正常である。読み取りパフォーマンスはノードの追加によりほぼリニアに拡張できる。

まとめ

MySQL 8.4 InnoDBクラスターは、運用複雑度と可用性のバランスが取れたソリューションだ。核心は3つある。

第一に、クラスター構成前にすべての前提条件(InnoDBエンジン、PK、GTID)を完全に満たすこと。第二に、Group Replicationの特性(certificationベースの合意)を理解し、トランザクションサイズを制御すること。第三に、performance_schemaとスロークエリ分析を通じて80/20の法則に従い、上位20%の問題クエリを集中的に最適化すること。

8.0から8.4へのアップグレードを検討している場合は、まずmysql_native_password依存関係の削除とMASTER/SLAVE用語の置換を行い、その後ローリングアップグレード方式で進めることを推奨する。


References

  1. MySQL 8.4 Release Notes - MySQL 8.4 LTSの完全なリリースノート
  2. MySQL 8.4 Reference Manual - What Is New in MySQL 8.4 - 8.0からの変更点に関する公式ドキュメント
  3. MySQL Shell 9.5 - InnoDB Cluster - InnoDBクラスター公式ガイド
  4. MySQL 8.4 Reference Manual - Group Replication - Group Replication公式リファレンス
  5. MySQL 8.4 Reference Manual - Optimizing SELECT Statements - クエリ最適化公式ガイド
  6. MySQL 8.4 - InnoDB vs NDB Cluster Comparison - InnoDBとNDBストレージエンジンの比較
  7. Percona - InnoDB Cluster Setup: Building a 3-Node HA Architecture - 実践的なセットアップガイド
  8. MySQL Replication Best Practices (Percona, 2025) - レプリケーション運用のベストプラクティス