ケース-誤って削除されたテーブル

4492 ワード

ある日の午后、テストライブラリにデータを入力していたところ、切断されたwarningsがあるのを见て、テーブルdeleteを落として、再インポートした.このインポート操作をすると同时に、オンラインで业务にupdateデータの操作をしていたが、突然、テストライブラリのsecureCRTをテストの窓口にして、delete操作をしていた.2秒后に削除に成功しなかった.テーブルの名前を见ると、オンライン业务のテーブルだった.その场で呆然とした
すぐにctrl+cはdelete文をキャンセルしますが、myshardミドルウェアを使用しているため、インデックスctrl+vは使用されていません.deleteの文は、下に掛けられているmysqlに渡されて実行され、2000万のテーブルが削除されました.世界で9つのノードが、dml sqlを同期しているため、すべてのノードのテーブルが削除されました.
しかしmyshardには保護メカニズムがあり、各行のデータに1つの__が追加されます.deletedフィールド、myshardのdeleteデータは、mysqlレベルのupdate deleted=1に相当し、3日後にデータを削除するのは、人為的な誤操作を防ぐためです.
そこで私はビジネスで最も多くのノードを選択し、mysqlレベルに入り、SET sql_log_bin=0、その後
updateテーブルset deleted=0 where deleted=1
1つのノードを回復するのに5分かかります.最初のノードを回復した後、すぐに業務に通知します.世界で表を変更した業務を、回復したノードに切ります.他のノードは先に使用しないでください.そこで、徐々に他のノードを回復して、最後に全部で20分を費やしてデータを回復します.
もちろんこの5分间、すべてのノードのこのテーブルはデータがないが、データが検索できないとは限らない.redisが担いでいるため、redisのヒット率は95%で、redisでデータが検索できないだけで、DBで検索してデータが取得できない场合がある.
その时はこれで终わったと思って、会议に行って、会议から帰ってきた后、业务はデータベースの同期に问题があると言って、データは一致しませんでした......
カーネル開発の同僚と調査したところ、誤操作を行ったノードのデータは、他のノードにうまく同期できないことが分かった.原因は2千万の表、delete文が下りると、18 Gのbinlogが生成されたが、myshardのsync同期プロセスでは、4 G以上のbinlogファイルを認識できず、位置点を負の数に変えたが、負の位置点の監視は私たちの監視スクリプトが上書きされていないことだ.
-rw-rw----. 1 mysql mysql 101M May 31 16:33 mysql-bin.270756
-rw-rw----. 1 mysql mysql  18G May 31 16:38 mysql-bin.270757
-rw-rw----. 1 mysql mysql 101M May 31 16:38 mysql-bin.270758

