FAT47の底辺インフラ議事録

学んだことのメモ帳です

online-schema-changeを過信していたら痛い目をみた話

先日記事に書いたように、無停止のALTER文実行では
Percona-ToolkitのOnline-schema-changeを利用しています。
無停止でALTERできるPercona-Toolkitのonline-schema-change

オンラインでのカラム追加
私が担当しているサービスでは、ALTER文実行時にレプリケーションの遅延を出来るだけ発生させたくないので、
以下の様な手順でOnline-schema-changeを実行しています。

(1) スレーブ全台でOnline-schema-changeの実行
(2) マスターでOnline-schema-changeの実行(--set-vars="sql_log_bin=0"のオプション指定)

"sql_log_bin=0"オプションをつけて実行すると、binlogを出さずに実行できるので、
マスターで実行してもそのクエリはスレーブにレプリケーションされません。

この手順でINDEXの追加やカラムの追加などを実行していました。

事故の発生
いつものように、スレーブでonline-schema-change実行後、マスターで実行させました。
すると、一斉にアラートメールが。。。
スレーブ全台がエラーでレプリケーション停止してました。

Last_SQL_Error: Error executing row event: 'Table 'hoge._user_new' doesn't exist'
 Replicate_Ignore_Server_Ids:

事故の概要
"sql_log_bin=0"オプションを指定して実行したマスターDBでの作業時に、
なぜかトリガーの作成がスレーブにレプリケーションされて、
スレーブ側で存在しないテーブルへ更新が走るようになりエラーで停止しました。

そもそも、Online-Schema-Changeの仕組みとしては、先日記事に書いたとおり

online-schema-changeの仕組み
1. 対象テーブルと同じ構造をした作業用テーブルを作成する
2. 作業用テーブルに変更するALTER文を適用する
3. 3つトリガーを作成して、対象テーブルへの挿入・削除・更新が作業用テーブルに反映されるようにする
4. 対象テーブルから作業用テーブルへデータをコピーしてくる
5. RENAMEして対象テーブルと作業用テーブルを入れ替える
6. 入れ替え後の古いテーブルとトリガーを削除する

http://d.hatena.ne.jp/fat47/20140418/1397811745

このようになっています。
この(3)での処理がなぜかスレーブにも伝搬して、

Last_SQL_Error: Error executing row event: 'Table 'hoge._user_new' doesn't exist'
 Replicate_Ignore_Server_Ids:

このhoge._user_newテーブルへの更新がスレーブで走るようになってしまいました。

発生した環境
バージョン
DBマスター

OS CentOS5.4
DB MySQL5.5.24
Percona-Toolkit 2.2.7-1

DBスレーブ

OS CentOS6.2
DB MySQL5.5.24
Percona-Toolkit 2.2.7-1

発行したSQL

ALTER TABLE `user` ADD COLUMN fuga int(10) NOT NULL DEFAULT '0' COMMENT 'fugafuga';

対象テーブルのデータ件数

select count(*) from user;
+----------+
| count(*) |
+----------+
| 18476032 |
+----------+
1 row in set (9.09 sec)

検証環境でいろいろ試してみた
本番データを入れて検証環境で試してみました。
ちなみに、今回データ数の少ないステージング環境で事前に試していましたが、そちらの動作では問題ありませんでした。

エラー出て失敗したパターン
■DBMのOSバージョンを入れ替える
DBMをCentOS6.2、DBSをCentOS5.4に

MySQLのバージョンを上げてみる
MySQL5.5.24から5.5.34に

■Percona-Toolkitのバージョン下げてみる
他サービスで動作実績のある2.2.6に

■カラム追加ではなくてINDEX追加にして実行してみる


エラー出ずに実行完了したパターン
■別のテーブルにカラム追加してみる

■他サービスで実行成功したテーブル(今回のテーブルよりデータ量2倍)で確認してみる。
他サービスのテーブルをdumpして検証環境に挿入して実行


とりあえず結果
一部の条件を満たすテーブルでのみバグが発生する
でも、一部の条件がわからない…。なんだろう。。。

今後の対策
スレーブ側で作業テーブルがないためエラーになってしまうので、
スレーブ実行後に事前に作業テーブル(_テーブル名_new)を作成しておけば、仮にスレーブ側で
トリガーが作成されてしまってもエラーでレプリ停止することはない。
マスターで実行完了後に、スレーブで作成した作業テーブルをDROPする。

最後に
怖い作業やるときは、事前に本番と同様の環境で動作チェックすること!
本番に近いデータ量じゃないと再現しないこともある!



_| ̄|● サービス停止させて、本当に本当に申し訳ありませんでした。