2026年10月13日

2026年10月13日

WordPressのデータベースをレプリケーションで冗長化する方法

はじめに

WordPressサイトの規模が拡大するにつれ、データベースの単一障害点(SPOF)は深刻なリスクとなります。MySQL/MariaDBのレプリケーション機能を活用してプライマリ・レプリカ構成を構築することで、データベース障害時のダウンタイムを最小化し、読み取りクエリの負荷分散も実現できます。本記事では、WordPressのHyperDBプラグインを使った実践的な冗長化手順を解説します。

症状・原因

  • データベースサーバーの単一障害でサイト全体がダウンする
  • 大量の読み取りクエリでDBサーバーのCPU使用率が100%に達する
  • バックアップ取得中にパフォーマンスが著しく低下する
  • 読み取り処理と書き込み処理を同一サーバーで処理している
  • ディザスタリカバリ(DR)計画が存在しない

解決手順

ステップ1:プライマリサーバーのMySQL設定

プライマリ(マスター)サーバーの /etc/mysql/mysql.conf.d/mysqld.cnf を編集します。

# /etc/mysql/mysql.conf.d/mysqld.cnf の設定
[mysqld]
server-id               = 1
log_bin                 = /var/log/mysql/mysql-bin.log
binlog_expire_logs_secs = 2592000
max_binlog_size         = 100M
binlog_format           = ROW
# WordPressのDBのみレプリケーション対象にする場合
binlog_do_db            = wordpress_db

# パフォーマンス設定
innodb_flush_log_at_trx_commit = 1
sync_binlog                    = 1

# 設定反映
# sudo systemctl restart mysql

# レプリケーション用ユーザー作成
# mysql -u root -p で接続後:
# CREATE USER 'replicator'@'%' IDENTIFIED BY 'StrongPass123!';
# GRANT REPLICATION SLAVE ON *.* TO 'replicator'@'%';
# FLUSH PRIVILEGES;
# SHOW MASTER STATUS;  -- File と Position をメモする

ステップ2:レプリカサーバーのMySQL設定

レプリカ(スレーブ)サーバーに同様の設定を行います。

# /etc/mysql/mysql.conf.d/mysqld.cnf の設定(レプリカ側)
[mysqld]
server-id        = 2
relay-log        = /var/log/mysql/mysql-relay-bin.log
log_bin          = /var/log/mysql/mysql-bin.log
read_only        = ON
super_read_only  = ON

# プライマリのデータをダンプ&インポート
# プライマリ側: mysqldump -u root -p --single-transaction --master-data=2 wordpress_db > dump.sql
# レプリカ側:   mysql -u root -p wordpress_db < dump.sql

# レプリカの設定(mysql コンソールで実行)
# CHANGE MASTER TO
#   MASTER_HOST='192.168.1.10',
#   MASTER_USER='replicator',
#   MASTER_PASSWORD='StrongPass123!',
#   MASTER_LOG_FILE='mysql-bin.000001',
#   MASTER_LOG_POS=154;
# START SLAVE;
# SHOW SLAVE STATUS\G  -- Seconds_Behind_Master が 0 になるまで確認

ステップ3:HyperDBのインストールと設定

WordPressのHyperDBドロップインを使って読み書き分離を実装します。

<?php
// wp-content/db.php に HyperDB を配置後
// wp-config.php の直前に以下を追加

// db-config.php を wp-config.php と同じ階層に配置

// db-config.php の内容:
$wpdb_config = [
    'primary' => [
        'host'     => '192.168.1.10',  // プライマリDB
        'user'     => DB_USER,
        'password' => DB_PASSWORD,
        'name'     => DB_NAME,
        'write'    => 1,
        'read'     => 0,               // プライマリは書き込み専用
        'dataset'  => 'global',
        'timeout'  => 0.2,
    ],
    'replica' => [
        'host'     => '192.168.1.20',  // レプリカDB
        'user'     => DB_USER,
        'password' => DB_PASSWORD,
        'name'     => DB_NAME,
        'write'    => 0,               // レプリカは読み取り専用
        'read'     => 1,
        'dataset'  => 'global',
        'timeout'  => 0.2,
    ],
];

$hyperdb->add_database( $wpdb_config['primary'] );
$hyperdb->add_database( $wpdb_config['replica'] );

ステップ4:レプリケーション監視の実装

レプリケーションの遅延を自動検知するWordPressカスタム関数を実装します。

