Cấu hình BorgBackup trên CentOS Stream 9: Tự động hóa sao lưu với ZSTD, mã hóa và Deduplication

CentOS tutorial - IT technology blog
CentOS tutorial - IT technology blog

Câu chuyện thực tế: Ổ NAS chạm đỉnh 92% và backup ngốn hơn 3 tiếng

Khoảng nửa năm trước, cụm dịch vụ chạy CentOS Stream 9 bên mình bắt đầu quá tải khâu backup. Cụm này gồm 2 web app Node.js/PHP và 1 cụm MySQL chứa khoảng 40GB dữ liệu giao dịch.

Mỗi đêm, cron job sẽ chạy script dump MySQL, gom thư mục mã nguồn qua tar rồi đẩy sang NAS bằng rsync. Sau 4 tháng vận hành, hệ thống lộ rõ 3 điểm nghẽn:

  • Ổ cứng 2TB trên NAS báo đỏ ở mức 92%, dù retention policy chỉ giữ đúng 14 ngày gần nhất.
  • Thời gian backup kéo dài từ 45 phút lên tận 3 tiếng 20 phút. I/O disk tăng vọt khiến query ứng dụng bị nghẽn (I/O wait vọt lên hơn 35%).
  • Dữ liệu đẩy qua mạng nội bộ hoàn toàn là plain text, không mã hóa đầu cuối (end-to-end encryption).

Vì sao rsync và tar truyền thống hụt hơi?

Cách làm cũ nhìn bề ngoài rất đơn giản, nhưng bên dưới tồn tại 3 rào cản kỹ thuật lớn:

1. Thiếu Deduplication ở cấp độ Block (Chunk-level)

File database 40GB mỗi ngày chỉ đổi khoảng 2-3% số record. Dù vậy, mysqldump hay tar vẫn xuất ra một file hoàn toàn mới với checksum khác biệt. rsync chỉ tối ưu băng thông lúc truyền tải. Tại máy chủ NAS, bạn vẫn phải lưu 14 bản full độc lập nếu muốn giữ lịch sử rollback theo ngày. Tính sơ bộ, 14 bản của riêng database đã nuốt trọn 560GB.

2. Cơ chế hardlink bó tay trước database dump và file nén

Nhiều anh em dùng cờ --link-dest của rsync để tiết kiệm ổ cứng. Cách này chạy rất mượt với ảnh tĩnh hay media ít chỉnh sửa. Ngược lại, nó hoàn toàn vô tác dụng với file nén .tar.gz hoặc SQL dump. Khi nội dung file bị dịch chuyển byte, inode thay đổi, rsync buộc phải lưu toàn bộ file mới.

3. Gzip ngốn CPU đơn nhân nhưng tỷ lệ nén không tương xứng

Tiến trình gzip truyền thống ép một core CPU chạy 100% suốt hàng giờ. Vừa tốn tài nguyên máy chủ, vừa làm chậm cả chuỗi tiến trình phía sau.

Cân nhắc 3 phương án trước khi triển khai

Trước khi gỡ bỏ script cũ, mình dựng môi trường staging để test thực tế 3 giải pháp:

  • Phương án 1: Rsync + Snapshot trên ZFS/Btrfs (phía NAS). Tốc độ chụp snapshot nhanh. Điểm trừ là máy chủ NAS phải format lại ổ cứng, ngốn thêm RAM để chạy ZFS pool và không xử lý được khâu mã hóa từ máy khách CentOS Stream 9.
  • Phương án 2: Restic. Công cụ viết bằng Go, hỗ trợ cloud backend rất tốt. Tuy nhiên, khi repo vượt ngưỡng 1.5TB trên testbed, các lệnh bảo trì như restic check và prune tiêu thụ tới hơn 3.2GB RAM, dễ chạm trần tài nguyên trên VPS nhỏ.
  • Phương án 3: BorgBackup (Borg). Borg băm nhỏ dữ liệu thành các chunk động (rolling hash). Repo chỉ lưu các chunk mới chưa từng xuất hiện. Ngoài ra, Borg hỗ trợ nén Zstandard (zstd) tốc độ cao, mã hóa AES-256 ngay trên client và cho phép mount điểm backup thành thư mục qua FUSE.

