1. 程式人生 > >mysql定時備份任務

mysql定時備份任務

# 簡介 在生產環境上,為了避免資料的丟失,通常情況下都會定時的對資料庫進行備份。而Linux的`crontab`指令則可以幫助我們實現對資料庫定時進行備份。首先我們來簡單瞭解`crontab`指令,如果你會了請跳到下一個內容**mysql備份**。 本文章的mysql資料庫是安裝在docker容器當中,以此為例進行講解。沒有安裝到docker容器當中也可以參照參照。 # contab定時任務 使用`crontab -e`來編寫我們的定時任務。 ``` 0 5 * * 1 [command] ``` 前面的5個數字分別代表**分、時、日、月、周**,後面的 `command`為你的執行命令。 假如你需要在每天晚上8點整執行定時任務,那麼可以這麼寫 ``` 0 8 * * * [command] ``` **擴充套件:** `crontab -l` 可以檢視自己的定時任務 `crontab -r` 刪除當前使用者的所有定時任務 # mysql備份 ## 快速上手 這裡我的mysql資料庫是docker容器。假如你需要在每天晚上8點整執行定時任務,那麼可以這麼寫。 首先執行命令`crontab -e`。 ``` 0 8 * * * docker exec mysql_container mysqldump -uroot -proot_password database_name > /var/backups/mysql/$(date +%Y%m%d_%H%M%S).sql ``` **mysql_container** 為你的資料庫容器名 **mysqldump** 是mysql資料庫匯出資料的指令 **-u** 填寫root賬號 **-p** 填寫root密碼 **database_name** 需要備份的資料庫名 **/var/backups/mysql/$(date +%Y%m%d_%H%M%S).sql** 備份檔案,後面是檔名的格式 如果你沒什麼要求,單純的只是想要備份,那麼上面那個命令就可以幫你進行定時備份。 **小坑:** mysql備份的時候我使用了`docker exec -it mysqldump ...` 這樣的命令去做`bash`指令碼,因為`-i`引數是有互動的意思,導致在`crontab`中執行定時任務的時候,沒有輸出資料到`sql`檔案當中。所以使用`crontab`定時的對docker容器進行備份命令的時候不要新增`-i`引數。 ## crontab優化 我不建議直接在`crontab -e`裡面寫要執行的命令,任務多了就把這個檔案寫的亂七八招了。 建議把資料庫備份的命令寫成一個`bash`指令碼。在`crontab`這裡呼叫就好了 如:建立一個`/var/backups/mysql/mysqldump.sh`檔案,內容如下 ```bash docker exec mysql_container mysqldump -uroot -pmypassword database_name > /var/backups/mysql/$(date +%Y%m%d_%H%M%S).sql ``` 然後把檔案改為當前使用者可執行的: ```bash chmod 711 /var/backups/mysql/mysqldump.sh ``` 執行`crontab -e `命令修改成如下: ```bash 0 20 * * * /var/backups/mysql/mysqldump.sh ``` 那麼這樣就比較規範了。 ## mysql備份優化 因為`sql`檔案比較大,所以一般情況下都會對`sql`檔案進行壓縮,不然的話磁碟佔用就太大了。 假設你做了上面這一步 **crontab優化**,我們可以把`mysqldump.sh`指令碼改成下面這樣: ``` export mysqldump_date=$(date +%Y%m%d_%H%M%S) && \ docker exec mysql_container mysqldump -uroot -pmypassword database_name> /var/backups/mysql/$mysqldump_date.sql && \ gzip /var/backups/mysql/$mysqldump_date.sql find /var/backups/mysql/ -name "*.sql" -mtime +15 -exec rm -f {} \; ``` `export` 在系統中自定義了個變數mysqldump_date,給備份和壓縮命令使用 `gzip` 為壓縮命令,預設壓縮了之後會把原始檔刪除,壓縮成`.gz`檔案 `find ...` 這行命令的意思為,查詢` /var/backups/mysql/`目錄下,建立時間15天之前(`-mtime +15`),檔名字尾為`.sql`的所有檔案 執行刪除命令`-exec rm -f {} \;`。總的意思就是:mysql的備份檔案只保留15天之內的。15天之前的都刪除掉。 # 資料恢復 若一不小心你執行`drop database`,穩住,淡定。我們首先要建立資料庫被刪除的資料庫。 ``` >mysql create database database_name; ``` 然後恢復最近備份的資料。恢復備份的命令: ```bash docker exec -i mysql_container mysql -uroot -proot_password database_name < /var/backups/mysql/20200619_120012.sql ``` 雖然恢復了備份檔案的資料,但是備份時間點之後的資料我們卻沒有恢復回來。 如:晚上8點進行定時備份,但是卻在晚上9點`drop database`,那麼晚上8點到晚上9點這一個小時之內的資料卻沒有備份到。這時候就要使用`binlog`日誌了。 # binlog日誌 binlog 是mysql的一個歸檔日誌,記錄的資料修改的邏輯,如:給 ID = 3 的這一行的 money 欄位 + 1。 首先登入mysql後查詢當前有多少個binlog檔案: ``` >
mysql show binary logs; +---------------+-----------+-----------+ | Log_name | File_size | Encrypted | +---------------+-----------+-----------+ | binlog.000001 | 729 | No | | binlog.000002 | 1749 | No | | binlog.000003 | 1087 | No | +---------------+-----------+-----------+ ``` 檢視當前正在寫入的binlog ``` mysql>
show master status\G; ``` 生成新的binlog檔案,mysql的後續操作都會寫入到新的binlog檔案當中,一般在恢復資料都時候都會先執行這個命令。 ``` mysql> flush logs ``` 檢視binlog日誌 ``` mysql> show binlog events in 'binlog.000003'; ``` 小知識點:初始化mysql容器時,新增引數`--binlog-rows-query-log-events=ON`。或者到容器當中修改`/etc/mysql/my.cnf`檔案,新增引數`binlog_rows_query_log_events=ON`,然後重啟mysql容器。這樣可以把原始的SQL新增到`binlog`檔案當中。 ## 恢復資料 拿回上面例子的這段話。 >
晚上8點進行定時備份,但是卻在晚上9點`drop database`,那麼晚上8點到晚上9點這一個小時之內的資料卻沒有備份到。。 首先進入到mysql容器後,切換到`/var/lib/mysql`目錄下,檢視binlog檔案的建立日期 ```bash cd /var/lib/mysql ls -l ... -rw-r----- 1 mysql mysql 729 Jun 19 15:54 binlog.000001 -rw-r----- 1 mysql mysql 1749 Jun 19 18:45 binlog.000002 -rw-r----- 1 mysql mysql 1087 Jun 19 20:58 binlog.000003 ... ``` 從檔案日期可以看出:當天時間為2020-06-21,`binlog.000002`檔案的最後更新時間是 18:45 分,那麼晚上8點的備份肯定包含了`binlog.000002`的資料; `binlog.000003`的最後更新日期為 20:58 分,那麼我們需要恢復的資料 = 晚上8點的全量備份 + `binlog.000003`的 20:00 - 執行`drop database`命令時間前的資料。 **恢復命令格式:** ```bash mysqlbinlog [options] file | mysql -uroot -proot_password database_name ``` mysqlbinlog常用引數: > --start-datetime 開始時間,格式 2020-06-19 18:00:00 > --stop-datetime 結束時間,格式同上 > --start-positon 開始位置,(需要檢視binlog檔案) > --stop-position 結束位置,同上 > ... 恢復備份資料和`binlog`資料前建議先登入mysql後執行`flush logs`生成新的`binlog`日誌,這樣可以專注需要恢復資料的`binlog`檔案。 首先我們需要檢視binlog日誌,在哪個位置進行了`drop database`操作: ``` mysql> show binlog events in 'binlog.000003'; +---------------+-----+----------------+-----------+-------------+---------------------------------------------------------------------------------------------------------------------------------------------+ | Log_name | Pos | Event_type | Server_id | End_log_pos | Info | +---------------+-----+----------------+-----------+-------------+---------------------------------------------------------------------------------------------------------------------------------------------+ | binlog.000003 | 4 | Format_desc | 1 | 125 | Server ver: 8.0.20, Binlog ver: 4 | | binlog.000003 | 125 | Previous_gtids | 1 | 156 | | | binlog.000003 | 156 | Anonymous_Gtid | 1 | 235 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS' | | binlog.000003 | 235 | Query | 1 | 318 | BEGIN | | binlog.000003 | 318 | Rows_query | 1 | 479 | # INSERT INTO `product_category` SET `name` = '床上用品' , `create_time` = 1592707634 , `update_time` = 1592707634 , `lock_version` = 0 | | binlog.000003 | 479 | Table_map | 1 | 559 | table_id: 139 (hotel_server.product_category) | | binlog.000003 | 559 | Write_rows | 1 | 629 | table_id: 139 flags: STMT_END_F | | binlog.000003 | 629 | Xid | 1 | 660 | COMMIT /* xid=2021 */ | | binlog.000004 | 660 | Anonymous_Gtid | 1 | 739 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS' | | binlog.000004 | 739 | Query | 1 | 822 | drop database hotel_server /* xid=26 */ | +---------------+-----+----------------+-----------+-------------+---------------------------------------------------------------------------------------------------------------------------------------------+ ``` 根據上面的日誌,我們可以看到,在`End_log_pos `= 822 的位置執行了`drop database`操作,那麼使用`binlog`恢復的範圍就在`2020-06-19 20:00:00` - 660 的位置。為什麼是660?因為`drop database`的上一個事務的提交是660的位置,命令如下: ``` mysqlbinlog --start-datetime=2020-06-19 20:00:00 --stop-position=660 /var/lib/mysql/binlog.000003 | mysql -uroot -proot_password datbase_name ``` 如果你的範圍包括了822的位置,那麼就會幫你執行`drop database`命令了。不信你試試? 執行完上面的命令,你的資料就會恢復到`drop database`前啦!開不開心,激不激動! # 總結 因為mysql定時備份是在生產環境上必須的任務。是很常用的。所以我就迫不及待的寫部落格。當然也很感謝我同事的幫助。這篇文章已經寫了三天了,因為我也是在不斷地試錯,不斷的更新文章。避免把錯誤的知識點寫出來。如果幫到你了,關注我一波唄!謝謝。 > 個人部落格網址: https://colablog.cn/ 如果我的文章幫助到您,可以關注我的微信公眾號,第一時間分享文章給您 ![微信公眾號](http://qiniuyun.colablog.cn/%E4%BA%8C%E7%BB%B4%E7%A0%