Đầu năm nay, cụm storage media nội bộ bên mình chạm ngưỡng quá tải. Mỗi ngày nhân viên đẩy lên tầm 120.000 file ảnh và PDF, tương đương hơn 300GB dữ liệu mới. Bài toán đặt ra khá gắt: phải nhân bản tức thì toàn bộ file từ node chính sang node phụ để làm backup nóng và chia tải đọc cho nginx.
Dựng Ceph hay GlusterFS lúc này như dùng dao mổ trâu giết gà. Hệ thống chỉ có 2 node, dựng cụm phân tán vừa cồng kềnh vừa tốn RAM duy trì heartbeat. Sau khi cân nhắc, team mình chọn combo kinh điển: Lsyncd + Rsync trên CentOS Stream 9. Sau hơn 6 tháng chạy thực tế trên production, cụm này nuốt chưa tới 40MB RAM và gần như zero-maintenance.
Quick start: Dựng xong trong 5 phút
Mô hình triển khai gồm 2 server trong cùng dải mạng nội bộ 10Gbps:
- Source Server (Node nguồn):
192.168.1.10 - Target Server (Node đích):
192.168.1.20 - Thư mục đồng bộ:
/var/www/uploads/
Bước 1: Thiết lập SSH Key không mật khẩu
Lsyncd chạy ngầm dưới quyền root và gọi Rsync qua SSH. Do đó, Source cần quyền SSH thẳng vào Target mà không bị chặn hỏi mật khẩu.
Đứng trên Source Server, tạo key Ed25519 rồi đẩy sang Target:
ssh-keygen -t ed25519 -N "" -f ~/.ssh/id_ed25519
ssh-copy-id -i ~/.ssh/id_ed25519.pub [email protected]
Test lại bằng lệnh ssh [email protected]. Nếu vào thẳng shell đích mà không cần gõ mật khẩu là xong bước đầu.
Bước 2: Cài đặt Rsync và Lsyncd
Rsync cần có trên cả 2 node. Riêng Lsyncd chỉ cài trên Source. Trên CentOS Stream 9, gói này nằm sẵn trong repo EPEL.
Chạy lệnh này trên cả 2 server:
sudo dnf install -y epel-release
sudo dnf install -y rsync
Cài tiếp Lsyncd trên Source Server:
sudo dnf install -y lsyncd
Bước 3: Viết file cấu hình Lsyncd
Cấu hình của Lsyncd viết bằng cú pháp Lua. Lưu file gốc để dự phòng và tạo file mới tại /etc/lsyncd.conf:
sudo cp /etc/lsyncd.conf /etc/lsyncd.conf.bak
sudo nano /etc/lsyncd.conf
Nội dung cấu hình chuẩn cho mạng LAN:
settings {
logfile = "/var/log/lsyncd/lsyncd.log",
statusFile = "/var/log/lsyncd/lsyncd.status",
statusInterval = 10,
maxProcesses = 2
}
sync {
default.rsyncssh,
source = "/var/www/uploads",
host = "[email protected]",
targetdir = "/var/www/uploads",
delay = 3,
rsync = {
archive = true,
compress = false,
_extra = { "--bwlimit=60000" }
}
}
Bước 4: Khởi động và kiểm tra
Tạo trước thư mục /var/www/uploads trên cả 2 máy nếu chưa có. Bật service trên Source:
sudo systemctl enable --now lsyncd
sudo systemctl status lsyncd
Thử tạo nhanh một file test: touch /var/www/uploads/demo-sync.txt. Qua node Target kiểm tra thư mục uploads, file sẽ xuất hiện sau khoảng 3 đến 5 giây.
Bản chất: Lsyncd hoạt động như thế nào?
Nhiều người thường tự hỏi: tại sao không chạy cronjob rsync mỗi phút một lần?
Vấn đề nằm ở disk I/O. Khi thư mục phình lên 800.000 file, mỗi lần rsync chạy, nó phải duyệt toàn bộ cây thư mục để so sánh timestamp và kích thước. Đĩa cứng sẽ bị nghẽn I/O liên tục, CPU nhảy vọt dù thực tế chỉ có 2 file mới được tạo.
Lsyncd giải quyết triệt để bài toán này bằng cách kết hợp hai lớp xử lý:
- Linux inotify: Lsyncd lắng nghe trực tiếp các sự kiện từ nhân Linux (create, write, delete, move). Kernel báo thẳng file nào vừa đổi. Hệ thống không cần quét đĩa.
- Cơ chế gom batch (Aggregator): Lsyncd không gọi rsync ngay lập tức khi vừa có event. Nó gom toàn bộ thay đổi trong cửa sổ trễ (ở trên ta set
delay = 3giây). Hết 3 giây, nó gom danh sách file biến động và gọi rsync đẩy đúng cụm file đó một lần duy nhất.
Ý nghĩa các thông số then chốt
- default.rsyncssh: Lsyncd tận dụng SSH để push file. Cách này an toàn, không cần mở thêm port dịch vụ ra ngoài.
- delay = 3: Thời gian chờ gom sự kiện. Đừng đặt giá trị này bằng 0. Nếu user đang upload file video 500MB, đặt delay = 0 sẽ khiến rsync kích hoạt ngắt quãng liên tục khi file chưa ghi xong, gây lãng phí tài nguyên và dễ lỗi file.
- compress = false: Với mạng LAN nội bộ 1Gbps trở lên, hãy tắt nén gzip. CPU không phải tốn chu kỳ nén giải nén, tốc độ truyền thực tế sẽ nhanh hơn đáng kể. Chỉ bật nén khi sync qua Internet với đường truyền hẹp dưới 50Mbps.
- –bwlimit=60000: Giới hạn băng thông ở mức xấp xỉ 60MB/s (đơn vị của rsync là KiB/s). Flag này giúp tránh tình trạng rsync kéo sập băng thông LAN của các dịch vụ database lân cận.
Tối ưu production cho hệ thống file lớn
Cấu hình mặc định của Linux chỉ phù hợp cho môi trường dev. Khi số lượng file vượt mốc vài trăm ngàn, hệ thống sẽ gặp sự cố nếu không tinh chỉnh kernel.
1. Tăng giới hạn theo dõi của inotify
Mặc định CentOS Stream 9 chỉ cấp 8.192 watch descriptor cho inotify. Một khi tổng số folder vượt mốc này, Lsyncd lập tức crash kèm lỗi kinh điển: No space left on device, dù ổ cứng vẫn còn hàng trăm GB trống.
Kiểm tra giới hạn hiện tại:
cat /proc/sys/fs/inotify/max_user_watches
Nâng giới hạn lên 1 triệu thư mục bằng file cấu hình sysctl:
cat << 'EOF' | sudo tee /etc/sysctl.d/99-lsyncd.conf
fs.inotify.max_user_watches = 1048576
fs.inotify.max_user_instances = 1024
fs.inotify.max_queued_events = 32768
EOF
sudo sysctl --system
Mỗi watch tiêu tốn khoảng 1KB bộ nhớ nhân kernel trên hệ thống 64-bit. Theo dõi 1 triệu folder chỉ ngốn khoảng 1GB RAM ở mức kịch khung, đổi lại hệ thống chạy an toàn tuyệt đối.
2. Chuyển sang Rsync Daemon khi cần hiệu năng cao
Đồng bộ qua SSH an toàn nhưng tốn CPU cho quá trình mã hóa SSH. Nếu hai node nằm trọn trong private subnet tin cậy và cần sync hàng chục nghìn file nhỏ mỗi giờ, chạy rsync daemon trực tiếp qua port 873 sẽ giúp giảm tải CPU khoảng 35-40%.
Trên Target Server, sửa /etc/rsyncd.conf:
pid file = /var/run/rsyncd.pid
lock file = /var/run/rsync.lock
log file = /var/log/rsync.log
[media_mirror]
path = /var/www/uploads
hosts allow = 192.168.1.10
read only = false
uid = nginx
gid = nginx
Mở port trên firewalld và khởi chạy rsync daemon:
sudo firewall-cmd --permanent --add-service=rsyncd
sudo firewall-cmd --reload
sudo systemctl enable --now rsyncd
Trên Source Server, tinh chỉnh block sync trong /etc/lsyncd.conf:
sync {
default.rsync,
source = "/var/www/uploads",
target = "192.168.1.20::media_mirror",
delay = 3,
rsync = {
archive = true,
compress = false
}
}
3. Loại bỏ file rác và log tạm
Không nên tốn I/O cho file log hoặc file tạm do editor sinh ra. Thêm bộ lọc exclude vào cấu hình:
sync {
default.rsyncssh,
source = "/var/www/uploads",
host = "[email protected]",
targetdir = "/var/www/uploads",
exclude = {
'*.tmp',
'*.swp',
'.git*',
'cache/**'
}
}
Kinh nghiệm xương máu khi vận hành
Hệ thống chạy mượt trên lab không có nghĩa sẽ bình yên trên production. Đây là ba bài học thực tế bên mình đã trả giá bằng downtime:
Cực kỳ thận trọng với tham số delete
Theo mặc định, default.rsyncssh bật sẵn cơ chế mirror xóa file. Nghĩa là file bị xóa ở Source thì node Target cũng tự động xóa theo.
Điều này biến backup nóng thành con dao hai lưỡi. Một lệnh rm -rf gõ nhầm trên Source sẽ quét sạch dữ liệu ở Target chỉ sau 3 giây. Nếu mục đích chính là sao lưu dự phòng an toàn, hãy tắt hẳn tính năng xóa tự động:
delete = false
Nếu vẫn cần dọn dẹp file thừa để tiết kiệm đĩa, giải pháp an toàn hơn là đặt delete = 'running'. Tham số này đảm bảo Lsyncd chỉ xóa file ở node đích sau khi đã hoàn tất toàn bộ tiến trình sync các file mới, tránh mất dữ liệu giữa chừng khi mạng chập chờn.
Lsyncd chỉ là giải pháp một chiều (Master – Slave)
Không bao giờ cấu hình sync chéo hai chiều (A đẩy sang B đồng thời B đẩy ngược lại A). Lsyncd không có cơ chế giải quyết xung đột (conflict resolution). Khi hai file cùng sửa một lúc, hai node sẽ bắn event liên tục tạo thành vòng lặp race condition vô tận. Hậu quả là CPU chạm đỉnh 100%, log phình hàng chục GB và crash service. Nếu nghiệp vụ bắt buộc ghi dữ liệu từ cả hai đầu, hãy chuyển sang dùng GlusterFS, MooseFS hoặc MinIO Object Storage.
Tự động hồi sinh khi bị Kernel OOM Kill
Khi các app nặng như PHP-FPM hay Elasticsearch trên server ngốn sạch RAM, Linux OOM Killer có thể chọn lsyncd làm con mồi để giải phóng bộ nhớ. Để dịch vụ không bị chết im lặng, tạo file override cho systemd:
sudo systemctl edit lsyncd
Nhập nội dung sau để systemd tự restart tiến trình sau 5 giây:
[Service]
Restart=always
RestartSec=5s
Để theo dõi sức khỏe đồng bộ, chỉ cần đọc file status:
cat /var/log/lsyncd/lsyncd.status
Nếu Inotify watches tương ứng với số lượng folder thực tế và Delay queues thường xuyên về 0, hệ thống của bạn đang chạy rất ổn định.