Quy trình cài đặt và chuẩn hóa BorgBackup trên CentOS Stream 9

BorgBackup đáp ứng trọn vẹn cả 3 tiêu chí: tiết kiệm dung lượng, tốc độ cao và dùng ít RAM. Dưới đây là các bước mình đã áp dụng cho môi trường production.

Bước 1: Cài đặt BorgBackup và FUSE từ EPEL

Gói cài đặt có sẵn trên kho EPEL (Extra Packages for Enterprise Linux). Bạn cài đồng thời Borg và module FUSE để phục vụ việc mount file sau này:

# Bật EPEL và cài đặt Borg cùng FUSE
sudo dnf install -y epel-release
sudo dnf install -y borgbackup fuse

Kiểm tra phiên bản sau khi cài:

borg --version
# Kết quả mẫu: borg 1.2.8

Bước 2: Khởi tạo Repository và lưu trữ Repokey an toàn

Ở ví dụ này, thư mục backup nằm tại /mnt/backup-storage/borg-repo (đã mount qua NFS từ NAS). Chế độ mã hóa khuyến nghị là repokey-blake2: key mã hóa nằm trong header repo và được bảo vệ bằng passphrase.

# Tạo thư mục chứa repo
sudo mkdir -p /mnt/backup-storage/borg-repo

# Khởi tạo repository
sudo borg init --encryption=repokey-blake2 /mnt/backup-storage/borg-repo

Hệ thống sẽ yêu cầu nhập passphrase. Bạn hãy đặt mật khẩu phức tạp và lưu vào password manager. Mất passphrase đồng nghĩa với mất toàn bộ dữ liệu. Kế tiếp, export key dự phòng ra file an toàn:

# Xuất key dự phòng ra file text và cất ở nơi biệt lập
sudo borg key export /mnt/backup-storage/borg-repo /root/borg-backup-repo.key

Bước 3: Chạy bản backup đầu tiên với thuật toán nén ZSTD

Mục tiêu cần backup gồm mã nguồn web /var/www và thư mục dump SQL /var/backups/db. Thuật toán zstd,3 đem lại tỷ lệ nén tương đương gzip level 6 nhưng tốc độ nhanh hơn gần 3 lần:

# Khai báo passphrase tạm thời cho phiên làm việc
export BORG_PASSPHRASE='MatKhauBaoMatCuaBan123@'

# Tạo archive đầu tiên
sudo -E borg create --stats --progress --compression zstd,3 \
    /mnt/backup-storage/borg-repo::'{now:%Y-%m-%d_%H:%M}' \
    /var/www \
    /var/backups/db \
    --exclude '*.log' \
    --exclude '/var/www/*/cache'

Khi lệnh hoàn tất, màn hình sẽ hiển thị bảng thống kê dung lượng. Đến ngày thứ hai, bạn sẽ thấy cột Deduplicated size giảm rõ rệt. Lượng dữ liệu ghi thực tế vào ổ cứng thường chỉ còn vài trăm megabyte thay vì vài chục gigabyte.

Bước 4: Tự động hóa với Shell Script và Systemd Timer

Thay vì đặt cron job đơn giản, bạn nên tạo script gom cả 3 khâu: tạo archive, tỉa bản cũ (prune) và giải phóng dung lượng rác (compact). Tạo file /usr/local/bin/borg-backup.sh:

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

export BORG_REPO="/mnt/backup-storage/borg-repo"
export BORG_PASSPHRASE="MatKhauBaoMatCuaBan123@"

ARCHIVE_NAME="$(hostname)-$(date +%Y-%m-%d_%H%M%S)"

echo "[$(date)] Bắt đầu tiến trình sao lưu Borg..."

# 1. Tạo archive mới
borg create --stats --compression zstd,3 \
    ::"$ARCHIVE_NAME" \
    /var/www \
    /etc \
    /var/backups/db \
    --exclude '*/cache' \
    --exclude '*/tmp'

