WordPress/MariaDB を utf8mb4 + unicode_520_ci に統一し、Redis 導入&WP Cron 外部化まで仕上げた実録(hd0.biz /wpm)
最終更新: 2025-10-03
ゴール(今回やったことの全体像)
- 文字コード/照合順序の完全統一:DBサーバ・データベース・テーブル・WordPress のすべてを
utf8mb4 / utf8mb4_unicode_520_ci
に。 - MariaDB 起動エラーの解消:
unknown variable 'default-character-set'
の根本原因を除去。 - Redis オブジェクトキャッシュ導入:Cocoon のページキャッシュとレイヤ分けで併用。
- WP Cron の外部化:
DISABLE_WP_CRON=true
+ systemd timer で5分おきに確実実行。 - スロークエリログ整備:
/var/log/mariadb/slow.log
に常時出力、logrotate 設定まで。
対象環境(主要値)
- WordPress: 6.8.3(パス:
/var/www/html/wpm/
) - MariaDB: 11.4.8
- サイトURL:
WP_SITEURL=https://hd0.biz/wpm
,WP_HOME=https://hd0.biz
- 最終状態(実効)
- WordPress:
DB_CHARSET=utf8mb4
,DB_COLLATE=''
(空),WP_CACHE=有効
、DISABLE_WP_CRON=true
- DBサーバ:
character-set-server=utf8mb4
,collation-server=utf8mb4_unicode_520_ci
- DB/テーブル: データベース
wordpress
の既定もutf8mb4 / utf8mb4_unicode_520_ci
、全テーブルROW_FORMAT=DYNAMIC
かつutf8mb4_unicode_520_ci
- セキュリティ/運用:
FORCE_SSL_ADMIN=ON
,DISALLOW_FILE_EDIT=ON
, Core 自動更新 minor
- WordPress:
実施サマリ
wp-config.php
の重複定義(DB_CHARSET/DB_COLLATE
)を整理。- すべてのベーステーブルを
ROW_FORMAT=DYNAMIC
→utf8mb4_unicode_520_ci
に変換。 - MariaDB の server.cnf を最小構成で統一(
character-set-server
/collation-server
)。 - 起動失敗の根本原因:クライアント設定ファイルの
[mariadb]
にdefault-character-set
があり、サーバがそれを誤って読んでいた → コメントアウト&systemd drop-in の不要設定を退避。 - Redis を WordPress のオブジェクトキャッシュとして使用(
WP_CACHE_KEY_SALT
/DB 番号で衝突回避)。 - WP Cron 外部化:systemd service/timer を作成し 5 分毎に
wp cron event run --due-now
。 - スロークエリログをセットアップ。検証は SESSION で
long_query_time=0
にしてSLEEP()
を流す。
詳細手順
すべて root 実行例。
--allow-root
を付けた WP-CLI を使用。
1) WordPress 側の定義を整理
# 重複防止のバックアップ
cp -a /var/www/html/wpm/wp-config.php /root/wp-config.php.bak.$(date +%F-%H%M) # サンプル:以前の重複を削る(行番号は環境依存なので実際は grep で確認)
grep -nE "define\(\s*'DB_CHARSET'|'DB_COLLATE'" /var/www/html/wpm/wp-config.php
# → DB_CHARSET は 'utf8mb4'、DB_COLLATE は ''(空)を1つだけ残す
最終形(抜粋)
define('DB_CHARSET', 'utf8mb4');
define('DB_COLLATE', ''); // 本番デバッグ方針
define('WP_DEBUG', false);
define('WP_DEBUG_DISPLAY', false);
define('WP_DEBUG_LOG', true); // WP_DEBUG=true の時に有効 // 運用・セキュリティ
define('FORCE_SSL_ADMIN', true);
define('DISALLOW_FILE_EDIT', true);
2) テーブルを ROW_FORMAT=DYNAMIC & utf8mb4_unicode_520_ci に
# DYNAMIC に統一
/usr/local/bin/wp --allow-root --path=/var/www/html/wpm db query \
"SELECT TABLE_NAME FROM information_schema.TABLES \ WHERE TABLE_SCHEMA=DATABASE() AND TABLE_TYPE='BASE TABLE' AND TABLE_NAME<>''" \ --skip-column-names | awk 'NF' | while read -r t; do echo "ROW_FORMAT=DYNAMIC: $t" /usr/local/bin/wp --allow-root --path=/var/www/html/wpm db query \ "ALTER TABLE \`$t\` ROW_FORMAT=DYNAMIC;" done # 文字コード/照合順序を変換
/usr/local/bin/wp --allow-root --path=/var/www/html/wpm db query \
"SELECT TABLE_NAME FROM information_schema.TABLES \ WHERE TABLE_SCHEMA=DATABASE() AND TABLE_TYPE='BASE TABLE' AND TABLE_NAME<>''" \ --skip-column-names | awk 'NF' | while read -r t; do echo "CONVERT: $t" /usr/local/bin/wp --allow-root --path=/var/www/html/wpm db query \ "ALTER TABLE \`$t\` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_520_ci;" \ || { echo "*** ERROR converting $t"; exit 1; } done # 変換漏れの確認(0行ならOK)
/usr/local/bin/wp --allow-root --path=/var/www/html/wpm db query \
"SELECT TABLE_NAME, TABLE_COLLATION FROM information_schema.TABLES \ WHERE TABLE_SCHEMA=DATABASE() AND (TABLE_COLLATION IS NULL OR TABLE_COLLATION NOT LIKE 'utf8mb4%');" \ --skip-column-names
3) MariaDB: サーバ設定を最小で統一
/etc/my.cnf.d/server.cnf
(抜粋)
[mysqld]
# 通信まわり
net_read_timeout = 60
net_write_timeout = 120
max_allowed_packet = 64M # 文字コード統一
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_520_ci # (任意)スロークエリログは §6 で設定
重要:起動失敗の根本原因
/etc/my.cnf.d/client.cnf
の [mariadb] セクションにdefault-character-set=utf8mb4
を書くと、サーバ(mariadbd)がそれを拾ってしまい、unknown variable 'default-character-set=utf8mb4'
で起動に失敗する場合がある。- 対策:[mariadb] 節の
default-character-set
をコメントアウト。[client]
/[mysql]
など“純クライアント側”だけに置く。
# 反映確認(mysqld に渡る既定)
/usr/sbin/mariadbd --print-defaults
# → ここに default-character-set が出てこないこと
systemd drop-in にも注意
# 実際に有効な設定を確認
a) systemctl cat mariadb.service | sed -n '/mariadb.service.d/,$p'
# 不要な drop-in があれば退避
b) mv /etc/systemd/system/mariadb.service.d/migrated-from-my.cnf-settings.conf \ /root/mariadb-dropin.bak/ 2>/dev/null || true
systemctl daemon-reload
systemctl restart mariadb
4) WordPress 側の実効値を確認
# 文字コード・照合順序(WPオブジェクト)
/usr/local/bin/wp --allow-root --path=/var/www/html/wpm eval \ 'global $wpdb; echo "wpdb->charset={$wpdb->charset}\nwpdb->collate={$wpdb->collate}\n";' # 表示用のブログ文字セット(通常 UTF-8)
/usr/local/bin/wp --allow-root --path=/var/www/html/wpm option get blog_charset
5) Redis オブジェクトキャッシュ導入
Cocoon のページキャッシュ(WP_CACHE)とは別レイヤ。併用で相乗効果。
プラグイン導入 & ドロップイン有効化
/usr/local/bin/wp --allow-root --path=/var/www/html/wpm plugin install redis-cache --activate
/usr/local/bin/wp --allow-root --path=/var/www/html/wpm redis enable
wp-config.php
例(重複定義に注意)
// Redis Object Cache
define('WP_CACHE', true); // ページキャッシュ系と共存OK
define('WP_REDIS_HOST', '127.0.0.1');
define('WP_REDIS_PORT', 6379);
define('WP_REDIS_DATABASE', 0); // 他用途と共用なら専用番号に
define('WP_CACHE_KEY_SALT', 'hd0.biz:'); // キー衝突回避
// define('WP_REDIS_MAXTTL', 86400); // 任意:最大TTL(秒)
動作・メンテ
# ステータス(サブコマンドは環境によって異なる)
/usr/local/bin/wp --allow-root --path=/var/www/html/wpm redis status || true # キャッシュ全消去(WordPress経由なので安全)
/usr/local/bin/wp --allow-root --path=/var/www/html/wpm cache flush
wp redis flush/info
が無い環境でも、wp cache flush
で十分。Redis を他システムと共有する場合はWP_CACHE_KEY_SALT
か DB 番号を必ず分ける。
6) WP Cron を外部化(systemd timer)
DISABLE_WP_CRON=true
にしたので、OS側で 5 分ごとに実行。
ユニット作成
# Service: 期限到来分を即時実行
cat >/etc/systemd/system/wp-cron-wpm.service <<'EOF'
[Unit]
Description=Run WordPress cron for /var/www/html/wpm [Service]
Type=oneshot
ExecStart=/usr/local/bin/wp --allow-root --path=/var/www/html/wpm cron event run --due-now --quiet
EOF # Timer: 5分おき
cat >/etc/systemd/system/wp-cron-wpm.timer <<'EOF'
[Unit]
Description=Schedule WordPress cron for /var/www/html/wpm [Timer]
OnBootSec=2min
OnUnitActiveSec=5min
AccuracySec=1s
Unit=wp-cron-wpm.service [Install]
WantedBy=timers.target
EOF systemctl daemon-reload
systemctl enable --now wp-cron-wpm.timer # 動作確認
systemctl status wp-cron-wpm.timer --no-pager
systemctl list-timers --no-pager | grep wp-cron-wpm # いますぐ実行
systemctl start wp-cron-wpm.service
journalctl -u wp-cron-wpm.service -n 50 --no-pager
timer と crontab の二重起動はNG。どちらか一方に統一。
Cron イベントの可視化/手動実行
/usr/local/bin/wp --allow-root --path=/var/www/html/wpm \ cron event list --fields=hook,next_run_gmt,next_run_relative --format=table | head /usr/local/bin/wp --allow-root --path=/var/www/html/wpm cron event run --due-now
7) MariaDB スロークエリログ整備
サーバ設定(server.cnf
の [mysqld])
slow_query_log = ON
slow_query_log_file= /var/log/mariadb/slow.log
long_query_time = 1
初期化・権限
install -d -o mysql -g mysql -m 750 /var/log/mariadb
: > /var/log/mariadb/slow.log
chown mysql:mysql /var/log/mariadb/slow.log
chmod 640 /var/log/mariadb/slow.log
systemctl restart mariadb
logrotate(/etc/logrotate.d/mariadb-slow
)
/var/log/mariadb/slow.log { daily rotate 7 missingok compress delaycompress notifempty create 640 mysql mysql postrotate systemctl kill -s USR1 mariadb.service 2>/dev/null || true endscript
}
確実にログへ書かせるテスト
# そのセッションだけ 0 秒にして強制的に拾わせる
mariadb -e "SET SESSION long_query_time=0; SELECT SLEEP(0.2) AS t;" tail -n 20 /var/log/mariadb/slow.log
long_query_time
は セッション変数でもあるため、GLOBAL を 0 に変えて同一セッションで計測しても拾われないことがある点に注意。
ハマりポイント / トラブルシュート
- mariadbd 起動失敗:
unknown variable 'default-character-set=utf8mb4'
- 原因:
/etc/my.cnf.d/client.cnf
の [mariadb] にdefault-character-set
。サーバが解釈して落ちる。 - 対応:当該行をコメントアウト。
/usr/sbin/mariadbd --print-defaults
で mysqld に渡るオプションから消えていることを確認。
- 原因:
- systemd drop-in による意図しない上書き
systemctl cat mariadb.service
でmariadb.service.d/
の存在を確認。不要なら退避しdaemon-reload
。
- WP-CLI を root で実行
--allow-root
を必ず付ける。sudo -u apache
での実行は環境次第でこのアカウントは現在利用できません
となる。
wp redis
サブコマンドが少ない- 環境により
info/flush
が無い場合あり。wp cache flush
で十分。
- 環境により
運用ワンライナー(任意)
# 1) WP全キャッシュ消し → 2) 期限到来Cron実行 → 3) DB簡易最適化
/usr/local/bin/wp --allow-root --path=/var/www/html/wpm cache flush && \
/usr/local/bin/wp --allow-root --path=/var/www/html/wpm cron event run --due-now --quiet && \
/usr/local/bin/wp --allow-root --path=/var/www/html/wpm db optimize
ロールバック手順(万一のとき)
wp-config.php
をバックアップから戻す。cp -a /root/wp-config.php.bak.YYYY-MM-DD-HHMM /var/www/html/wpm/wp-config.php
- DB をダンプから復元(例:
/root/hd0biz_before_utf8mb4.sql
)。mariadb -u root -p wordpress < /root/hd0biz_before_utf8mb4.sql
- MariaDB / PHP-FPM / Web サーバを再起動し、フロント/管理の基本動作を確認。
参考:最終チェックコマンド集
# WP / DB 文字コードの実効値
/usr/local/bin/wp --allow-root --path=/var/www/html/wpm eval 'global $wpdb; echo "$wpdb->charset / $wpdb->collate\n";'
/usr/local/bin/wp --allow-root --path=/var/www/html/wpm option get blog_charset
mariadb -e "SHOW VARIABLES LIKE 'character_set_server'; SHOW VARIABLES LIKE 'collation_server';" # Cron
systemctl list-timers --no-pager | grep wp-cron-wpm
/usr/local/bin/wp --allow-root --path=/var/www/html/wpm cron event list --fields=hook,next_run_gmt,next_run_relative --format=table | head # Redis(導入済みならステータス)
/usr/local/bin/wp --allow-root --path=/var/www/html/wpm redis status || true # Slow log
mariadb -e "SHOW VARIABLES LIKE 'slow_query_log%'; SHOW VARIABLES LIKE 'long_query_time'; SHOW VARIABLES LIKE 'log_output';"
結論
- utf8mb4 + unicode_520_ci で完全統一でき、WordPress/DB/サーバのズレが解消。
- Redis + Cocoon の二層キャッシュ、WP Cron 外部化、スローログまで整備し、安定かつ観測可能な運用に移行。
- あとはアクセス状況に応じて、オブジェクトキャッシュの TTLやログインユーザのページキャッシュ除外などを微調整すれば完成度はさらに上がる。
調整ポイント(任意):
- 投稿リビジョン上限 50 → 20 程度も検討余地
- PHP の
memory_limit
が WP の上限(768M)を下回っていないか確認- アクセス増に応じて Redis の
maxmemory
ポリシーやWP_REDIS_DATABASE
の分離も検討