前面寫了篇 MySQL 複寫(熱備份),這廂就要來篇備份(冷備份)。
MySQL 備份的方法很多,有專門的備份服務,例如 SqlBak、Backup Ninja,也有一些外部或內建的備份工具如下:
- mysqldump
- mysqlpump
- XtraBackup
- MyDumper
這些工具都各有支持者,而本篇採用的是本家的 mysqlpump,就本人目前的備份需求來說,足矣。
mysqlpump
它是個隨附於 MySQL 的命令列工具,裝完 MySQL 應該就有了。
只要對 MySQL 有基本的認識,使用 mysqldump 應該沒什麼障礙,下面是我的基本使用參數:
$ /usr/bin/mysqlpump \
--user=root \
--password=myrootpassword \
--compress \
--add-drop-database \
--add-drop-table \
--single-transaction \
--watch-progress \
--exclude-databases=mysql \
--result-file=/data/backups/mysql_2022-10-13.sql \
大部分的參數應該都可以望文生義,就不多解釋。
以日期命名備份檔
上面這個命令的問題是,它的備份檔日期是死的,想要用當天日期命名的話可以改成這樣:
$ /usr/bin/mysqlpump \
--user=root \
--password=myrootpassword \
--compress \
--add-drop-database \
--add-drop-table \
--single-transaction \
--watch-progress \
--exclude-databases=mysql \
--result-file=/data/backups/mysql_"$(date --iso-8601='date')".sql \
這裡用到 shell 腳本的變數($
)以及 date
來組合出當天的日期當作備份檔名。
隱藏密碼
還有另外一個問題是,密碼是明碼,把這些寫成腳本令人感到不放心。
這個問題 MySQL 也有應對方案,它自帶一組密碼加密工具。
在開始前,先到 MySQL 建立一組專門的備份帳號,就叫它 bkpuser 吧!
用 MySQL 附的密碼加密工具生成加密的帳密檔:
$ mysql_config_editor set --login-path=backup --user=bkpuser --password
其中參數 login-path
只是該組帳密對的識別名稱而已,沒有功能上的意義。
執行之後,需要輸入 bkpuser 的密碼。
再確認一下:
$ mysql_config_editor print --all
應該會輸出以下結果:
[backup]
user = "bkpuser"
password = *****
其中的區塊名 backup
來自前面執行時的 login-path
參數值。
mysql_config_editor
這支程式會生成一個加密過的帳密檔案 ~/.mylogin.cnf,看一下真的是亂碼:
$ cat ~/.myloing.cnf
因為帳密對有識別名稱,所以可以視需要添加其它帳密對,MySQL 的命令列工具幾乎都支援以 login-path
的方式做身份認證。
最後回到備份話題,設好之後就可以用 login-path
替代明碼的密碼啦:
$ /usr/bin/mysqlpump \
--login-path=backup \
--compress \
--add-drop-database \
--add-drop-table \
--single-transaction \
--watch-progress \
--exclude-databases=mysql \
--result-file=/data/backups/mysql_"$(date --iso-8601='date')".sql \
日期也自動產生了,密碼也隱藏了,接著就是讓它每天自動跑啦!
定期備份
把上面的命令變成腳本:
#!/usr/bin/bash
/usr/bin/mysqlpump \
--login-path=backup \
--compress \
--add-drop-database \
--add-drop-table \
--single-transaction \
--watch-progress \
--exclude-databases=mysql \
--result-file=/data/backups/mysql_"$(date --iso-8601='date')".sql \
把腳本文存為 /usr/local/bin/backup-mysql.sh,記得加上可執行權限。
另外那放備份檔的 /data/backups/ 的寫入權限也要先開好。
設定 cron 任務:
$ crontab -e
此處我們用特定帳號的 cron,沒有為什麼。
添加 crontab 如下:
0 1 * * * /usr/local/bin/backup-mysql.sh
10 1 * * * find /data/backup/ -mtime +30 -name 'mysql_*.sql' -delete;
第一行表示每日凌晨一點跑備份腳本。
第二行是每日凌晨 1:10 刪除三十天以上的舊備份,主要是用 find 指令的比對和刪除功能。簡單搞定,沒有用到什麼複雜的 retention / rotation 工具。
還原
很多人做到備份就停了,但建議還是實際演練一下還原作業,真的碰到時比較不會手忙腳亂。
還原當下典型的情境應該是一台空的 MySQL,回頭看我們的還原腳本有這幾個參數:
--add-drop-database
--add-drop-table
意思是備份檔的 SQL 內有加入丟掉資料庫、丟掉資料表等指令,所以空的 MySQL 也好,已經有東西的 MySQL 也好,只要有與備份檔同名的資料庫都會被先被拋棄再重建。
還原的指令相當簡單,在 shell 環境執行:
$ mysql -uroot -p < mysql_2022-10-31.sql
如此即可還原。