日B视频 亚洲,啪啪啪网站一区二区,91色情精品久久,日日噜狠狠色综合久,超碰人妻少妇97在线,999青青视频,亚洲一区二卡,让本一区二区视频,日韩网站推荐

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

MySQL自動備份配置與恢復演練實戰(zhàn)

馬哥Linux運維 ? 來源:馬哥Linux運維 ? 2026-05-12 09:46 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

背景與適用場景

數(shù)據(jù)庫是幾乎所有業(yè)務(wù)系統(tǒng)的核心,MySQL 作為最流行的開源關(guān)系型數(shù)據(jù)庫之一,在生產(chǎn)環(huán)境中承擔著海量業(yè)務(wù)數(shù)據(jù)的存儲任務(wù)。一次誤操作、一個升級事故、一次硬件故障,甚至一個凌晨的勒索病毒,都可能導致數(shù)據(jù)丟失或損壞。沒有可用備份的數(shù)據(jù)庫,在發(fā)生故障時幾乎等于從零重建——這對于業(yè)務(wù)連續(xù)性來說是不可接受的風險。

本文面向 Linux 運維工程師、DevOps 工程師和初中級 DBA,目標是讓你掌握一套完整的 MySQL 自動備份與恢復體系。具體包括:

全量備份、增量備份的原理與實戰(zhàn)

mysqldump 和 MySQL XtraBackup 兩種主流備份工具的使用方法

基于 binlog 的時間點恢復(Point-in-Time Recovery)操作步驟

備份策略的自動化配置與監(jiān)控

真實故障場景下的恢復演練流程

備份恢復過程中的常見坑點與風險規(guī)避

整個內(nèi)容設(shè)計為可直接在測試環(huán)境復現(xiàn)的操作手冊,建議先在非生產(chǎn)環(huán)境走通全部流程,再將驗證過的方案部署到生產(chǎn)環(huán)境。

備份類型與核心概念

在動手之前,先梳理清楚備份領(lǐng)域的幾個核心概念,這些概念貫穿整個備份體系,理解它們是正確設(shè)計備份策略的前提。

邏輯備份與物理備份

邏輯備份(Logical Backup)是通過 SQL 語句導出數(shù)據(jù),備份內(nèi)容是 INSERT 語句或 CSV 數(shù)據(jù),代表工具是 mysqldump 和 mydumper。邏輯備份的優(yōu)勢在于跨版本兼容性好、恢復靈活(可以單獨恢復某張表)、導出文件人類可讀。缺點是備份和恢復速度慢,占用空間相對較大,且備份過程中需要鎖定某些對象(取決于存儲引擎和隔離級別)。

物理備份(Physical Backup)直接拷貝 MySQL 數(shù)據(jù)文件(frm、ibd、ibdata、redo log 等),代表工具是 MySQL XtraBackup 和 mysqlbackup。物理備份的優(yōu)勢是備份恢復速度快、完整保留數(shù)據(jù)頁、對于大數(shù)據(jù)庫效率更高。缺點是跨平臺兼容性差(不同 OS、不同 MySQL 版本之間可能不兼容)、恢復粒度是整個實例或單庫,不易做單表恢復。

對于數(shù)據(jù)量在幾百 GB 以內(nèi)的中小型業(yè)務(wù),mysqldump 配合定時任務(wù)已經(jīng)足夠。對于數(shù)據(jù)量在 TB 級別的業(yè)務(wù),XtraBackup 是更合理的選擇。

全量備份與增量備份

全量備份(Full Backup)每次備份數(shù)據(jù)庫的全部數(shù)據(jù)。無論數(shù)據(jù)變化多少,備份內(nèi)容都是完整的一份。全量備份的缺點是占用空間大、備份時間長,優(yōu)點是恢復簡單——拿一份備份直接恢復即可。

增量備份(Incremental Backup)只備份自上一次備份(可以是全量或增量)以來發(fā)生變化的數(shù)據(jù)。MySQL 中實現(xiàn)增量備份的核心機制是基于 binlog(Binary Log)和 XtraBackup 的增量能力。增量備份的優(yōu)勢是備份速度快、占用空間小,缺點是恢復流程復雜——需要先恢復全量備份,再順序重放所有增量備份。

常見的組合策略是"全量 + binlog":每天做一次全量備份,每 15~30 分鐘備份一次 binlog。這樣在發(fā)生故障時,可以恢復到任意時間點。

備份頻率與保留策略

備份頻率取決于兩個因素:業(yè)務(wù)對數(shù)據(jù)丟失的容忍度(RPO,Recovery Point Objective)和運維團隊對恢復流程的熟練程度。

如果業(yè)務(wù)要求最多丟失 15 分鐘的數(shù)據(jù),那么需要每 15 分鐘備份一次 binlog,或者每 15 分鐘做一次增量備份。如果業(yè)務(wù)可以容忍丟失一天的數(shù)據(jù),那么每天一次全量備份即可。

保留策略決定了備份集的保存時間。建議保留至少 7 天的備份,對于核心業(yè)務(wù)系統(tǒng),建議保留 30 天甚至更久。更長的保留周期意味著更高的存儲成本,但也能覆蓋更長時間的邏輯誤刪場景(比如三天前誤刪了一張表,現(xiàn)在才發(fā)現(xiàn))。

mysqldump 實戰(zhàn):從基礎(chǔ)到進階

mysqldump 是 MySQL 自帶的邏輯備份工具,幾乎所有 MySQL 發(fā)行版都自帶這個工具,無需額外安裝。它的使用場景覆蓋了絕大多數(shù)中小型業(yè)務(wù)的備份需求。

基礎(chǔ)用法

最基礎(chǔ)的備份命令如下,備份整個數(shù)據(jù)庫的所有表:

mysqldump -u root -p --single-transaction --routines --triggers --events 
 --master-data=2 --flush-logs dbname > /backup/dbname_$(date +%Y%m%d).sql

解釋一下各個參數(shù)的含義:

--single-transaction在備份開始時開啟一個事務(wù)(前提是表引擎為 InnoDB),在整個備份過程中保持事務(wù)一致性,備份期間業(yè)務(wù)讀寫不受影響。這個參數(shù)對于生產(chǎn)環(huán)境至關(guān)重要,沒有它,備份期間會對所有表加讀鎖,導致業(yè)務(wù)長時間阻塞。

--routines同時導出存儲過程和函數(shù)。--triggers導出觸發(fā)器,--events導出事件調(diào)度器。如果業(yè)務(wù)中使用了這些對象,務(wù)必帶上這兩個參數(shù)。

--master-data=2在備份文件中記錄備份時刻的 binlog 文件名和位置(以注釋形式),這個信息在配置主從復制或做時間點恢復時必不可少。值為 2 表示以注釋形式記錄,值為 1 表示以 CHANGE MASTER TO 命令形式記錄(可直接執(zhí)行,但會暴露敏感信息)。

--flush-logs在備份開始前刷新日志,關(guān)閉并重新打開 binlog 文件,這有助于確定備份對應(yīng)的 binlog 起始位置。

備份文件是壓縮存放還是直接存儲,取決于數(shù)據(jù)量大小和磁盤空間。對于中等大小的數(shù)據(jù)庫(幾十 GB 以內(nèi)),壓縮率通常在 3~5 倍,壓縮后存儲可以節(jié)省大量磁盤空間:

mysqldump -u root -p --single-transaction --routines --triggers --events 
 --master-data=2 --flush-logs dbname | gzip > /backup/dbname_$(date +%Y%m%d).sql.gz

備份單個數(shù)據(jù)庫的所有表

mysqldump -u root -p 
 --single-transaction 
 --routines 
 --triggers 
 --events 
 --master-data=2 
 --flush-logs 
 --databases app_db 
 | gzip > /backup/app_db_$(date +%Y%m%d).sql.gz

--databases參數(shù)告訴 mysqldump 接下來的是數(shù)據(jù)庫名列表,會為每個數(shù)據(jù)庫生成 CREATE DATABASE 和 USE 語句,恢復時可以直接作為 SQL 文件執(zhí)行,不需要手動創(chuàng)建數(shù)據(jù)庫。

備份所有數(shù)據(jù)庫

mysqldump -u root -p 
 --single-transaction 
 --routines 
 --triggers 
 --events 
 --master-data=2 
 --flush-logs 
 --all-databases 
 | gzip > /backup/all_db_$(date +%Y%m%d).sql.gz

--all-databases會備份所有數(shù)據(jù)庫,包括 mysql 系統(tǒng)庫。注意系統(tǒng)庫中包含了用戶權(quán)限信息、復制配置等關(guān)鍵元數(shù)據(jù),在恢復時不要輕易覆蓋這些內(nèi)容,除非你有明確的恢復目的。

備份指定表

有時候只需要備份某幾張表,而不是整個數(shù)據(jù)庫:

mysqldump -u root -p --single-transaction dbname orders users products 
 > /backup/dbname_tables_$(date +%Y%m%d).sql

這種場景常用于:某張表被誤刪,需要單獨恢復;或者大表中部分分區(qū)需要特殊處理。

只備份表結(jié)構(gòu),不備份數(shù)據(jù)

在某些場景下只需要表結(jié)構(gòu),比如做數(shù)據(jù)遷移前的環(huán)境準備:

mysqldump -u root -p --single-transaction --no-data dbname > /backup/dbname_structure_$(date +%Y%m%d).sql

反之,如果只需要數(shù)據(jù)而不需要表結(jié)構(gòu)(用于數(shù)據(jù)初始化或?qū)Ρ龋?,可以?-no-create-info參數(shù)。

備份大數(shù)據(jù)庫時的分表并行導出

mysqldump 默認是單線程,對于幾百 GB 的大數(shù)據(jù)庫,全量導出可能需要數(shù)小時。mydumper 是 mysqldump 的多線程替代方案,可以顯著加快大數(shù)據(jù)庫的備份速度:

# 安裝 mydumper(CentOS/RHEL 系列)
yum install -y mydumper

# 安裝 mydumper(Debian/Ubuntu 系列)
apt-get install -y mydumper

# 使用 mydumper 并行導出,4 個線程,導出的文件放在 /backup/export 目錄
mydumper 
 --host=127.0.0.1 
 --port=3306 
 --user=root 
 --password='your_password'
 --threads=4 
 --outputdir=/backup/mydumper_export 
 --database=app_db 
 --compress 
 --verbose=3

mydumper 的輸出是多個 chunk 文件(按表和數(shù)據(jù)范圍分片),恢復時使用 myloader 工具并行導入,速度遠快于單線程的 mysqldump + source 組合。

mydumper 備份產(chǎn)生的文件結(jié)構(gòu):

/backup/mydumper_export/
 app_db.orders-schema.sql.gz   # 建表語句
 app_db.orders.00000.sql.gz   # 數(shù)據(jù)文件(可能分多個文件)
 app_db.users-schema.sql.gz
 app_db.users.00000.sql.gz
 metadata             # 備份元數(shù)據(jù)(包含 binlog 位置)

mysqldump 的限制與注意事項

mysqldump 雖然方便,但有幾個重要限制必須清楚:

第一,--single-transaction只對 InnoDB 引擎有效。對于 MyISAM 表,備份期間仍然會加讀鎖。如果數(shù)據(jù)庫中混合使用了 MyISAM 和 InnoDB,需要評估一致性影響,或者將 MyISAM 表單獨處理。

第二,備份超大型數(shù)據(jù)庫(數(shù)百 GB 以上)時,mysqldump 的邏輯備份速度非常慢,且 SQL 文件本身可能達到數(shù)十 GB,存儲和恢復成本都很高。這種場景建議使用 XtraBackup 物理備份。

第三,備份文件本身沒有加密,所有數(shù)據(jù)以明文 SQL 形式存儲。如果數(shù)據(jù)庫包含敏感信息(身份證號、密碼明文等),需要在備份傳輸和存儲環(huán)節(jié)額外考慮加密,比如使用 LUKS 加密備份盤,或在備份后使用 gpg 加密文件。

第四,密碼不建議直接在命令行中以-ppassword形式傳入,這樣密碼會以明文形式出現(xiàn)在進程列表中,可能被其他用戶通過ps aux看到。推薦的做法是在/root/.my.cnf中配置客戶端默認賬號密碼:

[client]
user=root
password='your_password'
host=127.0.0.1
port=3306

給配置文件設(shè)置正確的權(quán)限,防止其他用戶讀?。?/p>

chmod 600 /root/.my.cnf

之后執(zhí)行 mysqldump 時不需要傳入-u和-p參數(shù),工具會自動讀取配置文件中的認證信息。

MySQL XtraBackup 實戰(zhàn):熱備份利器

XtraBackup 是 Percona 公司開發(fā)的一款開源物理備份工具,專為 MySQL 設(shè)計。它的核心優(yōu)勢在于:備份過程不需要鎖定數(shù)據(jù)庫(對于 InnoDB 來說),可以在業(yè)務(wù)正常運行的情況下完成備份。這對于 7x24 運行的業(yè)務(wù)系統(tǒng)來說是必備能力。

安裝 XtraBackup

# CentOS/RHEL 7 及以下
yum install -y https://repo.percona.com/yum/percona-release-latest.noarch.rpm
yum install -y percona-xtrabackup-24

# CentOS/RHEL 8 / AlmaLinux 8 / Rocky Linux 8
dnf install -y https://repo.percona.com/yum/percona-release-latest.noarch.rpm
dnf install -y percona-xtrabackup

# Debian/Ubuntu
wget https://repo.percona.com/apt/pool/main/p/percona-release/percona-release_latest.generic_all.deb
dpkg -i percona-release_latest.generic_all.deb
apt-get update
apt-get install -y percona-xtrabackup

安裝完成后,驗證安裝:

xtrabackup --version

本文以 XtraBackup 2.4 版本為例進行演示,它是目前生產(chǎn)環(huán)境中最常用的穩(wěn)定版本,支持 MySQL 5.6、5.7、8.0(8.0 部分功能需要 XtraBackup 8.0)。

全量熱備份

XtraBackup 的全量備份流程分為兩步:第一步是xtrabackup --backup,將數(shù)據(jù)文件拷貝到備份目錄;第二步是xtrabackup --prepare,對備份集進行一致性處理,使數(shù)據(jù)文件處于一致狀態(tài)。

創(chuàng)建備份用戶(最小權(quán)限原則):

CREATEUSER'backup'@'localhost'IDENTIFIEDBY'Str0ngP@ssword';
GRANTPROCESS, RELOAD,LOCKTABLES,REPLICATIONCLIENTON*.*TO'backup'@'localhost';
FLUSHPRIVILEGES;

執(zhí)行全量備份:

# 創(chuàng)建備份存放目錄
mkdir -p /backup/xtrabackup/full

# 執(zhí)行備份,備份目標目錄
xtrabackup 
 --backup 
 --user=backup 
 --password='Str0ngP@ssword'
 --target-dir=/backup/xtrabackup/full/$(date +%Y%m%d) 
 --parallel=4 
 --compress 
 --compress-threads=4

# 查看備份結(jié)果
ls -lh /backup/xtrabackup/full/$(date +%Y%m%d)/

--parallel=4指定使用 4 個并發(fā)線程拷貝數(shù)據(jù)文件,數(shù)據(jù)量大時增加這個值可以顯著加快備份速度。--compress開啟壓縮,XtraBackup 會使用 qpress 算法壓縮數(shù)據(jù)文件,壓縮率通常在 2~3 倍。

備份完成后,目錄中包含以下關(guān)鍵文件:

backup-my.cnf:備份時的配置信息(包含 datadir、innodb 數(shù)據(jù)文件路徑等)

xtrabackup_checkpoints:記錄備份類型(full-backuped)、開始和結(jié)束的 LSN(Log Sequence Number)

xtrabackup_info:詳細的備份元信息

*.qp:壓縮后的數(shù)據(jù)文件

ibdata1:系統(tǒng)表空間文件

對備份集進行 prepare(一致性處理):

xtrabackup 
 --prepare 
 --target-dir=/backup/xtrabackup/full/$(date +%Y%m%d)

prepare 過程相當于在備份數(shù)據(jù)上重放事務(wù)日志,使所有數(shù)據(jù)文件處于一致狀態(tài)。完成 prepare 的備份集才能用于恢復。

增量備份

XtraBackup 的增量備份基于 LSN(Log Sequence Number)機制。每次全量或增量備份都會記錄當前數(shù)據(jù)庫的 LSN,增量備份只拷貝 LSN 大于上一次備份 LSN 的數(shù)據(jù)頁。

先執(zhí)行一次全量備份作為基準:

# 第一次全量備份
FULL_DATE=$(date +%Y%m%d)
xtrabackup 
 --backup 
 --user=backup 
 --password='Str0ngP@ssword'
 --target-dir=/backup/xtrabackup/full/${FULL_DATE}
 --parallel=4

# 記住備份的 LSN,用于后續(xù)增量備份
cat /backup/xtrabackup/full/${FULL_DATE}/xtrabackup_checkpoints

輸出示例:

backup_type = full-backuped
from_lsn = 0
to_lsn = 12345678

一天后做增量備份:

INC_DATE=$(date +%Y%m%d)
xtrabackup 
 --backup 
 --user=backup 
 --password='Str0ngP@ssword'
 --target-dir=/backup/xtrabackup/incremental/${INC_DATE}
 --incremental-basedir=/backup/xtrabackup/full/${FULL_DATE}
 --parallel=4

--incremental-basedir指定了參考的全量備份目錄,XtraBackup 會自動讀取其中的 checkpoints 文件獲取 LSN 信息。

增量備份完成后再做第二次增量:

INC_DATE2=$(date +%Y%m%d --date='+1 day')
xtrabackup 
 --backup 
 --user=backup 
 --password='Str0ngP@ssword'
 --target-dir=/backup/xtrabackup/incremental/${INC_DATE2}
 --incremental-basedir=/backup/xtrabackup/incremental/${INC_DATE}
 --parallel=4

增量備份的目錄體積遠小于全量備份,因為只保存了變化的數(shù)據(jù)頁。

增量備份的 prepare

恢復增量備份時,需要對每個備份集按順序執(zhí)行 prepare:

# 第一步:對全量備份執(zhí)行 prepare,但使用 --apply-log-only 阻止回滾未提交事務(wù)
xtrabackup 
 --prepare 
 --apply-log-only 
 --target-dir=/backup/xtrabackup/full/${FULL_DATE}