<?php
// functions.php または mu-plugins に追加

/**
 * レプリケーション遅延を監視する
 * wp_schedule_event で定期実行
 */
function wpdr_check_replication_lag() {
    $replica_host = '192.168.1.20';
    $replica_user = DB_USER;
    $replica_pass = DB_PASSWORD;

    $mysqli = new mysqli( $replica_host, $replica_user, $replica_pass );
    if ( $mysqli->connect_error ) {
        wpdr_send_alert( 'レプリカDBへの接続失敗: ' . $mysqli->connect_error );
        return;
    }

    $result = $mysqli->query( 'SHOW SLAVE STATUS' );
    $status = $result->fetch_assoc();

    $lag = (int) $status['Seconds_Behind_Master'];
    $io_running  = $status['Slave_IO_Running'];
    $sql_running = $status['Slave_SQL_Running'];

    if ( 'Yes' !== $io_running || 'Yes' !== $sql_running ) {
        wpdr_send_alert( 'レプリケーション停止: IO=' . $io_running . ', SQL=' . $sql_running );
    } elseif ( $lag > 30 ) {
        wpdr_send_alert( 'レプリケーション遅延: ' . $lag . '秒' );
    }

    update_option( 'wpdr_last_lag', $lag );
    update_option( 'wpdr_last_check', current_time( 'mysql' ) );
    $mysqli->close();
}

function wpdr_send_alert( string $message ): void {
    wp_mail(
        get_option( 'admin_email' ),
        '[警告] DB レプリケーション異常',
        $message . "\n\nサイト: " . get_site_url()
    );
}

// 5分ごとに監視を実行
add_action( 'wpdr_monitor_hook', 'wpdr_check_replication_lag' );
if ( ! wp_next_scheduled( 'wpdr_monitor_hook' ) ) {
    wp_schedule_event( time(), 'five_minutes', 'wpdr_monitor_hook' );
}

ステップ5:フェイルオーバー処理の実装

プライマリ障害時に自動的にレプリカへ切り替えるフェイルオーバー処理を設定します。

<?php
// wp-content/db.php のカスタムフェイルオーバー設定

/**
 * プライマリDB障害時のフェイルオーバー
 * HyperDB の callback 機能を利用
 */
function wpdr_failover_callback( $hyperdb ) {
    // プライマリへの接続試行が失敗した場合
    $failure_key = 'wpdr_primary_failure_count';
    $failure_count = (int) get_transient( $failure_key );

    if ( $failure_count >= 3 ) {
        // プライマリを無効化し、レプリカを読み書き両用に昇格
        $hyperdb->add_database([
            'host'     => '192.168.1.20',
            'user'     => DB_USER,
            'password' => DB_PASSWORD,
            'name'     => DB_NAME,
            'write'    => 1,  // レプリカを書き込み可能に変更
            'read'     => 1,
            'dataset'  => 'global',
            'timeout'  => 0.2,
        ]);

        // 管理者へ通知
        error_log( '[CRITICAL] WordPress DB フェイルオーバー実行: レプリカをプライマリに昇格' );
        set_transient( 'wpdr_failover_active', true, HOUR_IN_SECONDS );
    } else {
        set_transient( $failure_key, $failure_count + 1, 300 );
    }
}

注意事項

  • レプリカへの書き込みは絶対に行わないこと。super_read_only = ON を必ず設定し、誤操作によるデータ不整合を防ぐ
  • フェイルオーバー後は速やかにプライマリを復旧し、レプリカを元の役割に戻す。レプリカを長期間プライマリとして運用するとデータが失われるリスクがある
  • binlog_format = ROW を使用すること。STATEMENT 形式は非決定的SQL(NOW(), RAND()等)でデータ不整合が発生する可能性がある
  • HyperDBはWordPress.orgの公式リポジトリからダウンロードし、必ずバージョンを確認してから本番環境に適用すること
  • レプリケーション遅延(Seconds_Behind_Master)が常に高い場合、バイナリログのI/O速度やネットワーク帯域を確認する

まとめ

MySQL/MariaDBのプライマリ・レプリカ構成とHyperDBを組み合わせることで、WordPressのデータベース冗長化と読み取り負荷分散を同時に実現できます。次のステップとして「WordPressを高可用性クラスター構成で運用する方法」も参照し、さらに堅牢なインフラ構築を検討してください。

お気軽にご相談ください

お見積りへ お問い合わせへ
▲