模擬數據恢復的案例
有些時候腦瓜就會短路,難免會出錯
場景:在生產環境中,我們搭建了mysql主從,備份操作都是在從備份數據庫上
前提:有最近一天或者最近的全備
或者最近一天相關數據庫的備份
最重要的是,二進制日志必須完整
服務器信息 | 角色 | 端口 |
192.168.1.21 | mysql主 | 30136 |
192.168.1.21 | mysql從 | 30236 |
接下來,我們模擬下
案例一、update未加where條件,誤操作修改數據
全備命令: mysqldump -uroot -p123456 --single-transaction --set-gtid-purged=OFF --master-data=2 -A > all_database.sql
mysqldump -uroot -p123456 --single-transaction --set-gtid-purged=OFF --master-data=2 xcrm > xcrm.sql
模擬災難現場
我這個是在k8s里面搭建了一個主從
kubectl get all -o wide
kubectl exec -it mysql-master-659958ff4f-l4sgt bash #mysql主
mysql -uroot -p123456
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
| xcrm |
+--------------------+
5 rows in set (0.00 sec)
mysql> use xcrm
mysql> create table edai_test like ding_cun;
mysql> insert into edai_test select * from ding_cun;
比如凌晨全備是做到這里的
命令:mysqldump -uroot -p123456 --single-transaction --set-gtid-purged=OFF --master-data=2 -A > all_database.sql
早上九點的時候,又有新的數據進來
mysql> insert into edai_test(nper,money) select nper,money from ding_cun;
110 rows in set (0.00 sec)
悲劇來了,上線中的sql,沒有檢查,where條件沒加,直接執行
mysql> update edai_test set money=0;
Query OK, 110 rows affected (0.07 sec)
Rows matched: 110 Changed: 110 Warnings: 0
糟糕,一不小心金額被我修改為0了,偶my嘎,
趕緊恢復,找出binlog點,根據之前的全備+binlog恢復
恢復步驟:
1.找出時間段
root@mysql-master-659958ff4f-l4sgt:~/backu1.p# cat all_database.sql |grep -i 'CHANGE MASTER TO MASTER_LOG_FILE'|head -n1
-- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000001', MASTER_LOG_POS=154;
mysql -uroot -p123456 -e "show binlog events in 'mysql-bin.000001'"|tail -n1000
找到了對應pos點:4326
2.mysql導入昨天晚上的備份數據,並且查看pos節點
mysql -uroot -p123456 < all_databases.sql
3.拷貝二進制日志文件到其他地方和二進制恢復
cp /var/lib/mysql/mysql-bin.000001 .
root@mysql-master-659958ff4f-l4sgt:~/backup# mysqlbinlog --start-position=154 --stop-position=4326 -d xcrm mysql-bin.000001|mysql -uroot -p123456 xcrm
好了,數據恢復
二、刪庫
其實刪除數據庫都是一樣的道理
比如我們的備份是還是昨天晚上的,但是今天下午清理數據,刪除無效的數據庫,誤刪了
恢復步驟和原理都是差不多的,我就不演示了,簡單講解下
比如下午有新加了一些數據:
mysql> create table customers( id int not null auto_increment, name char(20) not null, age int not null, primary key(id)
)engine=InnoDB; Query OK, 0 rows affected (0.35 sec) mysql> insert into customers values(1,"wangbo","24"); Query OK, 1 row affected (0.07 sec) mysql> insert into customers values(2,"guohui","22"); Query OK, 1 row affected (0.12 sec) mysql> insert into customers values(3,"zhangheng","27"); Query OK, 1 row affected (0.06 sec) mysql> select * from customers; +----+-----------+-----+ | id | name | age | +----+-----------+-----+ | 1 | wangbo | 24 | | 2 | guohui | 22 | | 3 | zhangheng | 27 | +----+-----------+-----+ 3 rows in set (0.00 sec)
然后我一不小心把數據庫刪除了
mysql> drop database xcrm; Query OK, 5 rows affected (0.40 sec)
刪庫恢復步驟
到這里,如果是在生產環境,必須立刻做處理
1.立刻設置全局只讀
進入數據庫:set global read_only=1; #普通權限的用戶只讀,不能寫數據
mysql> show variables like '%read_only%';
此時普通用戶不能進行寫操作啦,比如下面
mysql -udemo -pdemo -P30136 -h192.168.1.21 xcrm mysql> select * from customers ; +----+-----------+-----+ | id | name | age | +----+-----------+-----+ | 1 | wangbo | 24 | | 2 | guohui | 22 | | 3 | zhangheng | 27 | +----+-----------+-----+ 3 rows in set (0.00 sec) mysql> delete from customers where id=3; ERROR 1290 (HY000): The MySQL server is running with the --read-only option so it cannot execute this statement
2.找到最近備份文件和二進制日志點
root@mysql-master-659958ff4f-l4sgt:~/backup# mysql -uroot -p123456 -e "show binlog events in 'mysql-bin.000001'"|grep -i 'DROP DATABASE'
mysql: [Warning] Using a password on the command line interface can be insecure.
mysql-bin.000001 15035 Query 22 15127 drop database xcrm
找到最近備份文件的最后pos位置
root@mysql-master-659958ff4f-l4sgt:~/backup# cat all_database.sql |grep -i 'CHANGE MASTER TO MASTER_LOG_FILE'|head -n1
-- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000001', MASTER_LOG_POS=13871;
3.進行恢復
先將今天凌晨備份的導進去
mysql -uroot -p123456 < all_database.sql
13871 15035
查看數據中間還相差很多數據,沒關系,再根據pos期間來恢復
mysqlbinlog --start-position=13871 --stop-position=15035 -d xcrm mysql-bin.000001|mysql -uroot -p123456 xcrm
進入數據庫看看,數據是否正常
mysql -uroot -p123456 mysql> use xcrm Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed mysql> show tables; +------------------+ | Tables_in_xcrm | +------------------+ | customers | | ding_cun | | edai_app_version | | edai_test | +------------------+ 4 rows in set (0.00 sec) mysql> select * from customers; +----+-----------+-----+ | id | name | age | +----+-----------+-----+ | 1 | wangbo | 24 | | 2 | guohui | 22 | | 3 | zhangheng | 27 | +----+-----------+-----+ 3 rows in set (0.00 sec)
好了,沒問題,drop數據庫也可以恢復啦
現在把全局鎖解開:
mysql> set global read_only=0; Query OK, 0 rows affected (0.00 sec) mysql> show variables like '%read_only%'; +------------------+-------+ | Variable_name | Value | +------------------+-------+ | innodb_read_only | OFF | | read_only | OFF | | super_read_only | OFF | | tx_read_only | OFF | +------------------+-------+ 4 rows in set (0.00 sec) 大家有沒有什么疑問?
再三強調:
在生產環境誤操作之后,應該立刻判斷這個表或者庫的重要性
1.如果是不常用的數據庫或者表,幾乎沒有數據更新,可以不用鎖庫,只讀
2.如果是很常用的數據庫或者表,必須處理,設置為只讀,如果更為嚴重,需要停止mysql服務器。目的就是防止有新的數據寫進來,數據混亂
另外呢,假如在生產環境誤操作了,比如,insert,delete,update等表的操作,利用mysql全備+binlog來恢復,時間成本很大,這種方式不是很好。
我們可以用python開發的一個工具:binlog2sql (mysql閃回工具)
Mysql閃回工具之binlog2sql的原理及其使用