# 第二步:依次將每個增量備份合并到全量備份
xtrabackup 
 --prepare 
 --apply-log-only 
 --target-dir=/backup/xtrabackup/full/${FULL_DATE}
 --incremental-dir=/backup/xtrabackup/incremental/${INC_DATE}

xtrabackup 
 --prepare 
 --apply-log-only 
 --target-dir=/backup/xtrabackup/full/${FULL_DATE}
 --incremental-dir=/backup/xtrabackup/incremental/${INC_DATE2}

# 最后一步:對合并后的全量備份做完整的 prepare(不帶 --apply-log-only)
xtrabackup 
 --prepare 
 --target-dir=/backup/xtrabackup/full/${FULL_DATE}

最后一個 prepare 不加--apply-log-only,因為需要回滾未提交的事務(wù),使數(shù)據(jù)處于一致狀態(tài)。

流式備份與遠程備份

XtraBackup 支持將備份數(shù)據(jù)通過流式傳輸?shù)竭h程服務(wù)器,避免在本地堆積大量備份文件:

# 通過 ssh 加密傳輸?shù)竭h程服務(wù)器
xtrabackup 
 --backup 
 --user=backup 
 --password='Str0ngP@ssword'
 --target-dir=/backup/xtrabackup/full/$(date +%Y%m%d) 
 --stream=xbstream 
 --compress 
 | ssh backup@remote-server"cat > /remote/backup/$(date +%Y%m%d).xbstream"

在遠程服務(wù)器上接收并解壓:

# 在遠程服務(wù)器上執(zhí)行
cat /remote/backup/20240101.xbstream | xbstream -x -C /remote/backup/restore
xtrabackup --decompress --target-dir=/remote/backup/restore
xtrabackup --prepare --target-dir=/remote/backup/restore

XtraBackup 的適用場景

XtraBackup 適合以下場景:

數(shù)據(jù)量超過 100 GB,mysqldump 備份時間過長

需要在備份期間不鎖表,業(yè)務(wù)需要持續(xù)可用

需要增量備份能力,節(jié)省備份存儲空間

需要做主從復制的快速初始化(備份 + 恢復到從庫)

不適合使用 XtraBackup 的場景:

數(shù)據(jù)量很小(幾十 GB 以內(nèi)),mysqldump 足夠用

只需要備份單張表(邏輯備份更靈活)

跨 MySQL 版本恢復(物理備份不建議跨版本使用)

binlog 備份:時間點恢復的關(guān)鍵

binlog(Binary Log)是 MySQL 的變更日志,記錄了所有對數(shù)據(jù)庫的修改操作(INSERT、UPDATE、DELETE、DDL 等)。binlog 是實現(xiàn) MySQL 主從復制的基礎(chǔ),也是做時間點恢復(Point-in-Time Recovery)的核心數(shù)據(jù)源。

binlog 基礎(chǔ)配置

在 MySQL 配置文件中開啟 binlog:

[mysqld]
server-id = 1
log_bin = /var/lib/mysql/mysql-bin
binlog_format = ROW
expire_logs_days = 7
max_binlog_size = 1G
sync_binlog = 1

解釋關(guān)鍵參數(shù):

log_bin開啟 binlog 并指定文件名前綴。MySQL 實際會創(chuàng)建 mysql-bin.000001、mysql-bin.000002 等文件。

binlog_format = ROW設(shè)置 binlog 格式為 ROW 模式。ROW 模式記錄每行數(shù)據(jù)的變更,優(yōu)點是數(shù)據(jù)一致性最高,缺點是日志量可能較大。對于 MySQL 8.0,默認為 ROW。

expire_logs_days = 7設(shè)置 binlog 文件保留 7 天。這個值應(yīng)該大于等于備份頻率,比如每天全量備份,就應(yīng)該至少保留 7 天,確保每天的備份都能找到對應(yīng)的 binlog起點。

max_binlog_size = 1G每個 binlog 文件最大 1GB,達到上限后自動切換到新文件。

sync_binlog = 1每執(zhí)行一次事務(wù)就同步 binlog 到磁盤,防止服務(wù)器崩潰時丟失事務(wù)。這是數(shù)據(jù)安全性最高的設(shè)置,但會帶來一定的性能開銷。如果對性能要求極高,可以設(shè)為 100~1000(即每 100~1000 次事務(wù)同步一次),但存在丟失最近一批事務(wù)的風險。

手動備份 binlog

備份 binlog 文件非常簡單,只需要將 binlog 目錄中的已完成文件拷貝到備份位置。注意不要拷貝正在寫入的當前 binlog 文件,否則可能導致備份不完整:

# 創(chuàng)建備份目錄
mkdir -p /backup/binlog

# 刷新日志,產(chǎn)生一個新的 binlog 文件(這樣上一個文件就成為已完成的文件)
mysql -u root -p -e"FLUSH BINARY LOGS;"

# 獲取當前正在寫入的 binlog 文件名
CURRENT_BINLOG=$(mysql -u root -p -N -e"SHOW BINARY LOGS;"| tail -n 1 | awk'{print $1}')
echo"當前活躍 binlog:${CURRENT_BINLOG}"

# 拷貝所有已完成的 binlog 文件(排除正在寫入的當前文件)
forfilein/var/lib/mysql/mysql-bin.*;do
  filename=$(basename"$file")
 if[["$filename"!="$CURRENT_BINLOG"]];then
    cp"$file"/backup/binlog/
   echo"已備份:$filename"
 fi
done

注意:上述操作只是拷貝文件,沒有考慮正在寫入的當前 binlog。更穩(wěn)妥的做法是使用SHOW BINARY LOGS獲取文件列表,并使用PURGE BINARY LOGS清理已備份的舊文件(但清理前必須確認從庫已經(jīng)拉取完畢)。

自動備份 binlog 的腳本

生產(chǎn)環(huán)境通常使用腳本來自動備份 binlog,并結(jié)合定時任務(wù)定期執(zhí)行:

#!/bin/bash
# /opt/scripts/backup_binlog.sh

BACKUP_DIR="/backup/binlog"
MYSQL_HOST="127.0.0.1"
MYSQL_PORT="3306"
MYSQL_USER="backup"
MYSQL_PASSWORD='Str0ngP@ssword'

# 創(chuàng)建當天的備份目錄
TODAY=$(date +%Y%m%d)
mkdir -p${BACKUP_DIR}/${TODAY}

# 獲取當前 binlog 文件名
CURRENT_BINLOG=$(mysql -h${MYSQL_HOST}-P${MYSQL_PORT}-u${MYSQL_USER}-p${MYSQL_PASSWORD}
 -N -e"SHOW BINARY LOGS;"| tail -n 1 | awk'{print $1}')

# 刷新并鎖定 binlog,確保備份一致性
mysql -h${MYSQL_HOST}-P${MYSQL_PORT}-u${MYSQL_USER}-p${MYSQL_PASSWORD}
 -e"FLUSH BINARY LOGS;"

# 拷貝所有 binlog 文件(不包括正在寫入的最新文件)
forfilein/var/lib/mysql/mysql-bin.*;do
 filename=$(basename"$file")
# 跳過當前正在寫入的文件
if[["$filename"!="$CURRENT_BINLOG"]];then
  cp"$file"${BACKUP_DIR}/${TODAY}/
fi
done

# 刪除 7 天前的備份
find${BACKUP_DIR}-typed -mtime +7 -execrm -rf {} ;

echo"$(date '+%Y-%m-%d %H:%M:%S')- binlog backup completed"

設(shè)置定時任務(wù),每天凌晨執(zhí)行:

# 編輯 crontab
crontab -e

# 每天凌晨 3 點執(zhí)行 binlog 備份
0 3 * * * /bin/bash /opt/scripts/backup_binlog.sh >> /var/log/backup_binlog.log 2>&1

基于 binlog 的時間點恢復原理

理解 binlog 恢復原理是掌握 PITR 的關(guān)鍵。binlog 中記錄了每條 SQL 的執(zhí)行時間、所屬文件名和位置。當我們需要將數(shù)據(jù)庫恢復到某個具體時間點時:

先用全量備份恢復到一個一致的狀態(tài)點(備份時刻的數(shù)據(jù)庫狀態(tài))

找到全量備份對應(yīng)的 binlog 起始位置(--master-data=2記錄的信息)

從這個位置開始,順序讀取 binlog,應(yīng)用 SQL 語句到目標時間點

關(guān)鍵工具是mysqlbinlog,它可以解析 binlog 文件并輸出可執(zhí)行的 SQL 語句:

# 查看某個 binlog 文件的內(nèi)容(不執(zhí)行)
mysqlbinlog /var/lib/mysql/mysql-bin.000010

# 篩選特定時間范圍內(nèi)的日志
mysqlbinlog 
 --start-datetime="2024-01-15 1000"
 --stop-datetime="2024-01-15 1400"
 /var/lib/mysql/mysql-bin.000010 
 > /tmp/binlog_replay.sql

# 篩選特定位置范圍內(nèi)的日志
mysqlbinlog 
 --start-position=1234 
 --stop-position=5678 
 /var/lib/mysql/mysql-bin.000010 
 > /tmp/binlog_replay.sql