echo "[$(date)] Hoàn tất archive. Bắt đầu dọn dẹp bản sao lưu cũ..."

# 2. Xóa archive cũ: giữ 7 ngày gần nhất, 4 tuần, 6 tháng
borg prune -v --list \
    --keep-daily=7 \
    --keep-weekly=4 \
    --keep-monthly=6

# 3. Thu hồi dung lượng đĩa trống sau khi xóa metadata
borg compact

echo "[$(date)] Toàn bộ quy trình sao lưu kết thúc thành công!"

Phân quyền nghiêm ngặt để chỉ tài khoản root đọc và thực thi script:

sudo chmod 700 /usr/local/bin/borg-backup.sh

Trên CentOS Stream 9, Systemd Timer thay thế cron rất hiệu quả nhờ khả năng kiểm soát I/O priority và gom log tập trung qua journalctl.

Tạo file service /etc/systemd/system/borg-backup.service:

[Unit]
Description=BorgBackup Daily Service
After=network.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/borg-backup.sh
Nice=19
IOSchedulingClass=best-effort
IOSchedulingPriority=7

Tạo file timer /etc/systemd/system/borg-backup.timer để kích hoạt lúc 02:30 sáng:

[Unit]
Description=Trigger BorgBackup daily at 02:30 AM

[Timer]
OnCalendar=*-*-* 02:30:00
Persistent=true

[Install]
WantedBy=timers.target

Nạp cấu hình và kích hoạt timer:

sudo systemctl daemon-reload
sudo systemctl enable --now borg-backup.timer

# Kiểm tra mốc thời gian chạy tiếp theo
sudo systemctl list-timers borg-backup.timer

Bước 5: Khôi phục và kiểm tra dữ liệu

Backup không test khôi phục cũng như chưa backup. Với Borg, bạn có hai cách lấy lại file linh hoạt tùy tình huống:

Cách 1: Trích xuất trực tiếp toàn bộ archive

export BORG_PASSPHRASE="MatKhauBaoMatCuaBan123@"

# Xem danh sách archive trong repo
sudo -E borg list /mnt/backup-storage/borg-repo

# Bung dữ liệu của một bản backup cụ thể vào thư mục restore tạm
mkdir -p /tmp/restore && cd /tmp/restore
sudo -E borg extract /mnt/backup-storage/borg-repo::centos9-prod-2026-10-20_023000

Cách 2: Mount repo thành thư mục để lấy file lẻ

Khi lập trình viên chỉ cần lấy lại 1 file config hoặc 1 bảng SQL cũ, bạn không cần xả toàn bộ archive dung lượng lớn. Chỉ cần mount repo qua FUSE rồi mở file bằng lệnh thông thường:

sudo mkdir -p /mnt/borg-mount

# Mount repo dạng read-only
sudo -E borg mount /mnt/backup-storage/borg-repo /mnt/borg-mount

# Duyệt file như một phân vùng đĩa thông thường
ls -la /mnt/borg-mount
cp /mnt/borg-mount/centos9-prod-2026-10-20_023000/var/www/html/app/config.php /tmp/

# Xem xong, unmount thư mục
sudo umount /mnt/borg-mount

Kết quả sau 6 tháng vận hành production

Các chỉ số đo lường thực tế trên cụm máy chủ CentOS Stream 9 đã chứng minh hiệu quả rõ rệt:

  • Dung lượng lưu trữ: Bộ backup 14 ngày trước đây ngốn xấp xỉ 1.8TB trên NAS. Hiện tại, Borg repo gom toàn bộ dữ liệu này vào đúng 310GB đĩa cứng, tiết kiệm gần 83% không gian.
  • Thời gian chạy: Tổng thời gian sao lưu mỗi đêm giảm từ 3 tiếng 20 phút xuống còn 6 đến 8 phút. Hầu hết các chunk cũ không cần đọc lại hay gửi qua mạng.
  • Tải hệ thống: Nhờ thiết lập Nice=19 và I/O class thấp, máy chủ hoàn toàn không ghi nhận hiện tượng giật lag truy vấn người dùng lúc 02:30 sáng.
Share: