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間でデータに差異が発生しない