# 也可以同時處理多個 binlog 文件(按順序)
mysqlbinlog 
 /var/lib/mysql/mysql-bin.000010 
 /var/lib/mysql/mysql-bin.000011 
 /var/lib/mysql/mysql-bin.000012 
 --start-datetime="2024-01-15 1000"
 --stop-datetime="2024-01-15 1400"
 | mysql -u root -p

使用 ROW 格式的 binlog 時,建議加--verbose(-v)參數(shù),它會把行變更格式化為易讀的 SQL 語句,便于人工排查:

mysqlbinlog -v /var/lib/mysql/mysql-bin.000010

備份恢復全流程:場景化實戰(zhàn)

掌握備份和恢復的各種工具后,接下來看幾個典型的恢復場景。每個場景都模擬了真實的故障情況,按照"故障發(fā)現(xiàn) → 初步評估 → 恢復準備 → 執(zhí)行恢復 → 驗證數(shù)據(jù) → 業(yè)務(wù)驗證"的完整閉環(huán)來演示。

場景一:整庫誤刪除恢復(mysqldump 備份)

故障描述:開發(fā)人員在凌晨 2 點誤執(zhí)行了DROP DATABASE app_db;,需要將數(shù)據(jù)恢復到誤操作之前的狀態(tài)。當前時間是凌晨 2 點 15 分。

第一步:評估損失范圍和可用備份

檢查當前 binlog 狀態(tài),確定故障發(fā)生的時間點和數(shù)據(jù)損失范圍:

# 連接到 MySQL,查看當前的 binlog 文件和位置
mysql -u root -p -e"SHOW MASTER LOGS;"

# 如果數(shù)據(jù)庫已被刪除,可以通過 binlog 文件推斷誤操作的-position
# 先查看最近的 binlog 文件內(nèi)容
mysqlbinlog -v /var/lib/mysql/mysql-bin.000015 | tail -n 100

第二步:找到最近的全量備份

