MySQL Hot Backup với Percona XtraBackup: Tự động hóa Full và Incremental Backup cho Production

Database tutorial - IT technology blog
Database tutorial - IT technology blog

Bối cảnh & Lý do: Giới hạn của Logical Dump trên môi trường Production

Thời gian đầu khi mới làm nghề, tôi từng nghĩ chỉ cần chạy một cron job mysqldump đơn giản là đã đủ. Nhưng quan điểm đó thay đổi hoàn toàn khi database production chính của chúng tôi vượt mốc 150 GB. Tác vụ dump dữ liệu hàng đêm gây ra hiện tượng query spike nghiêm trọng, làm tràn và loãng InnoDB buffer pool, đồng thời khóa các bảng ngay trong các đợt xử lý batch cao điểm. Tệ hơn nữa, việc khôi phục một file dump duy nhất đó trong đợt diễn tập khắc phục sự cố (disaster recovery) đã mất hơn sáu tiếng đồng hồ.

Với các hệ thống MySQL có lưu lượng truy cập lớn (high-throughput), logical dump đơn giản là không thể đáp ứng được khả năng mở rộng. Logical backup phải tái tạo lại toàn bộ tập dữ liệu theo từng dòng thông qua hàng triệu câu lệnh SQL INSERT. Ngược lại, physical backup hoạt động trực tiếp ở tầng lưu trữ, sao chép các data file thô, tablespace và index ở cấp độ block.

Percona XtraBackup giải quyết bài toán downtime bằng cách thực hiện hot backup hoàn toàn không gây nghẽn (non-blocking). Trong khi database vẫn đang xử lý hàng nghìn query mỗi giây, XtraBackup sao chép các data page của InnoDB và đồng thời theo dõi (tail) các thay đổi phát sinh từ redo log theo thời gian thực. Điều này đảm bảo một snapshot crash-consistent tại một thời điểm xác định mà không cần khóa bảng hay làm suy giảm hiệu năng của người dùng.

Cài đặt và cấu hình Repository

Đối với hệ thống MySQL 8.0, hãy cài đặt Percona XtraBackup 8.0. Lưu ý rằng các phiên bản major phải tương thích với nhau: XtraBackup 8.0 không thể backup cho MySQL 5.7, và XtraBackup 2.4 không thể backup cho MySQL 8.0.

1. Cài đặt Percona Repository

Trên hệ thống Debian và Ubuntu, hãy đăng ký gói release chính thức của Percona:

# Tải về và đăng ký repository của Percona
wget https://repo.percona.com/apt/percona-release_latest.generic_all.deb
sudo dpkg -i percona-release_latest.generic_all.deb

# Bật repository tools cho XtraBackup 8.0
sudo percona-release enable-only tools release
sudo apt-get update

# Cài đặt package
sudo apt-get install -y percona-xtrabackup-80

Trên hệ thống RHEL, Rocky Linux hoặc AlmaLinux:

sudo yum install -y https://repo.percona.com/yum/percona-release-latest.noarch.rpm
sudo percona-release enable-only tools release
sudo yum install -y percona-xtrabackup-80

2. Tạo User chuyên dụng để Backup Database

Tuyệt đối không nên chạy tác vụ backup tự động bằng tài khoản superuser root của MySQL. Thay vào đó, hãy tạo một tài khoản riêng với quyền tối thiểu cần thiết để đọc các data page, kiểm tra trạng thái replication và flush log:

sudo mysql -u root -p
CREATE USER 'xtrabackup'@'localhost' IDENTIFIED BY 'StrongBackupPass123!';

GRANT BACKUP_ADMIN, PROCESS, RELOAD, LOCK TABLES, REPLICATION CLIENT 
ON *.* TO 'xtrabackup'@'localhost';

FLUSH PRIVILEGES;
EXIT;

Cấu hình: Xây dựng Pipeline cho Full và Incremental Backup

