加班到2點,一不小心我把MySQL刪了
大家好,我是Leo。目前在常州從事Java后端。上一篇文章我們介紹了線上數據庫掛了一個節點之后,應該如何排查節點宕機問題。從select 1 ,外部統計,內部統計等一系列流程方案的介紹。這一篇我們介紹一下線上數據庫誤刪數據后,到底是跑路還是該如何解決!
思路
本篇文章的介紹思路以下圖的思維導圖為大綱。也有利于讀者更好的分辨可讀性!
誤刪行
誤刪行這種情況應該是比較常見的,有些時候為了解決數據問題,我們直接刪了這一行。刪完之后才反應過來刪錯了。接下來我們介紹一下,我們應該如何處理!
提到誤刪行,就必須涉及到兩個參數 binlog_format=row binlog_row_image=FULL
binlog_format=row
這個參數我們在前面介紹binlog日志的時候介紹過。主要分row, statement,mixed
這里為什么必須設置為row呢,因為只有記錄詳細的日志信息,作恢復數據的時候才好操作。statement肯定是不夠的。mixed也是不符合的,因為完全不需要判斷!
binlog_row_image=FULL
這個是由上列參數同時引入的一個新的參數。當前有兩個選擇項,FULL記錄每一行的變更,minimal只記錄影響后的行。默認使用FULL。
步入正題了。。。。。。
可以通過Flashback 工具通過閃回把數據恢復回來。數據恢復的原理就是修改binlog內容,拿回主庫重新加載。要使用當前方法同時也要對事物進行修改操作如下。
- 對于 insert 語句,對應的 binlog event 類型是 Write_rows event,把它改成 Delete_rows event 即可;
- 同理,對于 delete 語句,也是將 Delete_rows event 改為 Write_rows event;
- 而如果是 Update_rows 的話,binlog 里面記錄了數據行修改前和修改后的值,對調這兩行的位置即可。
如果執行的是多個事務,比如原本是A,B,C。想要數據恢復的話那就直接順序反過來即可,也就是C,B,A
建議: 不過不建議主庫直接執行,比較安全的做法是恢復出一個備份,或者找一個從庫作為臨時庫,在這個臨時庫上執行這些操作。然后再將確認過的臨時庫數據,恢復回主庫。
預防
- 把 sql_safe_updates 參數設置為 on。這樣一來,如果我們忘記在 delete 或者 update 語句中寫 where 條件,或者 where 條件里面沒有包含索引字段的話,這條語句的執行就會報錯。
- 代碼上線前,必須經過 SQL 審計。
如果要刪除表的數據量比較大,并且確認數據是無用的,不建議使用delete。這樣會生成并寫入redo log,binlog,回滾日志等。采用truncate table 或者 drop table 命令可以節省性能
為什么采用truncate table 或者 drop table可以節省性能?
上文我們說到, 必須設置 binlog_format=row 。這里我們要說明一下,雖然我們配置的是沒問題的,但是內部機制的問題。使用這兩個命令會自動設置成statement 所以這兩個命令保存的日志比較簡單。恢復不了數據。性能比較好。
如果真刪了呢?
誤刪表/庫
如果真刪了還是有辦法的。不過稍微比較費事。這也是最低的底牌了。全量備份+增量備份 。這種方案要求線上有定期的全量備份,并且實時備份。
這個方案類似于Redis的AOF和RDB。那么他們是如何操作的呢?
假如有人中午12點誤刪了一個庫
取最近的一次全量備份,假如備份時間是凌晨3點,一天一備。
用備份恢復出一個臨時庫;
從日志備份里面,取出凌晨 3 點之后的日志;
把這些日志,除了誤刪除數據的語句外,全部應用到臨時庫。
擴展
- 上述在做數據恢復的時候,如果這個臨時庫有多個數據庫。在使用mysqlbinlog命令時加一個-database參數。指定表所在的庫避免恢復數據時還要查找其他庫的日志情況。
- 如果使用了GTID模式,就省事多了,只需要將未執行的gtid1加到臨時實例的GTID集合中,之后按順序執行binlog就可以了。
- 如果沒有使用GTID模式,還是比較麻煩的。只能在應用到包含 12 點的 binlog 文件的時候,先用–stop-position 參數執行到誤操作之前的日志,然后再用–start-position 從誤操作之后的日志繼續執行;
性能優化
這樣的流程從性能上考慮還是比較慢的,因為操作的話往往是一個庫,一個實例。如果恢復的是一個表的話就多此一舉了。也不是多此一舉,只是mysql并不能指定只解析一個表的日志。
加速方法
用備份恢復臨時實例之后,將這個臨時實例設置成線上備庫的從庫。在保存主從配置之前,先通過執行change replication filter replicate_do_table = (tbl_name)
命令,就可以讓臨時庫只同步誤操作的表。這樣做也可以用之前介紹的并行復制技術,來加速整個數據恢復過程。
日志遺失
如果在尋找日志恢復實例時,備庫上已經刪除了臨時實例需要的binlog的話,我們可以從binlog備份系統中找到需要的binlog,再放回備庫中。具體操作如下
- 先下載兩個遺失的日志,放到備庫的日志目錄下
- 打開日志目錄下的 master.index 文件,在文件開頭加入兩行,內容分別是 ./master.丟失001和 ./master.丟失002
- 重啟備庫,重新加載這兩個日志。這個時候建立主從關系就可以正常同步了。
必須要求備份系統定期備份全量日志,考慮磁盤硬件需求??梢赃m當的保存固定的天數
延遲復制備庫
這個方案是屬于一個日志延遲方案。比如在從庫寫入一個數據,這個數據不會立即同步到備庫上。然后采用延遲的手法同步到備庫。
比如我們延遲1個小時。主庫寫入數據之后,1個小時之后會同步到從庫。那么如果1個小時內發現了數據有誤,就可以使用stop slave 命令把這個寫入的數據停止。
可以通過 CHANGE MASTER TO MASTER_DELAY = N 命令,可以指定這個備庫持續保持跟主庫有 N 秒的延遲。
預防表/庫方法
賬號分離,不同的業務人員擁有不同的操作權限。避免寫錯命令。
制定操作規范。這樣做的目的,是避免寫錯要刪除的表名
rm 刪除數據
這個風險還是比較高的,一般出現這種情況,只能采用集群的方式恢復了,如果沒有集群的話只能嗝屁了。
如果只是刪除一個節點的話,HA系統就會開始工作,先選出一個新的主庫,然后就是在這個節點上把數據恢復然后接入整個集群。這樣就可以解決了。
為了保險起見,一般rm命令危害比較大,建議分機房,跨城市保存數據
總結
今天介紹了數據被刪后,除了跑路我們還可以有哪些處理方式以及數據被刪后的應對方案和應急方案。