ls -lht /backup/*.sql.gz | head -5

假設(shè)找到的最近全量備份是/backup/app_db_20240114.sql.gz,備份時間是 2024-01-14 凌晨 3 點。

第三步:確定恢復的時間點

通過 binlog 確認誤操作的精確時間:

mysqlbinlog -v /var/lib/mysql/mysql-bin.000015 
 | grep -i"DROP DATABASE"-A 5 -B 5

找到 DROP DATABASE 語句的精確時間,假設(shè)是2024-01-15 0232,對應(yīng)位置是 876543。

第四步:執(zhí)行恢復

恢復前,先在 MySQL 中創(chuàng)建數(shù)據(jù)庫(因為備份文件中包含了 CREATE DATABASE 語句,需要調(diào)整恢復邏輯):

# 創(chuàng)建同名數(shù)據(jù)庫(如果已被刪除)
mysql -u root -p -e"CREATE DATABASE app_db;"

# 恢復全量備份(跳過 DROP DATABASE 相關(guān)的行可能導致的問題)
# 由于備份時間是前一天,我們用備份恢復基礎(chǔ)數(shù)據(jù)
gunzip < /backup/app_db_20240114.sql.gz 
? | mysql -u root -p app_db

第五步:基于 binlog 做時間點恢復

根據(jù)全量備份的--master-data信息,找到備份結(jié)束時的 binlog 位置:

# 從備份文件中提取 master-data 信息
grep -i"CHANGE MASTER"/backup/app_db_20240114.sql.gz | head -3

假設(shè)輸出為:

-- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000014', MASTER_LOG_POS=12345;

這表示備份結(jié)束時的 binlog 位置是 mysql-bin.000014 的第 12345 字節(jié)處。從這個位置開始,重放 binlog 直到誤操作之前:

# 從備份結(jié)束位置重放到誤操作前
mysqlbinlog 
 --start-position=12345 
 --stop-datetime="2024-01-15 0231"
 /var/lib/mysql/mysql-bin.000014 
 /var/lib/mysql/mysql-bin.000015 
 | mysql -u root -p app_db

注意--stop-datetime設(shè)為誤操作時間點的前一秒,確保不包含 DROP DATABASE 語句。

第六步:驗證數(shù)據(jù)完整性

# 檢查數(shù)據(jù)庫和表是否存在
mysql -u root -p -e"USE app_db; SHOW TABLES;"

# 檢查關(guān)鍵表的數(shù)據(jù)量
mysql -u root -p -e"USE app_db; SELECT COUNT(*) FROM orders; SELECT COUNT(*) FROM users;"

# 檢查最近幾條數(shù)據(jù)的時間戳
mysql -u root -p -e"USE app_db; SELECT * FROM orders ORDER BY id DESC LIMIT 5;"

# 檢查誤刪除的表是否已經(jīng)恢復
mysql -u root -p -e"USE app_db; SHOW TABLES LIKE '%dropped%';"

風險提醒:

恢復操作會覆蓋當前數(shù)據(jù)。如果有從庫,應(yīng)先在從庫上驗證恢復流程,確認無誤后再在主庫執(zhí)行

重放 binlog 時如果遇到重復的主鍵沖突(因為備份數(shù)據(jù)本身已經(jīng)包含了部分日志后的數(shù)據(jù)),會導致導入中斷,需要使用--skip-slave-start或調(diào)整 binlog 過濾策略

建議在恢復前做一個當前數(shù)據(jù)庫的即時備份(即使數(shù)據(jù)不完整),作為回退的兜底方案

場景二:單表誤刪除恢復(基于 XtraBackup 備份 + binlog)

故障描述:某張核心表orders被開發(fā)人員執(zhí)行了TRUNCATE orders(清空數(shù)據(jù)),需要單獨恢復這張表。當前數(shù)據(jù)量約 500 萬行。

這個場景的特點是:不需要恢復整個數(shù)據(jù)庫,只需要恢復單張表。結(jié)合 binlog 可以精確定位到 TRUNCATE 之前的數(shù)據(jù)狀態(tài)。

第一步:找到包含誤操作 binlog 信息的 binlog 文件

# 先查 TRUNCATE 語句的精確時間
mysqlbinlog -v /var/lib/mysql/mysql-bin.000016 
 | grep -i"TRUNCATE"-B 10

假設(shè) TRUNCATE orders 發(fā)生在2024-01-15 1415,對應(yīng)位置 54321。

第二步:恢復全量備份到一個臨時實例或臨時目錄

如果直接恢復會影響正在運行的業(yè)務(wù),建議將備份恢復到一個臨時 MySQL 實例,提取表數(shù)據(jù)后再導入生產(chǎn)庫:

# 假設(shè)已有 prepare 好的 XtraBackup 全量備份在 /backup/xtrabackup/full/20240114
# 恢復備份到臨時目錄
mkdir -p /tmp/mysql_restore
xtrabackup --copy-back 
 --target-dir=/backup/xtrabackup/full/20240114 
 --datadir=/tmp/mysql_restore

# 啟動臨時 MySQL 實例(使用不同的端口和 socket)
mysqld --defaults-file=/etc/my.cnf 
 --port=3307 
 --socket=/tmp/mysql.sock 
 --datadir=/tmp/mysql_restore 
 --user=mysql &

第三步:從臨時實例導出誤刪的表

# 連接到臨時實例,導出 TRUNCATE 之前的數(shù)據(jù)
# 先確定備份結(jié)束時的 binlog 位置(同場景一的方法)
mysqlbinlog 
 --start-position=12345 
 --stop-datetime="2024-01-15 1414"
 /var/lib/mysql/mysql-bin.000014 
 /var/lib/mysql/mysql-bin.000015 
 /var/lib/mysql/mysql-bin.000016 
 | mysql -u root -p -P 3307 app_db

# 驗證數(shù)據(jù)
mysql -u root -p -P 3307 -e"USE app_db; SELECT COUNT(*) FROM orders;"

# 導出表數(shù)據(jù)為 SQL
mysqldump -u root -p -P 3307 app_db orders > /tmp/orders_recover.sql

第四步:將數(shù)據(jù)導入生產(chǎn)庫

# 確認生產(chǎn)庫中 orders 表的狀態(tài)
mysql -u root -p -e"USE app_db; DESC orders; SELECT COUNT(*) FROM orders;"

# 清空生產(chǎn)庫 orders 表(如果是 TRUNCATE 后狀態(tài),表為空但結(jié)構(gòu)存在)
# 注意:清空操作前務(wù)必確認有當前數(shù)據(jù)的備份
mysql -u root -p -e"USE app_db; TRUNCATE TABLE orders;"

# 從恢復的數(shù)據(jù)中篩選出需要的數(shù)據(jù),再次確認時間戳
# 將導出的數(shù)據(jù)導入生產(chǎn)庫
mysql -u root -p app_db < /tmp/orders_recover.sql

# 驗證恢復結(jié)果
mysql -u root -p -e?"USE app_db; SELECT COUNT(*) FROM orders; SELECT MAX(created_at) FROM orders;"

風險提醒:

臨時 MySQL 實例會和生產(chǎn)實例競爭服務(wù)器資源(CPU、內(nèi)存、磁盤 IO),在生產(chǎn)高峰期不要執(zhí)行這類操作

TRUNCATE 是 DDL 語句,binlog 中記錄的是 CREATE TABLE 新建空表的事件(取決于 binlog_format),row 格式下 TRUNCATE 被記錄為刪除所有行的事件,恢復時需要按行恢復

如果生產(chǎn)庫和臨時實例的 MySQL 版本不同,某些 InnoDB 數(shù)據(jù)頁格式可能有兼容性問題,需要提前驗證

場景三:全量恢復演練(XtraBackup 物理恢復)

故障描述:服務(wù)器硬盤故障導致 MySQL 數(shù)據(jù)目錄損壞,需要在更換硬盤后從備份恢復服務(wù)。

這是最極端的恢復場景,考驗的是備份的可恢復性和恢復流程的熟練程度。

第一步:確認備份集可用

# 檢查備份目錄是否存在且完整
ls -lht /backup/xtrabackup/full/

# 檢查 checkpoints 文件,確認備份類型為 full-backuped
cat /backup/xtrabackup/full/20240114/xtrabackup_checkpoints

# 輸出應(yīng)為:
# backup_type = full-backuped
# from_lsn = 0
# to_lsn = 87654321

第二步:停止 MySQL 服務(wù)

# 停止 MySQL(生產(chǎn)環(huán)境建議先關(guān)閉緩沖寫入,等待片刻)
systemctl stop mysqld
# 或者
mysqladmin -u root -p shutdown

# 確認 MySQL 已完全停止
ps aux | grep mysql

第三步:備份現(xiàn)有數(shù)據(jù)目錄(如果還有殘留數(shù)據(jù))

即使硬盤故障,也不應(yīng)該直接清空數(shù)據(jù)目錄,應(yīng)該先嘗試保留現(xiàn)有文件:

# 如果磁盤還能讀取,先做一次殘留數(shù)據(jù)的拷貝
cp -a /var/lib/mysql /backup/rescue_old_data_$(date +%Y%m%d%H%M%S)

第四步:清空數(shù)據(jù)目錄

# 確認磁盤已更換或修復
# 清空原數(shù)據(jù)目錄(必須確認已做好殘留數(shù)據(jù)備份)
rm -rf /var/lib/mysql/*

# 確認目錄已清空
ls -la /var/lib/mysql/

第五步:執(zhí)行物理恢復

# 使用 xtrabackup 拷貝備份數(shù)據(jù)到目標數(shù)據(jù)目錄
xtrabackup 
 --copy-back 
 --target-dir=/backup/xtrabackup/full/20240114

# 如果備份是壓縮的,需要先解壓再拷貝
# xtrabackup --decompress --target-dir=/backup/xtrabackup/full/20240114

第六步:設(shè)置正確的文件權(quán)限

chown -R mysql:mysql /var/lib/mysql

第七步:啟動 MySQL 并驗證

# 啟動 MySQL
systemctl start mysqld

# 檢查啟動日志
tail -n 100 /var/log/mysqld.log | grep -i error

# 驗證數(shù)據(jù)庫可訪問
mysql -u root -p -e"SHOW DATABASES;"
mysql -u root -p -e"USE app_db; SELECT COUNT(*) FROM orders;"

第八步:驗證復制狀態(tài)(如果配置了主從)

# 在從庫上檢查復制狀態(tài)
mysql -u root -p -e"SHOW SLAVE STATUSG"
# 或 MySQL 8.0
mysql -u root -p -e"SHOW REPLICA STATUSG"

重點關(guān)注以下字段:

Slave_IO_Running和Slave_SQL_Running(或Replica_IO_Running和Replica_SQL_Running)是否為 YES

Seconds_Behind_Master(或Seconds_Behind_Source)是否為 0 或很小的值

Last_Error是否為空

備份策略自動化

手動執(zhí)行備份在測試環(huán)境可以工作,但生產(chǎn)環(huán)境必須實現(xiàn)自動化。本節(jié)介紹如何搭建完整的備份自動化體系。

備份腳本設(shè)計原則

一個生產(chǎn)可用的備份腳本必須滿足以下要求:

冪等性:重復執(zhí)行不會產(chǎn)生副作用,不會覆蓋正在進行的備份

日志記錄:每次執(zhí)行的輸入輸出必須記錄到日志文件,包含開始時間、結(jié)束時間、備份文件大小、是否成功

異常處理:備份失敗時必須發(fā)送告警,不能靜默失敗

干跑模式:支持 dry-run,用于驗證腳本邏輯正確性

保留策略:自動清理過期備份,避免磁盤空間耗盡

完整的 mysqldump 備份腳本

#!/bin/bash
# /opt/scripts/mysql_backup.sh
# MySQL 自動備份腳本,支持全量備份和 binlog 備份

set-euo pipefail

# ========== 配置區(qū) ==========
BACKUP_ROOT="/backup/mysql"
MYSQL_HOST="127.0.0.1"
MYSQL_PORT="3306"
MYSQL_USER="root"
MYSQL_PASS="Str0ngP@ssword"
DBS_TO_BACKUP="app_db cache_db log_db"
RETENTION_DAYS=7
LOG_FILE="/var/log/mysql_backup.log"
DRY_RUN=false

# ========== 工具函數(shù) ==========
log() {
 echo"[$(date '+%Y-%m-%d %H:%M:%S')] $*"| tee -a"$LOG_FILE"
}

send_alert() {
 # 這里的 alert 是示意,生產(chǎn)環(huán)境應(yīng)接入 Prometheus、釘釘、郵件等告警渠道
 echo"[ALERT] $*"
}

die() {
 log"ERROR: $*"
  send_alert"MySQL backup failed: $*"
 exit1
}

# ========== 參數(shù)解析 ==========
while[[$#-gt 0 ]];do
 case$1in
    --dry-run)
      DRY_RUN=true
     shift
      ;;
    --help)
     echo"Usage:$0[--dry-run]"
     echo" --dry-run 干跑模式,不實際執(zhí)行備份"
     exit0
      ;;
    *)
     shift
      ;;
 esac
done

# ========== 備份前檢查 ==========
# 檢查 MySQL 連接
log"檢查 MySQL 連接..."
mysql -h"${MYSQL_HOST}"-P"${MYSQL_PORT}"-u"${MYSQL_USER}"-p"${MYSQL_PASS}"
  -e"SELECT 1;"> /dev/null 2>&1 
  || die"無法連接到 MySQL"

# 檢查備份目錄磁盤空間(至少保留 20GB 可用)
AVAIL=$(df -BG"$BACKUP_ROOT"| awk'NR==2 {print $4}'| tr -d'G')
if[["$AVAIL"-lt 20 ]];then
  die"備份目錄磁盤空間不足,當前可用:${AVAIL}GB"
fi

# ========== 執(zhí)行備份 ==========
log"========== 開始 MySQL 備份 =========="
TODAY=$(date +%Y%m%d)
BACKUP_DIR="${BACKUP_ROOT}/${TODAY}"
mkdir -p"$BACKUP_DIR"

# 備份每個數(shù)據(jù)庫
fordbin$DBS_TO_BACKUP;do
 log"備份數(shù)據(jù)庫:$db"
  BACKUP_FILE="${BACKUP_DIR}/${db}_${TODAY}.sql.gz"

 if[["$DRY_RUN"=="true"]];then
   log"[DRY-RUN] 干跑模式: mysqldump -h${MYSQL_HOST}-P${MYSQL_PORT}-u${MYSQL_USER}${db}| gzip >${BACKUP_FILE}"
   continue
 fi

 # 執(zhí)行備份并壓縮
  mysqldump 
    -h"${MYSQL_HOST}"
    -P"${MYSQL_PORT}"
    -u"${MYSQL_USER}"
    -p"${MYSQL_PASS}"
    --single-transaction 
    --routines 
    --triggers 
    --events 
    --master-data=2 
    --flush-logs 
    --databases"$db"
    | gzip >"${BACKUP_FILE}.tmp"
    || die"備份$db失敗"

  mv"${BACKUP_FILE}.tmp""${BACKUP_FILE}"

 # 記錄備份文件大小
  SIZE=$(du -h"$BACKUP_FILE"| cut -f1)
 log" -> 已保存:$BACKUP_FILE($SIZE)"
done

# ========== 備份 binlog ==========
log"備份 binlog..."
BINLOG_DIR="${BACKUP_ROOT}/binlog/${TODAY}"
mkdir -p"$BINLOG_DIR"

if[["$DRY_RUN"=="true"]];then
 log"[DRY-RUN] 干跑模式: 拷貝 binlog 文件到${BINLOG_DIR}"
else
 # 獲取當前 binlog 文件名(不拷貝正在寫入的當前文件)
  CURRENT_BINLOG=$(mysql -h"${MYSQL_HOST}"-P"${MYSQL_PORT}"-u"${MYSQL_USER}"-p"${MYSQL_PASS}"
    -N -e"SHOW BINARY LOGS;"| tail -n 1 | awk'{print $1}')

 # 刷新日志,產(chǎn)生一個新的 binlog 文件(確保當前寫入的內(nèi)容被保存)
  mysql -h"${MYSQL_HOST}"-P"${MYSQL_PORT}"-u"${MYSQL_USER}"-p"${MYSQL_PASS}"
    -e"FLUSH BINARY LOGS;"

 # 拷貝所有已完成的歷史 binlog 文件
 forfin/var/lib/mysql/mysql-bin.*;do
    fname=$(basename"$f")
   if[["$fname"!="$CURRENT_BINLOG"]];then
      cp"$f""${BINLOG_DIR}/"
   fi
 done

 log" -> binlog 已保存到${BINLOG_DIR}"
fi

# ========== 清理過期備份 ==========
log"清理超過${RETENTION_DAYS}天的備份..."
if[["$DRY_RUN"=="true"]];then
 log"[DRY-RUN] 干跑模式: find${BACKUP_ROOT}-type f -mtime +${RETENTION_DAYS}"
else
  find"${BACKUP_ROOT}"-typef -mtime +"${RETENTION_DAYS}"-delete
 log"清理完成"
fi

# ========== 完成 ==========
log"========== 備份完成:$(date '+%Y-%m-%d %H:%M:%S')=========="

給腳本添加執(zhí)行權(quán)限:

chmod +x /opt/scripts/mysql_backup.sh

配置定時任務(wù)

# 每天凌晨 3 點執(zhí)行全量備份
0 3 * * * /bin/bash /opt/scripts/mysql_backup.sh >> /var/log/mysql_backup.log 2>&1

# 每周日凌晨 4 點執(zhí)行一次完整的備份(包括所有數(shù)據(jù)庫)
0 4 * * 0 /bin/bash /opt/scripts/mysql_backup.sh >> /var/log/mysql_backup.log 2>&1

備份監(jiān)控:確認備份是否成功

備份腳本即使寫得很完善,也不能保證它每次都執(zhí)行成功。必須引入監(jiān)控機制,確保告警能夠及時傳達給運維人員。

#!/bin/bash
# /opt/scripts/check_backup.sh
# 檢查最近的備份是否存在、文件大小是否正常

BACKUP_ROOT="/backup/mysql"
ALERT_THRESHOLD_MB=10 # 備份文件小于 10MB 視為異常
RECENT_BACKUP=$(find"${BACKUP_ROOT}"-name"*.sql.gz"-typef | sort -r | head -n 1)

if[[ -z"$RECENT_BACKUP"]];then
 echo"[ALERT] 未找到任何備份文件!"
 exit1
fi

# 獲取備份文件大?。∕B)
SIZE_MB=$(du -m"$RECENT_BACKUP"| cut -f1)

if[["$SIZE_MB"-lt"$ALERT_THRESHOLD_MB"]];then
 echo"[ALERT] 備份文件異常小:${RECENT_BACKUP}大小:${SIZE_MB}MB (閾值:${ALERT_THRESHOLD_MB}MB)"
 exit1
fi

# 檢查備份文件的修改時間,確保是今天生成的
BACKUP_DATE=$(stat-c %y"$RECENT_BACKUP"| cut -d' '-f1)
TODAY=$(date +%Y-%m-%d)

if[["$BACKUP_DATE"!="$TODAY"]];then
 echo"[ALERT] 最新備份不是今天的:${BACKUP_DATE}"
 exit1
fi

echo"[OK] 備份正常:${RECENT_BACKUP}(${SIZE_MB}MB)"

將監(jiān)控腳本接入 Prometheus+Grafana 或其他告警系統(tǒng)。在 Prometheus 中可以配置一個 cron job 定期執(zhí)行這個腳本,將結(jié)果作為指標暴露出去。

一個簡單的接入方式是讓腳本返回非零退出碼來觸發(fā)告警,在 Prometheus Alertmanager 中配置基于退出碼的告警規(guī)則:

# prometheus rules 示例
groups:
-name:mysql_backup
 rules:
  -alert:MySQLBackupFailed
   expr:cron_backup_check_exit_code!=0
   for:5m
   labels:
    severity:critical
   annotations:
    summary:"MySQL 備份失敗"
    description:"最近的備份文件異?;虿淮嬖?,請立即檢查。"

備份壓縮與并行化

對于大型數(shù)據(jù)庫,可以在備份腳本中加入并行處理能力,顯著減少備份時間:

# 使用 GNU parallel 對多個數(shù)據(jù)庫并行備份
export-f backup_one_db
backup_one_db() {
 localdb=$1
 localbackup_root=$2
 localtoday=$(date +%Y%m%d)
 localmysql_host="127.0.0.1"
 localmysql_port="3306"
 localmysql_user="root"
 localmysql_pass="Str0ngP@ssword"

  mysqldump 
    -h"${mysql_host}"
    -P"${mysql_port}"
    -u"${mysql_user}"
    -p"${mysql_pass}"
    --single-transaction 
    --routines 
    --triggers 
    --events 
    --master-data=2 
    --flush-logs 
    --databases"$db"
    | gzip >"${backup_root}/${db}_${today}.sql.gz"
}

# 導出函數(shù)和變量供 parallel 使用
export-f backup_one_db
exportBACKUP_ROOT="/backup/mysql"
exportMYSQL_HOST MYSQL_PORT MYSQL_USER MYSQL_PASS

# 列出需要備份的數(shù)據(jù)庫,用 parallel 并行執(zhí)行
echo"app_db cache_db log_db analytics_db"| tr' ''
'| 
  parallel -j 4 backup_one_db {}"${BACKUP_ROOT}"

備份恢復的風險控制

備份恢復體系的核心不僅是"能備份",更重要的是"敢恢復"。很多團隊備份做了很多,但真正需要恢復時才發(fā)現(xiàn)備份不可用、恢復流程不通、或者恢復時間遠超預期。本節(jié)重點講風險控制。

備份恢復的可測試性

備份如果從未測試恢復,就等于沒有備份。建議按以下頻率進行恢復演練:

每月一次:在隔離環(huán)境中執(zhí)行完整的全量恢復,驗證備份文件完整性和恢復流程正確性

每季度一次:模擬真實的災(zāi)難恢復場景,包括單表恢復、PITR 恢復、跨服務(wù)器恢復

每次備份腳本變更后:變更備份腳本可能引入 bug,變更后必須立即測試

演練時需要注意:

不要在生產(chǎn)環(huán)境直接演練,使用獨立的測試環(huán)境

記錄演練的耗時,評估 RTO(Recovery Time Objective)是否滿足業(yè)務(wù)要求

演練后總結(jié)問題,更新恢復文檔和腳本

RPO 與 RTO 評估

RPO(Recovery Point Objective):業(yè)務(wù)能容忍的最大數(shù)據(jù)丟失量。這個指標決定了備份頻率——如果 RPO 是 15 分鐘,那么必須每 15 分鐘做一次增量備份或 binlog 備份。

RTO(Recovery Time Objective):從故障發(fā)生到業(yè)務(wù)恢復的總時間。這個指標決定了恢復方案的選擇——如果 RTO 要求是 30 分鐘,但你的備份恢復需要 2 小時,說明備份策略或恢復方案需要優(yōu)化。

常見配置參考:

業(yè)務(wù)類型 RPO RTO 建議備份策略
核心交易系統(tǒng) < 5 分鐘 < 30 分鐘 實時 binlog 備份 + 每小時增量 + 每日全量
普通業(yè)務(wù)系統(tǒng) 1 小時 2 小時 每 15 分鐘 binlog + 每日全量
內(nèi)部工具系統(tǒng) 24 小時 24 小時 每日全量

備份數(shù)據(jù)的安全保護

備份文件包含完整的業(yè)務(wù)數(shù)據(jù),必須妥善保護:

加密備份文件:

# 使用 gpg 對備份文件加密
gpg --batch --yes --passphrase"YourPassphrase"
  --symmetric --cipher-algo AES256 
  /backup/app_db_20240114.sql.gz

# 加密后的文件擴展名通常為 .gpg
# 解密時使用
gpg --batch --yes --passphrase"YourPassphrase"
  --decrypt /backup/app_db_20240114.sql.gz.gpg 
  | mysql -u root -p app_db

注意:密碼不應(yīng)該硬編碼在腳本中,建議使用環(huán)境變量或密鑰管理服務(wù)(如 HashiCorp Vault)。生產(chǎn)環(huán)境的備份加密策略應(yīng)根據(jù)數(shù)據(jù)安全合規(guī)要求(等保、GDPR 等)制定。

備份文件權(quán)限控制:

# 備份目錄僅允許 root 和 mysql 用戶訪問
chown -R root:mysql /backup
chmod 700 /backup
chmod 600 /backup/*.sql.gz

異地備份:本地備份無法抵御本地災(zāi)難(火災(zāi)、盜竊、機房級故障)。重要數(shù)據(jù)應(yīng)該同時備份到異地存儲。常見的異地備份方案:

對象存儲(S3、阿里云 OSS、騰訊云 COS):成本低、可靠性高,適合長期保留

異地服務(wù)器:通過 ssh + rsync 增量同步備份文件

數(shù)據(jù)庫主從復制:在異地機房搭建從庫,實時同步數(shù)據(jù)

備份對性能的影響

備份操作會消耗服務(wù)器資源,對生產(chǎn)業(yè)務(wù)造成性能壓力。評估和緩解備份對業(yè)務(wù)的影響:

mysqldump 對性能的影響:--single-transaction模式下,InnoDB 表的備份不會鎖表,但事務(wù)開始和結(jié)束時的快照切換會短暫阻塞所有寫入。如果業(yè)務(wù)高峰期的寫入量很大,備份事務(wù)可能持有快照時間較長,導致 undo 日志膨脹。

緩解方法:使用--single-transaction時配合合理的快照時間窗口;避免在業(yè)務(wù)高峰期執(zhí)行備份;或者使用 XtraBackup 替代 mysqldump。

XtraBackup 對性能的影響:XtraBackup 的備份過程會讀取大量數(shù)據(jù)頁,對磁盤 IO 和 CPU 都有一定壓力。優(yōu)化方法:

# 使用 --throttle 參數(shù)限制 IO 操作速度,減少對業(yè)務(wù)的影響
xtrabackup 
 --backup 
 --user=backup 
 --password='Str0ngP@ssword'
 --target-dir=/backup/xtrabackup/full/$(date +%Y%m%d) 
 --throttle=100 
 --parallel=2

--throttle=100表示每秒最多執(zhí)行 100 次 IO 操作。生產(chǎn)環(huán)境中建議從較低值開始測試,找到對業(yè)務(wù)影響可接受的最大值。

常見問題與排錯

備份文件損壞

備份文件損壞是常見問題,可能由磁盤故障、壓縮工具 bug、網(wǎng)絡(luò)傳輸中斷等原因?qū)е隆z測備份文件完整性的方法:

# 檢查 gzip 文件完整性
gzip -t /backup/app_db_20240114.sql.gz
echo$? # 返回 0 表示文件完整

# 使用 mysqldump 的 --verbose 模式檢查 SQL 文件頭尾
head -20 /backup/app_db_20240114.sql.gz | gunzip | head -20
tail -20 /backup/app_db_20240114.sql.gz | gunzip | tail -20

# 嘗試解析 SQL 文件,檢查是否有截斷
gunzip < /backup/app_db_20240114.sql.gz | tail -n 5
# 正常文件末尾應(yīng)該是包含數(shù)據(jù)庫備份結(jié)束標記和最后幾個 INSERT 語句

XtraBackup 的備份完整性可以通過 checkpoints 文件來驗證:

cat /backup/xtrabackup/full/20240114/xtrabackup_checkpoints

# backup_type 表示備份類型
# from_lsn 和 to_lsn 如果相等,說明備份是空的
# last_lsn 應(yīng)該大于 to_lsn(prepare 后)

恢復時表已存在

使用 mysqldump 恢復時,如果目標數(shù)據(jù)庫中已經(jīng)存在同名表,會報錯退出。可以使用以下策略處理:

策略一:強制創(chuàng)建(會丟失現(xiàn)有表數(shù)據(jù)):

# 備份現(xiàn)有表結(jié)構(gòu)(以防萬一)
mysqldump -u root -p --no-data dbname table_name > /tmp/table_structure.sql

# 刪掉現(xiàn)有表
mysql -u root -p dbname -e"DROP TABLE table_name;"

# 恢復數(shù)據(jù)
mysql -u root -p dbname < /backup/dbname_20240114.sql.gz

策略二:使用 --add-drop-table 參數(shù):

# 重新生成備份,加上 DROP TABLE IF EXISTS 語句
mysqldump -u root -p --single-transaction --add-drop-table 
 --databases dbname | gzip > /backup/dbname_with_drop_$(date +%Y%m%d).sql.gz

策略三:只恢復數(shù)據(jù),不恢復表結(jié)構(gòu)(推薦):

# 從備份中提取表的 INSERT 語句(跳過 CREATE TABLE)
gunzip < /backup/dbname_20240114.sql.gz 
? | grep -v?"CREATE TABLE"?
? | grep -v?"DROP TABLE"?
? | grep -v?"LOCK TABLES"?
? | mysql -u root -p dbname

注意:策略三在表結(jié)構(gòu)已存在且未變化時可用,但如果表結(jié)構(gòu)有差異(列類型不同、缺少列等),可能會報錯。

XtraBackup 恢復時 innodb_log_file_size 不匹配

執(zhí)行xtrabackup --copy-back時,如果備份信息中的innodb_log_file_size與目標 MySQL 配置不一致,會導致啟動失敗。

檢查備份配置:

cat /backup/xtrabackup/full/20240114/backup-my.cnf

輸出示例:

[mysqld]
datadir=/var/lib/mysql
innodb_log_file_size=50331648

檢查當前 MySQL 配置:

grep innodb_log_file_size /etc/my.cnf

如果不一致,需要調(diào)整目標 MySQL 的innodb_log_file_size配置,重啟 MySQL 使其生效后,再執(zhí)行 copy-back。或者,如果現(xiàn)有 MySQL 實例的日志文件大小是正確的,可以從現(xiàn)有實例中獲取正確的值。

binlog 文件損壞或丟失

如果某個 binlog 文件損壞,mysqlbinlog解析時會報錯:

mysqlbinlog /var/lib/mysql/mysql-bin.000018
# 輸出可能包含 "ERROR: Error in Log_event" 等錯誤

對于已損壞的 binlog,無法通過它恢復數(shù)據(jù)。需要判斷數(shù)據(jù)損失的范圍:

確認損壞的 binlog 文件編號:SHOW BINARY LOGS;

從上一個完好的 binlog 文件開始恢復,到損壞文件之前的最后一個完好位置

如果所有后續(xù)備份都依賴損壞的 binlog,則該時間點之后的數(shù)據(jù)無法通過 binlog 恢復,只能從下一個全量備份重新開始

這就體現(xiàn)了異地備份和備份驗證的重要性——如果 binlog 只保存在本地服務(wù)器上,本地故障會導致 binlog 和數(shù)據(jù)文件同時丟失。

mysqldump 備份時表被其他 session 鎖住

在某些情況下,--single-transaction可能無法正常工作(比如有未提交的長事務(wù)或大事務(wù))。如果備份期間有其他 session 對表加了鎖,會導致 mysqldump 的備份視圖與預期不符。

檢查當前未提交的長事務(wù):

SELECT*FROMinformation_schema.INNODB_TRXWHEREtrx_state ='RUNNING';

關(guān)注trx_started字段,如果發(fā)現(xiàn)有運行時間異常長的事務(wù)(持續(xù)幾小時甚至更久),可能是應(yīng)用出現(xiàn)了未提交事務(wù)的 bug,應(yīng)該先處理這個問題再進行備份。

# 如果發(fā)現(xiàn)長時間運行的事務(wù),可以根據(jù) trx_id kill 掉(慎用?。?KILL 12345;

在 kill 之前,務(wù)必確認這個事務(wù)不是正常業(yè)務(wù)事務(wù)(比如數(shù)據(jù)導入、大表更新等)。聯(lián)系開發(fā)人員確認后再執(zhí)行 kill。

恢復后從庫復制延遲

主庫恢復后,如果配置了主從復制,從庫通常會因為需要同步大量數(shù)據(jù)而產(chǎn)生延遲。解決步驟:

確認從庫狀態(tài):SHOW SLAVE STATUSG或SHOW REPLICA STATUSG

確認從庫的Slave_IO_Running和Slave_SQL_Running是否為 YES

如果Seconds_Behind_Master(或Seconds_Behind_Source)很大,等待復制追上,或者調(diào)整主從復制的并發(fā)度

-- 在從庫上調(diào)整復制相關(guān)參數(shù)(MySQL 5.7+)
STOPSLAVE;
SETGLOBALslave_parallel_workers =4; -- 增加復制線程數(shù)
SETGLOBALslave_parallel_type = LOGICAL_CLOCK; -- 使用邏輯時鐘并發(fā)
STARTSLAVE;

MySQL 8.0 中引入了更多復制優(yōu)化,包括基于writeset 的并行復制(binlog_transaction_dependency_tracking = WRITESET),可以顯著提升從庫的復制并行度。

備份成功但恢復后發(fā)現(xiàn)數(shù)據(jù)不完整

這是最嚴重的問題。備份成功了,但在恢復時發(fā)現(xiàn)備份本身就不完整。根本原因可能是:

備份時使用了--single-transaction,但存在未提交的事務(wù)導致快照不一致

備份過程中有 DDL 操作(如 ALTER TABLE、DROP TABLE),導致備份期間數(shù)據(jù)不一致

備份文件被部分寫入或截斷

預防措施:

備份期間暫停所有 DDL 操作,或者使用--lock-all-tables代替--single-transaction(但會鎖表)

備份完成后立即檢查備份文件大小,和上次對比是否有明顯異常

備份文件壓縮前檢查完整性(gzip -t)

定期做恢復演練,驗證備份數(shù)據(jù)確實是完整的

備份方案設(shè)計最佳實踐

綜合前面所有內(nèi)容,梳理一套生產(chǎn)級 MySQL 備份方案的最佳實踐:

備份工具組合:

中小型數(shù)據(jù)庫(數(shù)據(jù)量 < 100GB):mysqldump + 定時任務(wù) + binlog 備份

大型數(shù)據(jù)庫(數(shù)據(jù)量 > 100GB):XtraBackup 全量 + XtraBackup 增量 + binlog 備份

備份頻率建議:

全量備份:每天 1 次,建議在業(yè)務(wù)低峰期(如凌晨 3 點)執(zhí)行

增量備份(XtraBackup):每 6 小時一次

binlog 備份:每 15~30 分鐘一次

備份文件保留:至少 7 天,建議 30 天

備份監(jiān)控必須覆蓋:

備份任務(wù)是否按時執(zhí)行

備份文件大小是否異常(小于閾值立即告警)

備份文件是否完整(gzip -t 檢查)

定時執(zhí)行恢復演練

安全策略:

備份文件權(quán)限 600,僅 root 和 mysql 可訪問

敏感數(shù)據(jù)備份必須加密

異地備份,至少有一份備份在獨立存儲或異地機房

備份賬號使用最小權(quán)限(不需要 SELECT 權(quán)限,需要 PROCESS、RELOAD、LOCK TABLES、REPLICATION CLIENT)

恢復能力驗證:

每月至少一次完整恢復演練

記錄每次演練的 RTO,實際測量恢復時間

如果 RTO 不滿足業(yè)務(wù)要求,需要優(yōu)化備份策略或提升恢復速度

總結(jié)

MySQL 備份與恢復是運維工作中最考驗體系化能力的領(lǐng)域之一。單個工具(mysqldump 或 XtraBackup)的使用并不復雜,真正的挑戰(zhàn)在于:

第一,備份體系的建設(shè)需要結(jié)合業(yè)務(wù)對 RPO/RTO 的實際要求來設(shè)計,不是越頻繁越好,也不是保存越久越好。脫離業(yè)務(wù)需求的備份策略要么造成資源浪費,要么無法滿足恢復需求。

第二,備份的可恢復性比備份本身更重要。一次沒有被驗證過的備份,在真正需要恢復時可能變成一場災(zāi)難。每月一次恢復演練是最好的"保險"。

第三,自動化 + 監(jiān)控是生產(chǎn)環(huán)境的必備條件。沒有人應(yīng)該每天手動檢查備份任務(wù)是否成功,所有備份異常都應(yīng)該通過告警系統(tǒng)實時通知到值班人員。

第四,恢復流程必須形成閉環(huán):故障評估 → 備份選擇 → 恢復執(zhí)行 → 數(shù)據(jù)驗證 → 業(yè)務(wù)驗證 → 復盤總結(jié)。每一步都要有明確的判斷標準和執(zhí)行人。

整個備份體系的建設(shè)不是一蹴而就的。建議從本文的基礎(chǔ)內(nèi)容開始,先在測試環(huán)境走通全流程,再逐步加入監(jiān)控、異地備份、并行化等高級能力,最終形成一套可靠、可驗證、可告警的備份恢復體系。

在生產(chǎn)環(huán)境中,備份相關(guān)的腳本、配置、策略和演練記錄都應(yīng)該納入版本管理,定期 review 和更新。當真正發(fā)生數(shù)據(jù)故障時,你最寶貴的資源不是備份文件本身,而是備份恢復的熟練度和完善的恢復文檔。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 數(shù)據(jù)庫
    +關(guān)注

    關(guān)注

    7

    文章

    4089

    瀏覽量

    68613
  • MySQL
    +關(guān)注

    關(guān)注

    1

    文章

    936

    瀏覽量

    29805

原文標題:一文搞定:MySQL 自動備份配置與恢復演練全教程

文章出處:【微信號:magedu-Linux,微信公眾號:馬哥Linux運維】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關(guān)推薦
    熱點推薦

    《ZigBee入門與實戰(zhàn)演練

    《ZigBee入門與實戰(zhàn)演練》比較好奧,大家可以看看啊
    發(fā)表于 03-27 20:48

    基于linux的mysql數(shù)據(jù)庫每天自動備份定時備份的實現(xiàn)

    linux下如何實現(xiàn)mysql數(shù)據(jù)庫每天自動備份定時備份
    發(fā)表于 05-10 17:10

    FPGA II實戰(zhàn)演練V1.0

    FPGA II實戰(zhàn)演練V1.0,感興趣的小伙伴們可以瞧一瞧。
    發(fā)表于 11-17 11:43 ?7次下載

    FPGA II實戰(zhàn)演練V1.0

    FPGA II實戰(zhàn)演練V1.0,感興趣的小伙伴們可以瞧一瞧。
    發(fā)表于 11-05 14:48 ?12次下載

    MySQL基礎(chǔ)架構(gòu)自動化測試分析

    MySQL對于GitHub的重要性不言而喻,本文作者從MySQL備份、自動測試能否成功從備份恢復
    發(fā)表于 09-28 16:47 ?0次下載
    <b class='flag-5'>MySQL</b>基礎(chǔ)架構(gòu)<b class='flag-5'>自動</b>化測試分析

    Linux教程之linux下如何備份還原mysql數(shù)據(jù)庫

    本文介紹了linux下如何備份恢復mysql數(shù)據(jù)庫。數(shù)據(jù)庫備份是非常重要的。如果定期做好備份,這樣就可以在發(fā)生系統(tǒng)崩潰時
    發(fā)表于 10-19 17:18 ?4次下載

    為什么MySQL備份很重要?MySQL備份類型有哪些?

    隨著企業(yè)和應(yīng)用程序越來越依賴 MySQL 數(shù)據(jù)庫來管理其關(guān)鍵數(shù)據(jù),確保數(shù)據(jù)可靠性和可用性變得至關(guān)重要。在這個數(shù)字信息時代,強大的備份恢復策略是應(yīng)用程序穩(wěn)定性的支柱。 本文中,我們將回顧所有常用
    的頭像 發(fā)表于 11-14 10:20 ?1415次閱讀

    mysql數(shù)據(jù)庫備份與還原

    法、備份文件的恢復以及一些常見問題的解決方案。 第一部分:MySQL備份的不同方法 1.1 使用mysqldump命令備份 mysqldum
    的頭像 發(fā)表于 11-23 14:32 ?2260次閱讀

    mysql備份還原哪些方法

    MySQL是一個開源的關(guān)系型數(shù)據(jù)庫管理系統(tǒng),備份和還原是保證數(shù)據(jù)安全性和可恢復性的重要措施。本文將詳細介紹MySQL備份和還原的方法,包括物
    的頭像 發(fā)表于 11-23 14:35 ?1836次閱讀

    mysql中表分區(qū)的備份恢復

    MySQL的表分區(qū)是一種將大型表分成更小段的技術(shù),這樣可以提高查詢效率、降低維護成本和減少數(shù)據(jù)備份恢復時間。在進行表分區(qū)的過程中,我們也需要了解如何備份
    的頭像 發(fā)表于 11-23 14:39 ?2541次閱讀

    mysql定時備份任務(wù)

    在生產(chǎn)環(huán)境上,為了避免數(shù)據(jù)的丟失,通常情況下都會定時的對數(shù)據(jù)庫進行備份。而Linux的crontab指令則可以幫助我們實現(xiàn)對數(shù)據(jù)庫定時進行備份。首先我們來簡單了解crontab指令,如果你會了請?zhí)较乱粋€內(nèi)容mysql
    的頭像 發(fā)表于 10-31 10:07 ?1209次閱讀

    windows服務(wù)器備份mysql腳本

    = 'root'db_passwd = 'PASSWD'db_port = '3306'## 備份存放的目錄地址,沒有回自動生成back_dir = '/backups/mysql'# 備份
    的頭像 發(fā)表于 01-02 09:14 ?910次閱讀

    MySQL數(shù)據(jù)備份恢復策略

    數(shù)據(jù)是企業(yè)的核心資產(chǎn),MySQL作為主流的關(guān)系型數(shù)據(jù)庫管理系統(tǒng),其數(shù)據(jù)的安全性和可靠性至關(guān)重要。本文將深入探討MySQL的數(shù)據(jù)備份策略、常用備份工具以及數(shù)據(jù)
    的頭像 發(fā)表于 07-14 11:11 ?919次閱讀

    MySQL數(shù)據(jù)庫備份恢復方式對比

    備份是數(shù)據(jù)庫運維中最重要也最容易被忽視的環(huán)節(jié)。"重要"體現(xiàn)在數(shù)據(jù)丟失時備份是唯一的救命稻草,"忽視"體現(xiàn)在很多團隊有備份腳本但從未做過恢復演練
    的頭像 發(fā)表于 03-04 15:39 ?288次閱讀

    一文詳解MySQL備份恢復基礎(chǔ)流程

    數(shù)據(jù)備份是數(shù)據(jù)庫運維的最后一道防線。無論系統(tǒng)設(shè)計多么健壯、人為操作多么謹慎,硬件故障、軟件 BUG、人為誤刪都可能在毫無預兆的情況下發(fā)生。沒有可用的備份,意味著業(yè)務(wù)數(shù)據(jù)面臨永久丟失的風險。2024 年國內(nèi)某云廠商因備份系統(tǒng)缺陷導
    的頭像 發(fā)表于 04-21 11:43 ?256次閱讀
    东安县| 荔波县| 阜新市| 九江县| 宣威市| 加查县| 遂昌县| 五家渠市| 宝鸡市| 信宜市| 介休市| 堆龙德庆县| 防城港市| 韶关市| 电白县| 河源市| 麻城市| 昂仁县| 湛江市| 绥滨县| 宜君县| 吴江市| 阳泉市| 科技| 钟山县| 原阳县| 丹凤县| 静乐县| 三门县| 石阡县| 北川| 阜新市| 乐清市| 台前县| 怀远县| 玉龙| 綦江县| 泾源县| 屏山县| 锡林郭勒盟| 佛教|