以前に
で、mysqlのレプリケーション(replication) について記事にしました。
今回は、そのmysqlのレプリケーションでエラーストップしたときの対処についてです。
特に、今回は、単純なレプリケーションの取扱の誤りであるスレーブ側への書き込みをしてしまった場合のエラーストップの対処を考えてみたいと思います。
直訳のとおり複製を意味します。(レプリカ(replica)と語源は一緒なので、こちらがピンとくるかもしれません)
mysqlでレプリケーションと言うと、マスター、スレーブのそれぞれのmysqlサーバーを構築することに他なりません。
マスター1台に対して、スレーブ複数台というのが一般的なmysqlサーバーの構成になります。
一般的には、マスター mysql サーバー でデータベースの更新処理(書き込み)を受け持ち、スレーブ側で参照処理(読み込み)を受け持つことで負荷を分散させたり、バックアップデータベースを作成するなど行うことができます。
上の図は、その典型的なレプリケーションの例を示したものです。
ユーザは、1台のサーバーにアクセスしているつもりですが、実際のデータベースへの書き込み処理は、バックにあるマスターサーバー側で処理され、データベースの読み込み処理は、フロントのスレーブサーバーで処理されます。
特に参照がメインのサーバーでは、かなりの負荷分散が期待されます。
- 目次
- 履歴
2011年4月6日 初版
レプリケーションの基本
MySQLに限らずレプリケーションの基本を少しおさらいしておきます。
以下の図は、簡単なレプリケーションの関係図を表現しています。
ここで注意すべき点は、
書き込みは、マスターデータベースへ行うこと。
読み込みは、すべてのデータベースで行うことができること。
図では、スレーブデータベースでの読み込みを意図していますが、設定によりマスターでも読み込めます。(一般的にそうします。)
肝心なのは、書き込みです。
書き込みは、常にマスターデータベースにのみ実施されることに注意する必要があることです。
マスターデータベースへ書き込むことで、マスターデータベースは、登録されているスレーブデータベースへコピー(レプリケーション)しようとします。
スレーブデータベースが多ければ、それだけ、ユーザ(アプリケーション)側ですべてのデータベースへの変更を意識する必要がなくなり、効率的でもあります。
一番ありがちなエラーは、スレーブ側に書き込んでしまうケースです。自分もよく失敗しました。今でもレプリケーションの設定をしているのを忘れて書き込んでしまうことも・・・・。
スレーブデータベースでもデータベースに変わりはありませんから、書き込み処理を受け付けますし、SQLに誤りがなければ正常に書きこめてしまいます。
レプリケーションでエラーを発生させてみる
先に書いたようにレプリケーションのスレーブ側に書き込みをすると、マスターとスレーブにデータの不一致が検知されスレーブ側では、同期(レプリケーション)処理を停止します。
これを簡単に再現してみます。
マスターデータベースで以下のようにテーブルを作成して、データを設定してみます。
|
次に、
スレーブデータベースでマスタで更新された情報が反映されたか確認してみます。
|
こんな感じで情報がちゃんとスレーブ側に伝わっていればOK。
スレーブデータベースで以下のように表示されればちゃんと動作しています。
|
さあ次にエラーを発生させてみましょう。
スレーブデータベースで先に作成したテーブルを更新してしまえばエラーになります。
|
こんな感じで情報がちゃんとスレーブ側でレコードの追加はできてしまいますね。
同じようにマスターデータベースでもレコードの追加を行います。
|
これで、マスターとスレーブで完全に不一致が発生します。
スレーブデータベースの状態を確認します。
|
上記表示項目のSlave_SQL_RunningがNoとなって完全に止まってますね。
Errno : 1062は、レコードが重複していてアップデートできない状態であることを意味します。
つまり、マスターで更新されたレコードがスレーブに既にあるのでエラーとなっています。
レプリケーションでエラーを対処してみる
上記のエラー対処方法は、以下のような手順で行います。
- まずは、マスターデータベースを正しい情報に設定する
これは、上記に例でいうとスレーブ側で更新したレコードとマスター側で更新したレコードがあります。
この更新した情報が、いずれも正しい情報であるなら、マスター側を再設定する必要があるでしょう。
また、誤ってスレーブ側を更新してしまったというだけなら、スレーブ側を該当するレコードを削除すれば良いでしょう。
まず大事なことは、マスターデータベースを正しい情報に設定することです。
ここでは、誤ってスレーブにデータを設定してしまったという例なので、マスター側は、そのままで正しいことになります。
スレーブ側の(誤って追加した)データを削除すればOKのはずですね。
AUTO_INCREMENTが気になるところですが、まず問題になることはありません。
- スレーブを起動する
エラーで止まっているスレーブを起動します。
上記のレプリケーションでエラーを発生させてみるで具体的なエラーについて、どのようにエラーを対処したかは、以下のような感じです。
これは、すべてスレーブ側で実施した様子です。
|
最初にスレーブ側で誤って設定してしてしったデータを削除しています。
その後、エラーで停止してしまったスレーブを起動しています。
あとは、確認しているだけなので、手順としては、上の2つだけです。
MySQLのレプリケーションのエラー1062を対処する方法として、以下のような記載があります。
|
SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1;は、エラーを1回無視しなさいということです。
※START SLAVE は、START SLAVE SQL_THREAD; としていることも多い。
これは、とりあえずエラーを回避する上だけで、問題の本質を無視した対処です。
ここでの例では、この対処は誤りになります。
ここで誤って設定してしまったスレーブ側のデータを対処せずに、エラーをスキップさせていることが大きな問題です。
つまり、この対処では、誤って設定してしまったスレーブ側のデータはそのまま残ります。
マスター側とスレーブ側は、アンマッチとなるわけです。
SET GLOBAL SQL_SLAVE_SKIP_COUNTER は、非常に便利なものですが、よく理解した上で利用しましょう。
レプリケーションでエラーをスレーブのリセットで対処してみる
先のエラー対処方法は、自力でデータを修復するようなものです。
実際のトラブルでは、こんなに簡単なパターンは、ほとんどありません。
とりあえず、このスレーブ側のエラーを回避するのは、マスター側にデータを合わせてしまうのは、最も手っ取り早い手順の場合があります。
この手順は、mysqlのレプリケーションを使う のスレーブの設定とほとんど同じです。
その手順を簡単に解説してみます。
- マスターのデータバックアップ
データの書き込みを一時停止します。
mysql> FLUSH TABLES WITH READ LOCK; Query OK, 0 rows affected (0.01 sec)
データのバックアップをtarで1ファイルに固めます。
$ tar cvfz mysql-bin-backup.tar.gz /var/lib/maysql :
バックアップしたデータベースの状態を確認しておきます。
mysql> SHOW MASTER STATUS; +----------------+----------+--------------+------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | +----------------+----------+--------------+------------------+ | bin-log.000001 | 901 | | | +----------------+----------+--------------+------------------+ 1 row in set (0.00 sec)
データの書き込みを一時停止を解除します。
mysql> UNLOCK TABLES; Query OK, 0 rows affected (0.00 sec)
- スレーブでリストア
MySQLを停止します。
$ /etc/init.d/mysqld stop mysqld を停止中: [ OK ]
マスターでバックアップしたデータを展開(リストア)します。
$ tar xvfz mysql-bin-backup.tar.gz /var/lib/maysql ...
MySQLを起動します。
$ /etc/init.d/mysqld start mysqld を起動中: [ OK ]
MySQLのスレーブをリセットし起動します。
mysql> stop slave; Query OK, 0 rows affected (0.00 sec) mysql> reset slave; Query OK, 0 rows affected (0.00 sec) mysql> CHANGE MASTER TO MASTER_HOST='xxx.xxx.xxx.xxx', MASTER_USER='slave-user', MASTER_PASSWORD='slave-password', MASTER_LOG_FILE='bin-log.000001', MASTER_LOG_POS=901; Query OK, 0 rows affected (0.00 sec) mysql> start slave; Query OK, 0 rows affected (0.00 sec) mysql> show slave status \G; *************************** 1. row *************************** Slave_IO_State: Waiting for master to send event Master_Host: xxx.xxx.xxx.xxx Master_User: slave-user Master_Port: 3306 Connect_Retry: 60 Master_Log_File: bin-log.000001 Read_Master_Log_Pos: 901 Relay_Log_File: mysqld-relay-bin.000002 Relay_Log_Pos: 249 Relay_Master_Log_File: bin-log.000001 Slave_IO_Running: Yes Slave_SQL_Running: Yes Replicate_Do_DB: Replicate_Ignore_DB: Replicate_Do_Table: Replicate_Ignore_Table: Replicate_Wild_Do_Table: Replicate_Wild_Ignore_Table: Last_Errno: 0 Last_Error: Skip_Counter: 0 Exec_Master_Log_Pos: 901 Relay_Log_Space: 405 Until_Condition: None Until_Log_File: Until_Log_Pos: 0 Master_SSL_Allowed: No Master_SSL_CA_File: Master_SSL_CA_Path: Master_SSL_Cert: Master_SSL_Cipher: Master_SSL_Key: Seconds_Behind_Master: 0 Master_SSL_Verify_Server_Cert: No Last_IO_Errno: 0 Last_IO_Error: Last_SQL_Errno: 0 Last_SQL_Error: 1 row in set (0.00 sec) ERROR: No query specified
ただ、RESET SLAVE をお忘れなく。
RESET SLAVE を実行しないとエラーが取れません。
エラーを無視するだけなら、
my.conf ( [mysqld]セクション )に
slave-skip-errors = 1062
を追記して、MySQLをリスタートすれば、すべての1062エラーは無視されます。
いろいろな対処がありますが、エラーを発生させないのが一番です。
このサイトでは、コンテンツの一部が非表示、あるいは、コメント、お問い合わせの投稿ができない、検索ができないことがあります。
コメントを投稿 :