Một chiến lược backup vững chắc thường kết hợp giữa bản base backup hàng tuần và các bản incremental backup hàng ngày. Incremental backup chỉ sao chép các data page đã bị thay đổi kể từ lần backup gần nhất. Với một database dung lượng 200 GB nhưng chỉ thay đổi khoảng 5 GB mỗi ngày, phương pháp này giúp rút ngắn thời gian chạy backup từ 40 phút xuống còn dưới 3 phút.

1. Thiết lập thư mục lưu trữ

Nên đặt thư mục backup trên một ổ đĩa riêng biệt hoặc network mount point để tránh làm cạn kiệt dung lượng ổ đĩa hệ điều hành:

sudo mkdir -p /var/backups/mysql/{full,inc}
sudo chown -R mysql:mysql /var/backups/mysql
sudo chmod -R 700 /var/backups/mysql

2. Chạy Full Backup thủ công

Thực hiện bản full backup đầu tiên để kiểm tra phân quyền và đánh giá hiệu năng cơ bản:

xtrabackup --backup \
  --user=xtrabackup \
  --password='StrongBackupPass123!' \
  --target-dir=/var/backups/mysql/full/base_$(date +%F)

Khi lệnh hoàn tất, hãy kiểm tra dòng cuối cùng của output xem có thông báo completed OK! hay không. Thư mục đích sẽ chứa các file dữ liệu thô cùng một file metadata có tên xtrabackup_checkpoints, dùng để lưu trữ các checkpoint Log Sequence Number (LSN).

3. Chạy Incremental Backup

Incremental backup sẽ so sánh thư mục đích với bản base backup, chỉ sao chép các page có giá trị LSN lớn hơn checkpoint trước đó:

xtrabackup --backup \
  --user=xtrabackup \
  --password='StrongBackupPass123!' \
  --target-dir=/var/backups/mysql/inc/inc_$(date +%F) \
  --incremental-basedir=/var/backups/mysql/full/base_2026-10-01

4. Script tự động hóa cho Production

Môi trường production luôn cần sự tự động hóa tin cậy. Script Bash dưới đây sẽ thực hiện full backup vào mỗi Chủ Nhật và incremental backup từ Thứ Hai đến Thứ Bảy. Script cũng tự động cập nhật các symlink thư mục và dọn dẹp các bản backup cũ hơn 14 ngày.

Lưu script này vào đường dẫn /usr/local/bin/mysql-backup.sh:

#!/usr/bin/env bash
set -euo pipefail

BACKUP_ROOT="/var/backups/mysql"
FULL_DIR="${BACKUP_ROOT}/full"
INC_DIR="${BACKUP_ROOT}/inc"
USER="xtrabackup"
PASS="StrongBackupPass123!"
TODAY=$(date +%Y-%m-%d)
DAY_OF_WEEK=$(date +%u) # 7 = Chủ Nhật

mkdir -p "${FULL_DIR}" "${INC_DIR}"

