今回はcp932からutf8mb4に変更した話をします。
長年運用されているサービスでは、同じような課題があると思うので参考になればと思います。
何故対応する必要があったの?
- 絵文字が使えない
cp932(ShifJIS)で構成されているため、絵文字が化けてしまい、ユーザの体験を下げていた。<emoji:xxx>
などの絵文字コードで絵文字変換する仕組みを自前で実装しているが、メンテナンスコストが高くなっていた。 - utf8mb4のテーブルとのJOINが遅い
各テーブルのIDをvarchar(255)で定義しているため、utf8mb4で定義したテーブルとJOINするとINDEXが適用されない。cp932にキャストすることで改善できるが本質的な改善ではない。
これらの課題を解決するため、全てのテーブルをutf8mb4に統一を行うことになりました。
実際の移行手順
以下の手順を開発環境で検証し、問題なく移行できると判断した後に対応しました。
また、本番環境では余裕を持ったメンテナンス日程を決めて事故がないように確認しながら進めています。
文字コードを変更してレプリケーションする
-
パタメータグループをコピーして slave_type_conversions = ALL_NON_LOSSY にしたものを作成する
-
パラメータグループを 1. で設定したものにしてDBをスナップショットから復元
- システム取得のスナップショットからではなく復元前にスナップショット取得する
-
レプリケーション設定
-
既存DBでレプリケーションの設定を実行する
CREATE USER 'repl_user'@'%' IDENTIFIED BY 'pass123'; GRANT REPLICATION CLIENT, REPLICATION SLAVE ON *.* TO 'repl_user'@'%'; # bin logの確認 SHOW MASTER STATUS;
-
新しいDBでレプリケーション設定を行う
⚠ ポジションを間違えないように注意 ⚠
ポジションは復元したRDSのログに記載されているCALL mysql.rds_set_external_master ('xxxxx', 3306,'repl_user', 'pass123', 'mysql-bin-changelog.xxxx', xxxx, 0); CALL mysql.rds_start_replication;
-
-
スレーブ側の全テーブルのALTER TABLE(先にレプリケーションを止める)
CALL mysql.rds_stop_replication;
- 照合順序の指定が必要なカラムの対応&全テーブルの文字コード変換
- 照合順序の個別設定ALTER
-- 全テーブル分文字コード変換するALTERを作成 SELECT CONCAT(CONCAT('ALTER TABLE ', table_name),' CONVERT TO CHARACTER SET utf8mb4;') FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'xxxx';
-
ALTERした後にレプリケーション再開してエラーなくレプリケーションが追いついたことを確認
-
メンテナンスを入れる
- パラメータグループを戻す(レプリケーション先クラスター)
- アプリケーションの向き先を変更する
ボツ案
上記で移行出来ましたが、検討する際に何個かの案を試行錯誤しながら確定させていきました。
参考までにですが、ボツとした案も以下に記載します。
案① シンプルに置き換えるパターン
ボツの理由
- データ量が多く時間がかかりすぎる(1番大きいテーブルで1時間以上かかるため)
検証方法、やること
- 本番相当のデータをdevに持っていく
- ALTERテーブルでテーブルのスキーマ情報をutf8mb4にする
ALTER TABLE xxx CHARACTER SET utf8mb4;
ALTER TABLE xxx CONVERT TO CHARACTER SET utf8mb4;
メリット
- 最小の手間で済む
デメリット
- ALTERにかかる時間検証が必要
- ダウンタイムが発生する可能性あり
案② ダブルライトパターン
ボツの理由
- 影響範囲が大きすぎるので、対応が現実的ではない
検証方法、やること
- 本番相当のデータをdevに持っていく
- 新定義のDBをutf8mb4で作成する
- CREATE TRIGGERで別のDBにアクセスする
- 並行してメンバーなどの全データ移行batchも作成する
- 数ヶ月の後、データが溜まったタイミングで置き換える
メリット
- ダウンタイムはなし
デメリット
- 全テーブルのダブルライトは工数が最大になる
- 影響範囲が大きい = オペレーションミスが発生する