Vấn đề thực tế khi sao lưu và đồng bộ file
Mình từng dùng cp -r để backup thư mục web mỗi đêm. Nghe có vẻ ổn, nhưng sau vài tuần thì nhận ra vấn đề: cứ mỗi lần backup là copy toàn bộ vài GB dữ liệu, dù chỉ có vài chục file thay đổi. Kết quả là cron job chạy 30-40 phút, I/O disk tăng vọt, server ì ạch vào đúng giờ cao điểm.
Vấn đề nằm ở chỗ cp không phân biệt được file nào đã thay đổi — nó copy tất cả mà không cần biết. rsync ra đời đúng để giải quyết chuyện này.
rsync (Remote Sync) hoạt động theo nguyên tắc delta transfer — chỉ truyền phần dữ liệu thực sự thay đổi giữa nguồn và đích. Trên server production Ubuntu 22.04 với 4GB RAM mình đang quản lý, sau khi chuyển sang rsync, thời gian backup giảm từ 35 phút xuống còn 2-3 phút cho cùng lượng dữ liệu.
rsync đã có sẵn chưa? Kiểm tra trước khi cài
Thật ra bạn có thể không cần cài gì cả. Hầu hết distro Linux hiện đại đều đã có rsync sẵn — kiểm tra nhanh:
rsync --version
Ra output dạng rsync version 3.2.x thì dùng luôn, không cần cài thêm. Chưa có thì:
# Ubuntu / Debian
sudo apt install rsync
# RHEL / AlmaLinux / Rocky
sudo dnf install rsync
# Arch Linux
sudo pacman -S rsync
Với đồng bộ remote qua SSH, máy đích cũng cần có rsync. Kiểm tra luôn:
ssh user@remote-server "rsync --version"
Cú pháp cơ bản và các flag quan trọng
Cú pháp nhìn đơn giản:
rsync [options] source destination
Nhưng phần quan trọng là biết chọn flag nào. Đây là bộ mình hay dùng nhất, kèm giải thích thực tế:
-a— archive mode: giữ nguyên permission, owner, timestamp, symlink, recursive-v— verbose: hiển thị file đang được sync-z— nén dữ liệu khi truyền qua network (hữu ích với kết nối chậm)-P— hiển thị progress bar + resume nếu bị gián đoạn--delete— xóa file ở đích nếu ở nguồn không còn nữa--dry-runhoặc-n— chạy thử, không thực sự thay đổi gì--exclude— bỏ qua file/thư mục theo pattern
Các trường hợp dùng thực tế
1. Đồng bộ thư mục local sang local
Trường hợp đơn giản nhất — sao lưu từ ổ này sang ổ khác trên cùng máy:
# Sync thư mục /var/www/html sang /mnt/backup/www
rsync -av /var/www/html/ /mnt/backup/www/
# Lưu ý dấu / ở cuối source:
# /var/www/html/ → copy NỘI DUNG bên trong thư mục
# /var/www/html → copy CẢ thư mục html vào đích
Dấu / ở cuối đường dẫn nguồn là chỗ hay nhầm nhất khi mới dùng rsync. Cứ chạy --dry-run lần đầu cho chắc:
rsync -av --dry-run /var/www/html/ /mnt/backup/www/
2. Đồng bộ lên remote server qua SSH
Use case mình dùng nhiều nhất — đẩy backup lên server khác:
# Push từ local lên remote
rsync -avz -P /var/www/html/ [email protected]:/backup/www/
# Pull từ remote về local
rsync -avz -P [email protected]:/var/www/html/ /local/backup/www/
# Chỉ định SSH key và port khác
rsync -avz -e "ssh -i ~/.ssh/id_rsa -p 2222" \
/var/www/html/ user@remote:/backup/www/
3. Đồng bộ có xóa file cũ (mirror)
Khi muốn đích giống hệt nguồn — file nào xóa ở nguồn thì cũng xóa ở đích:
rsync -av --delete /var/www/html/ /mnt/backup/www/
Cẩn thận với --delete: nếu chạy nhầm chiều (source và destination bị đổi chỗ), sẽ xóa dữ liệu gốc. Luôn test với --dry-run trước.
4. Loại trừ file/thư mục không cần sync
# Bỏ qua thư mục cache, log, temp
rsync -av \
--exclude='cache/' \
--exclude='*.log' \
--exclude='.git/' \
--exclude='node_modules/' \
/var/www/myapp/ user@remote:/backup/myapp/
# Dùng file exclude list (tiện hơn khi có nhiều pattern)
cat > /etc/rsync-exclude.txt << 'EOF'
cache/
*.log
*.tmp
.git/
node_modules/
EOF
rsync -av --exclude-from='/etc/rsync-exclude.txt' \
/var/www/myapp/ user@remote:/backup/myapp/
5. Backup tự động với cron
Để rsync chạy tự động, SSH không được hỏi password. Dùng SSH key là cách đơn giản nhất:
# Tạo SSH key không passphrase cho backup user
ssh-keygen -t ed25519 -f ~/.ssh/backup_key -N ""
# Copy public key lên remote
ssh-copy-id -i ~/.ssh/backup_key.pub user@remote-server
Sau đó tạo script backup:
cat > /usr/local/bin/backup-web.sh << 'EOF'
#!/bin/bash
LOG_FILE="/var/log/rsync-backup.log"
DATE=$(date '+%Y-%m-%d %H:%M:%S')
echo "[$DATE] Starting backup..." >> "$LOG_FILE"
rsync -az --delete \
-e "ssh -i /root/.ssh/backup_key -o StrictHostKeyChecking=no" \
--exclude-from='/etc/rsync-exclude.txt' \
/var/www/html/ \
[email protected]:/backup/www/ \
>> "$LOG_FILE" 2>&1
EXIT_CODE=$?
if [ $EXIT_CODE -eq 0 ]; then
echo "[$DATE] Backup completed successfully" >> "$LOG_FILE"
else
echo "[$DATE] Backup FAILED with exit code $EXIT_CODE" >> "$LOG_FILE"
fi
EOF
chmod +x /usr/local/bin/backup-web.sh
Thêm vào crontab để chạy hàng đêm lúc 2 giờ sáng:
crontab -e
# Thêm dòng sau:
0 2 * * * /usr/local/bin/backup-web.sh
Làm sao biết backup có chạy đúng không?
Exit code — đừng bỏ qua
Sau mỗi lần chạy, rsync trả về exit code. Con số 0 là ổn, khác 0 là có vấn đề:
0— thành công1— lỗi cú pháp11— lỗi I/O đọc/ghi file23— transfer một phần bị lỗi (thường do permission)30— timeout kết nối
Script backup ở trên đã bắt exit code rồi. Kiểm tra nhanh khi chạy tay:
rsync -av /source/ /destination/
echo "Exit code: $?"
So sánh source và destination
Muốn chắc chắn hai thư mục đã giống nhau chưa? Chạy lại rsync với --dry-run — không có output nghĩa là đồng bộ hoàn toàn:
rsync -av --dry-run /source/ /destination/
# Không có dòng nào được liệt kê → hai thư mục giống nhau
Theo dõi log
# Xem log backup realtime
tail -f /var/log/rsync-backup.log
# Xem 50 dòng cuối
tail -n 50 /var/log/rsync-backup.log
# Lọc xem chỉ các lần backup thất bại
grep "FAILED" /var/log/rsync-backup.log
Đo tốc độ và hiệu quả
Thêm --stats vào là có ngay bảng thống kê sau khi chạy — số liệu thực tế thường bất ngờ lắm:
rsync -av --stats /var/www/html/ /mnt/backup/www/
# Output mẫu:
# Number of files: 1,234
# Number of created files: 5
# Number of deleted files: 2
# Number of regular files transferred: 12
# Total file size: 2.45G bytes
# Total transferred file size: 4.23M bytes ← chỉ 4MB thay vì 2.45GB!
# Speedup is 593.93
Dòng "Speedup" nói lên tất cả. Con số 593 nghĩa là rsync chỉ truyền 1/593 lượng dữ liệu so với copy toàn bộ — tức khoảng 0.17% dữ liệu thực sự đi qua mạng.
Lỗi hay gặp và cách xử lý
Permission denied: File ở đích có permission khác với user đang chạy rsync. Chạy với sudo hoặc điều chỉnh ownership thư mục đích.
"skipping non-regular file": rsync gặp socket file hoặc device file không copy được. Thêm --exclude="*.sock" là xong.
Tốc độ chậm trên network yếu: Bật -z để nén. Nhưng với file đã nén sẵn như jpg, mp4, zip — nén lại không giúp được gì, bỏ -z đi còn nhanh hơn.
Dùng rsync ổn rồi thì bước tiếp theo đáng khám phá: --backup để giữ lại bản cũ trước khi ghi đè, hoặc kết hợp hardlink để làm incremental backup — nhiều snapshot lịch sử mà không tốn thêm disk space đáng kể.

