TORACON_QUEST ~そして障害へ~
問題文
概要
とあるゲーム会社に務めるA君は、以前運営していたオンラインゲームのシステムを再利用し、最近サービスが開始されたオンラインゲーム『TORACON QUEST』のデータベースのレプリカを作成をするよう頼まれました。
A君は、レプリカの作成をしたことが無かったのですが、インターネットの情報を元になんとかレプリケーション構成を組むことができました。
しかし、上司のBさんが確認したところMasterサーバのレプリカがSlaveサーバに正常に作成されていないことが判明しました。
A君の代わりに、MasterサーバとSlaveサーバ間でデータの差異が無いレプリケーション構成を組んであげてください!
ただし、Masterサーバのデータベースが正しいので、レプリケーション後のデータベースはMasterサーバのデータを元にしてください!
初期状態
- MasterサーバのDBに保存してある情報が正しい
- SlaveサーバのDBは一部のデータが誤っている
- 一部のクエリをMasterサーバに投げるとMasterサーバとSlaveサーバでデータの差異が生まれてしまう
- replはA君がレプリケーションを組んだときに作成したMySQLのレプリケーション用ユーザーである
終了状態
- どのようなクエリをMaster側に投げてもSlave側とデータの差異が発生しないレプリケーション構成が組めている
- 各データベースで初期状態のMasterサーバのデータベースを元に作成されたデータが保存されている
解説
トラブルの原因
今回、問題を解いてくださった皆さまありがとうございました! この問題では、MySQLのレプリケーションという技術を使用して、DB1の複製(レプリカ)をDB2に作成しようとしたところ問題が発生した、という内容でした。
このレプリケーションを行う際、Master側(今回はdb1)のMySQL binlogを元にSlave側(今回はdb2)にデータの複製を行います。
そのときに、binlogのフォーマットが複数存在し、そのうちのSTATEMENTを選択すると非決定的な関数(例えば、UUID()やユーザー定義関数)の値がMaster,Slave間のデータベース上で不一致が発生してしまうことがあります。(ちなみに、rand()はMySQLの仕様で暗黙的にseed値が揃えられているのでデータが一致していたはずです。)
今回の問題では、この不一致が発生した状況から開始となりました。
なので、復旧するにはMasterのバックアップをSlaveに上書きしてあげて、my.cnfにbinlog_format=row
を設定してあげなければいけません。
解決方法
VM02の作業
- vm02のmysqlがstopしてることを確認する
$ sudo systemctl status mysql
● mysql.service - LSB: Start and stop the mysql database server daemon
Loaded: loaded (/etc/init.d/mysql; bad; vendor preset: enabled)
Active: inactive (dead)
Docs: man:systemd-sysv-generator(8)
$ sudo systemctl start mysql
各VMで操作
- vm01とvm02にsshし、/etc/mysql/conf.d/mysql.cnfの
[mysqld]
以下に次の設定を記述する。
binlog_format=row
vm01で作業
- vm01のmysqlを起動する。
$ sudo systemctl restart mysql
- binlogの書き込みロックと状態の確認を行う。
- ここでFileとPositionを確認して覚えておきます。(この値を後で使用します。)
mysql> flush tables with read lock;
mysql> show master status;
- vm01にsshし、dumpを作成してscpでvm02に送信する。(dumpを送受信できればsftpなどでも問題ありません)
$ mysqldump --single-transaction -u root -p TORACON_QUEST > backup.dump
$ scp backup.dump user@192.168.18.2:~
- 最後にテーブルのロックを解除します。
mysql> unlock table;
ここからVM02
- vm02のmysqlを起動
$ sudo systemctl restart mysqld.service
- dumpデータを用いて正しいテーブルを作成
mysql> stop slave;
mysql> drop database TORACON_QUEST;
mysql> create database TORACON_QUEST;
mysql> use TORACON_QUEST;
mysql> source ~/backup.dump;
- 一度レプリケーションが止まってしまっているので、リレーログ周りの設定を初期化する。
mysql> RESET SLAVE;
- masterの情報を入れておく
mysql> change master to master_host='192.168.18.1', master_user='repl',master_password='PlzComeToICTSC2020',master_log_file='[さっきメモした値(File)]',master_log_pos=[さっきメモした値(Position)];
- レプリケーションを再開
mysql> start slave;
ここまで行うと終了条件をすべて満たすことができる。
トラブルシュートできたかの検証方法
- MasterのTQ_ITEMに以下のようなクエリを用いてUUIDが同じ状態になっているかを確認する
mysql> INSERT INTO TQ_ITEM (ItemID,WeaponID,Attack,UUID,UserID) VALUES (2020,1,ROUND(RAND()*(99999-1)+1,0),UUID(),8);
採点基準
- 25%:元のMasterサーバのデータの移行が済んでいる
- 25%:Mysqlのコンフィグファイル内でrowもしくはmixedベースのレプリケーションが組む内容が記入されている
- 25%:systemctl start mysqlなど細かく内容について書かれている。
- 25%:レプリケーションが組めている
【合計】
- 100%: UUID()を含むクエリを投げてもMasterSlave間でデータに差異が発生しない