方法はその18 Gのbinlogをスキップして、直接次のbinlogにつながって、先に同期を回復して、同期は20 G遅れて、同期が追いかけた後に、大体4時間のデータの遅延をもたらして、チャージの遅延は招きます
このmysql-bin.2707757のバイナリログは、5分で生成されますが、実際にはmyshardの下のMySQLレベルに入って、唯一のdelete文killを直接落とすことでbinlogのサイズを減らすことができ、データの生成時間を減らすことができますが、急いで反応しませんでした.
18 Gのbinlog、99%はそのdelete SQLが生成したrowモードのデータファイルですが、その間に他の業務の正常なSQLがあり、大衆評価のbinlog 2 sqlを使って仕事を再開しました.目的はバイナリファイルを具体的なSQL文に解析することです.
mysqlbinlogを使用して解析してもいいですが、具体的なSQL文は見えませんが、ビジネスは具体的なSQLを見てから回復する必要があります.例えば、update a=a+100のようなチャージ文は、直接更新できません.過去の値に依存しています.過去の値が正確ではありません(データの遅延)、更新が戻ってくると問題が発生します.このようにビジネスにどのように処理するかを測定します.具体的なSQL文を抽出しなければなりません
https://github.com/danfengcao/binlog2sql
実はアリにもbinlog解析ツールがありますが、アリが最後に出力した結果は逆解析です.例えばdeleteの文、アリのツールはinsertを生成します.私のシーンは正常なsqlを抽出するだけでいいので、逆解析は必要ありません.
しかし、大衆評価でもアリのツールでも、information_を取得するためにオンラインでデータベースに接続する必要があります.schema.columnsテーブルは、テーブルのフィールド名を取得し、binlog解析後の@1,@2,@3フィールドに置き換えますが、この18 GのbinlogをonlineのDBで解析したくないので、cpuリソースの消費を心配して、この18 Gのbinlogをテストライブラリにコピーします.
長い間考えていてやっと一つの方法を思いついたのは、テストライブラリをonlineのデータベースに偽装して、テストライブラリのschemaをすべて削除して、それから現在のbinlogの名前を、18 Gのbinlogの名前に置き換えて、脳の穴が少し大きいと感じて、しかしツールは使うことができて、その時書いたスクリプトの肝心な部分はこのようにしました
able_array=(
 1
 2
 3
.......
 
)
for table_name in "${table_array[@]}";do
    python binlog2sql.py -h127.0.0.1 -P  -u  -p   -d  --start-file='18G binlog ' -t${table_name} > /data1/flashback/"${table_name}".sql
done

そこで18 Gのsqlをすべて解析して、例えばこのようなフォーマット、SQL文があって、时間があって、すべてのSQL文は1行占めて、そこで業務に知らせて、更に回復の事を続けます
INSERT INTO `myshard`.`xxxxxxxxx`(`status`, `actor_uid`, `style`, `ctime`, `__deleted`, `__version`, `sid`, `date`, `utime`, `type`, `uid`) VALUES (0, xxxxxxxxx, 0, 1496219633, 0, xxxxxxxxx, xxxxxxxxx, 20170531, 1496219633, 1, 1605227422); #start 106192 end 106420 time 2017-05-31 16:33:53
INSERT INTO `myshard`.`xxxxxxxxx`(`status`, `actor_uid`, `style`, `ctime`, `__deleted`, `__version`, `sid`, `date`, `utime`, `type`, `uid`) VALUES (0, xxxxxxxxx, 0, 1496219633, 0, xxxxxxxxx, xxxxxxxxx, 20170531, 1496219633, 3, 1573543992); #start 258936 end 259164 time 2017-05-31 16:33:53
INSERT INTO `myshard`.`xxxxxxxxx`(`status`, `actor_uid`, `style`, `ctime`, `__deleted`, `__version`, `sid`, `date`, `utime`, `type`, `uid`) VALUES (0, xxxxxxxxx, 0, 1496219634, 0, xxxxxxxxx, xxxxxxxxx, 20170531, 1496219634, 3, 1509357246); #start 473268 end 473496 time 2017-05-31 16:33:54
INSERT INTO `myshard`.`xxxxxxxxx`(`status`, `actor_uid`, `style`, `ctime`, `__deleted`, `__version`, `sid`, `date`, `utime`, `type`, `uid`) VALUES (0, xxxxxxxxx, 0, 1496219636, 0, xxxxxxxxx, xxxxxxxxx, 20170531, 1496219636, 1, 1610811581); #start 1114346 end 1114574 time 2017-05-31 16:33:56
INSERT INTO `myshard`.`xxxxxxxxx`(`status`, `actor_uid`, `style`, `ctime`, `__deleted`, `__version`, `sid`, `date`, `utime`, `type`, `uid`) VALUES (0, xxxxxxxxx, 0, 1496219636, 0, xxxxxxxxx, xxxxxxxxx, 20170531, 1496219636, 1, 1593006833); #start 1295075 end 1295303 time 2017-05-31 16:33:56

今回の最大の教訓はdelete,rm,rsync,mv,updateの操作を実行する前に、ip,インスタンスを確認し、5秒黙読してから操作を実行し、慎重にすることです.