if [ "$DAY_OF_WEEK" -eq 7 ] || [ ! -d "${FULL_DIR}/latest" ]; then
    echo "[$(date)] Bắt đầu Full Backup..."
    TARGET="${FULL_DIR}/full_${TODAY}"
    
    xtrabackup --backup \
      --user="${USER}" \
      --password="${PASS}" \
      --target-dir="${TARGET}"
      
    ln -sfn "${TARGET}" "${FULL_DIR}/latest"
    rm -rf "${INC_DIR}"/*
    echo "[$(date)] Full Backup hoàn tất: ${TARGET}"
else
    echo "[$(date)] Bắt đầu Incremental Backup..."
    LAST_INC=$(find "${INC_DIR}" -maxdepth 1 -mindepth 1 -type d | sort | tail -n 1)
    
    if [ -z "${LAST_INC}" ]; then
        BASE_DIR="${FULL_DIR}/latest"
    else
        BASE_DIR="${LAST_INC}"
    fi
    
    TARGET="${INC_DIR}/inc_${TODAY}"
    
    xtrabackup --backup \
      --user="${USER}" \
      --password="${PASS}" \
      --target-dir="${TARGET}" \
      --incremental-basedir="${BASE_DIR}"
      
    echo "[$(date)] Incremental Backup hoàn tất dựa trên base ${BASE_DIR}: ${TARGET}"
fi

# Xóa các bản full backup cũ hơn 14 ngày
find "${FULL_DIR}" -maxdepth 1 -mindepth 1 -type d -mtime +14 -exec rm -rf {} +

Phân quyền thực thi và thêm tác vụ vào crontab:

sudo chmod +x /usr/local/bin/mysql-backup.sh

# Lập lịch chạy hàng đêm vào lúc 02:00 AM
(crontab -l 2>/dev/null; echo "0 2 * * * /usr/local/bin/mysql-backup.sh >> /var/log/mysql-backup.log 2>&1") | crontab -

Kiểm tra & Khôi phục: Thử nghiệm Restore trước khi sự cố xảy ra

Một bản backup chưa từng được thử nghiệm thì không thể coi là bản backup—đó chỉ là sự hy vọng suông. Do physical backup ghi lại các data page trực tiếp ngay khi các transaction vẫn đang diễn ra, dữ liệu sẽ chứa cả những thay đổi chưa được commit. Bạn bắt buộc phải thực hiện prepare bản backup trước khi MySQL có thể sử dụng dữ liệu một cách an toàn.

1. Chuẩn bị (Prepare) chuỗi Backup

Để khôi phục một bản base backup cùng các thay đổi incremental, bạn cần roll-forward các transaction đã commit từ từng thư mục incremental vào thư mục base. Sử dụng cờ --apply-log-only cho tất cả các bước trung gian để giữ cho bản base backup ở trạng thái mở, sẵn sàng nhận các bản diff tiếp theo:

# Bước 1: Prepare bản full base backup (giữ log mở cho các bản incremental)
xtrabackup --prepare \
  --apply-log-only \
  --target-dir=/var/backups/mysql/full/full_2026-10-01

# Bước 2: Apply bản incremental backup vào thư mục base
xtrabackup --prepare \
  --apply-log-only \
  --target-dir=/var/backups/mysql/full/full_2026-10-01 \
  --incremental-dir=/var/backups/mysql/inc/inc_2026-10-02

# Bước 3: Prepare lần cuối trên thư mục base (rollback các transaction chưa commit)
xtrabackup --prepare \
  --target-dir=/var/backups/mysql/full/full_2026-10-01

2. Khôi phục dữ liệu về thư mục Data của MySQL

Khi bản base backup đã được prepare hoàn tất, hãy sao chép các data file thô trở lại thư mục MySQL:

# Dừng service database
sudo systemctl stop mysql

# Backup thư mục data hiện tại và tạo thư mục đích rỗng
sudo mv /var/lib/mysql /var/lib/mysql.bak_$(date +%F)
sudo mkdir -p /var/lib/mysql

# Khôi phục các data file đã được prepare
xtrabackup --copy-back \
  --target-dir=/var/backups/mysql/full/full_2026-10-01

# Phân quyền lại quyền sở hữu và quyền truy cập file
sudo chown -R mysql:mysql /var/lib/mysql
sudo chmod 750 /var/lib/mysql

# Khởi động service MySQL và kiểm tra trạng thái
sudo systemctl start mysql
sudo systemctl status mysql

3. Giám sát và Health Check

Hãy tích hợp bốn bước kiểm tra vận hành sau vào hệ thống giám sát của bạn (Prometheus node-exporter, Datadog hoặc Zabbix):

  • Exit Code của tiến trình: Cảnh báo ngay lập tức nếu lệnh xtrabackup trả về exit code khác 0.
  • Kiểm tra log string: Phân tích file /var/log/mysql-backup.log để đảm bảo luôn xuất hiện chuỗi xác nhận completed OK!.
  • Kiểm tra tính liên tục của LSN: Đọc file xtrabackup_checkpoints để đối soát rằng from_lsn của mỗi lần chạy incremental khớp chính xác với to_lsn của bản backup liền trước.
  • Tự động restore trên môi trường Sandbox: Thiết lập CI/CD runner hàng tuần để khôi phục chuỗi backup mới nhất lên một instance staging độc lập và chạy các query kiểm thử tính toàn vẹn trên các bảng quan trọng.
Share: