ZFS trên FreeBSD và Linux: RAM đổi lấy gì?
ZFS có checksum, snapshot, send/receive và compression, nhưng ARC ăn RAM. Xem cách cân nhắc trên VPS 2 GB hoặc 4 GB trước khi tạo pool.
ZFS cung cấp gì và yêu cầu những gì
ZFS trên FreeBSD và Linux hiện dùng chung một codebase là OpenZFS, nên các tính năng trên hai hệ thống giống nhau. Server chạy ZFS có dữ liệu kèm checksum, snapshot không tốn dung lượng cho đến khi dữ liệu thay đổi, replication bằng zfs send và compression chỉ cần bật một property. Đổi lại, ZFS cần memory: ARC (adaptive replacement cache) mặc định chiếm một phần lớn RAM. Trên VPS (virtual private server) 2 GB hoặc 4 GB, phần memory đó chính là tài nguyên mà ứng dụng của bạn cần.
Hướng dẫn này đánh giá ZFS trên một VPS thuê có một hoặc hai virtual disk, không phải trên storage box có 40 drive bay. Những tính năng vẫn hữu ích trong môi trường đó là những tính năng đáng để bạn sử dụng. Bạn nên biết trước những phần không phù hợp trước khi tạo pool.
OpenZFS trên FreeBSD và Linux: một codebase, hai cách đóng gói
FreeBSD đã tích hợp ZFS trong base system từ FreeBSD 7.0 vào năm 2008, ban đầu dưới dạng tính năng thử nghiệm. Từ OpenZFS 2.0 vào tháng 12 năm 2020, FreeBSD và Linux đều build từ cùng một source tree. Vì vậy, zfs và zpool hoạt động giống nhau trên cả hai hệ điều hành, đồng thời pool được tạo trên hệ này có thể import trên hệ kia.
Lý do ZFS là một package trên Linux nhưng là một phần của base system trên FreeBSD nằm ở vấn đề license. OpenZFS sử dụng CDDL (common development and distribution license). Linux kernel sử dụng GPL (general public license) version 2. Dự án kernel xem hai license này là không tương thích. Vì vậy, code ZFS không được merge vào mainline Linux, và mỗi distribution tự quyết định cách ship nó. FreeBSD không gặp xung đột này, nên ZFS có sẵn trong hệ thống. Về mặt thực tế, toàn bộ câu chuyện chỉ là một khác biệt trong cách đóng gói; bạn không cần phải chọn bên nào.
SSD Nodes không cung cấp image FreeBSD. Vì vậy, trên server thuê tại đây, phần Linux của hướng dẫn này là phần áp dụng được. Nếu bạn chạy FreeBSD ở nơi khác, một server FreeBSD sẽ có ZFS mà không cần build module và không phải xử lý việc nâng cấp kernel.
Cài đặt ZFS và tạo pool
Trên Ubuntu, module đã có sẵn trong các package kernel, nên bạn chỉ cần cài các command.
sudo apt update
sudo apt install -y zfsutils-linux
zfs versionzfs version in ra 2 dòng: version của userland và version của kernel module. Nếu chỉ có 1 dòng thì module chưa được load. Package nằm trong component universe. Ubuntu server image mặc định đã enable component này. Nếu apt không tìm thấy package, trước hết chạy sudo add-apt-repository universe.
Trên Debian, các package nằm trong component contrib. DKMS (dynamic kernel module support) sẽ build module trên máy của bạn. Thêm contrib vào dòng Components: trong /etc/apt/sources.list.d/debian.sources, chạy sudo apt update, rồi chạy:
sudo apt install -y linux-headers-$(dpkg --print-architecture) zfs-dkms zfsutils-linuxQuá trình cài đặt sẽ compile module và in ra Building initial module for 6.12.0-.... Việc này có thể mất vài phút. Điều đó có nghĩa là mỗi lần upgrade kernel, module sẽ được build lại. Nếu build fail, pool sẽ không được import cho đến khi bạn sửa lỗi.
Trên FreeBSD không cần cài gì. Enable service rồi start service.
sysrc zfs_enable=YES
service zfs startBây giờ tạo pool. Trước tiên hãy kiểm tra các device path ổn định, vì /dev/vdb được cấp theo thứ tự phát hiện device và có thể thay đổi khi bạn attach thêm volume.
ls -l /dev/disk/by-id/
sudo zpool create -o ashift=12 tank /dev/disk/by-id/virtio-abc123def456
zpool status tankzpool status phải in ra state: ONLINE và device của bạn phải nằm dưới tank. ashift=12 đặt block nhỏ nhất của pool là 4 KiB. Giá trị này phù hợp với các SSD hiện nay và không thể thay đổi sau khi tạo pool.
Hầu hết image cho thuê boot từ root filesystem ext4. Vì vậy, trong trường hợp này ZFS là data pool trên volume thứ 2, không phải root filesystem. Hãy kiểm tra device đúng với dự kiến trước khi sử dụng, vì xác nhận disk NVMe bạn đã thuê chỉ mất 1 phút, còn rebuild có thể mất cả buổi chiều.
Checksum chỉ sửa được lỗi khi pool có dự phòng
Mỗi block ZFS ghi đều có checksum, và mỗi lần đọc đều được kiểm tra. Việc phát hiện lỗi luôn hoạt động. Việc sửa lỗi cần có bản sao thứ hai.
Trên pool chỉ có một disk, ZFS cho bạn biết sự thật rồi dừng ở đó. zpool status -v báo lỗi như sau:
status: One or more devices has experienced an error resulting in data
corruption.
action: Restore the file in question if possible. Otherwise restore the
entire pool from backup.
errors: Permanent errors have been detected in the following files:
/tank/data/archive.tarZFS chỉ ra tên file bị lỗi. ext4 sẽ trả về các byte đó mà không thông báo gì, nên riêng việc phát hiện này đã có giá trị. ZFS vẫn không thể sửa file vì pool không có bản sao thứ hai để khôi phục.
Với mirror, lần đọc đó sẽ lấy dữ liệu từ phía còn tốt, ghi lại block bị lỗi, và sự kiện xuất hiện trong cột CKSUM của zpool status. Đây là cơ chế tự sửa lỗi và cần 2 thiết bị.
sudo zpool create -o ashift=12 tank mirror /dev/disk/by-id/DISK1 /dev/disk/by-id/DISK2Trên VPS, storage của host thường đã có redundancy, thường là RAID 10 bên dưới hypervisor. Cơ chế này bảo vệ bạn khi một drive bị hỏng. Nó không cho biết khi nào một block trả về dữ liệu sai, vì array không có cách xác định bản sao nào là đúng. ZFS biết điều đó vì nó đối chiếu dữ liệu với checksum do chính nó ghi.
Nếu bạn có một virtual disk và muốn có khả năng sửa lỗi nhất định, sudo zfs set copies=2 tank/important sẽ lưu 2 bản sao của mỗi block trong dataset đó trên cùng một disk. Cách này làm tăng gấp đôi dung lượng dataset sử dụng, vẫn xử lý được khi một block bị lỗi, nhưng không có tác dụng khi toàn bộ volume biến mất.
Scrub đọc toàn bộ dữ liệu trong pool và kiểm tra dữ liệu.
sudo zpool scrub tank
zpool status tankPool khỏe mạnh sẽ kết thúc bằng một dòng như scan: scrub repaired 0B in 00:04:11 with 0 errors. Hãy lập lịch chạy scrub; với pool nhỏ, chạy mỗi tháng là đủ.
systemctl list-unit-files 'zfs-scrub*'
sudo systemctl enable --now zfs-scrub-monthly@tank.timerDataset là đơn vị áp dụng policy
Dataset là một filesystem bên trong pool. Việc tạo dataset không tốn nhiều tài nguyên, vì vậy hãy tạo một dataset cho mỗi job. Các property được kế thừa từ pool xuống dưới. Bạn chỉ cần đặt giá trị mặc định một lần, rồi override tại nơi cần thiết. Trên FreeBSD, jail thường được vận hành theo cách này: mỗi jail dùng một dataset riêng để có thể snapshot và rollback độc lập. Đây cũng là một phần của điểm khác biệt giữa jail và Docker container.
sudo zfs create tank/data
sudo zfs create tank/pg
sudo zfs set compression=lz4 tank
sudo zfs set atime=off tank
sudo zfs set quota=20G tank/data
sudo zfs set recordsize=16K tank/pg
zfs get -r compression,compressratio,quota tankCompression là property mà nhiều người không bật vì thận trọng, nhưng cách nghĩ đó là ngược. lz4 chỉ tốn một lượng nhỏ CPU và giảm số byte phải ghi xuống disk. Vì vậy, với dữ liệu có thể nén, compression thường giúp thao tác đọc và ghi nhanh hơn. zstd nén mạnh hơn nhưng tốn nhiều CPU hơn, phù hợp với log và archive mà bạn hiếm khi đọc lại. Dùng zfs get compressratio tank để kiểm tra kết quả thực tế, và nhớ rằng ratio chỉ tính dữ liệu được ghi sau khi property được đặt.
recordsize là block lớn nhất mà một dataset ghi, mặc định là 128K. Database ghi các page 8 KiB vào các record 128 KiB sẽ biến một lần ghi nhỏ thành thao tác đọc toàn bộ record, thay đổi dữ liệu rồi ghi lại. Hãy đặt recordsize=16K trên dataset của database trước khi load dữ liệu, vì property này chỉ áp dụng cho các block được ghi mới.
quota là cách ngăn một dataset chiếm đầy pool. ZFS pool gần đầy 100% sẽ trở nên chậm và khó xử lý khi cần dọn dẹp, vì vậy hãy chủ động chừa lại dung lượng dự phòng.
Snapshot không tốn dung lượng cho đến khi dữ liệu thay đổi
ZFS không bao giờ ghi đè block đang được sử dụng. Nó ghi một block mới rồi cập nhật các pointer. Đây chính là cơ chế copy-on-write. Snapshot là một ghi chú yêu cầu giữ lại các block mà dataset đang trỏ tới tại thời điểm đó, nên việc tạo snapshot diễn ra tức thì và không tốn dung lượng.
sudo zfs snapshot tank/data@2026-08-11
zfs list -t snapshot -o name,used,refer -r tank/dataCột USED của snapshot là dung lượng chỉ snapshot đó đang giữ. Giá trị này ban đầu gần bằng 0 và tăng lên khi bạn thay đổi hoặc xóa dữ liệu, vì các block cũ không còn được giải phóng.
Lấy lại một file không cần bước restore.
ls /tank/data/.zfs/snapshot/
cp /tank/data/.zfs/snapshot/2026-08-11/notes.txt /tank/data/notes.txtThư mục .zfs bị ẩn, kể cả với ls -a, cho đến khi bạn chạy sudo zfs set snapdir=visible tank/data. Hãy tạo snapshot trước khi cần đến nó. Nếu không có snapshot, một lệnh rm -rf sơ suất sẽ đưa bạn vào quy trình khôi phục ext4, bắt đầu bằng việc unmount disk và sau đó còn phức tạp hơn.
Rollback sẽ hủy mọi dữ liệu được ghi kể từ snapshot đó.
sudo zfs rollback tank/data@2026-08-11Thao tác này sẽ bị từ chối khi có snapshot mới hơn. -r sẽ xóa các snapshot mới hơn để tiếp tục. Hãy kiểm tra lại tên dataset 2 lần trước khi nhấn Enter.
Snapshot không phải là backup. Nó nằm trong cùng pool, trên cùng volume và cùng server. Một volume bị lỗi hoặc một zpool destroy sẽ kéo theo cả snapshot cùng dữ liệu. Snapshot bảo vệ bạn khỏi rm của chính mình và khỏi một lần nâng cấp lỗi. Đây là những sự cố phổ biến trong thực tế. Nhưng snapshot không bảo vệ bạn trước bất kỳ sự cố nào xảy ra với chính pool. Phân tích đầy đủ có ở đây: vì sao snapshot của VPS không phải là backup.
Gửi và nhận: replication bằng một lệnh
zfs send chuyển một snapshot thành byte stream trên standard output, còn zfs receive chuyển byte stream đó trở lại thành dataset. Lần copy đầu tiên là full send.
sudo zfs snapshot tank/data@daily-2026-08-11
sudo zfs send tank/data@daily-2026-08-11 | ssh backup.example.com "sudo zfs recv -F backup/data"Sau đó, chỉ gửi phần thay đổi giữa hai snapshot.
sudo zfs snapshot tank/data@daily-2026-08-12
sudo zfs send -i tank/data@daily-2026-08-11 tank/data@daily-2026-08-12 | ssh backup.example.com "sudo zfs recv backup/data"Bên nhận vẫn phải có snapshot mà bạn đang gửi từ đó. Nếu không, quá trình receive sẽ dừng với cannot receive incremental stream: most recent snapshot of backup/data does not match incremental source vì ZFS không có bản cơ sở để áp dụng phần chênh lệch. Hãy gửi từ một snapshot mà cả hai bên đều có, hoặc bắt đầu lại bằng full send.
Cấp quyền trên target thay vì dùng remote root: sudo zfs allow -u backupuser create,mount,receive backup/data.
Đây là một bản backup off-site thực sự, với một điều kiện. Đầu xa phải là một ZFS pool vì object storage không thể nhận stream. Nếu target của bạn là storage tương thích S3 hoặc một Linux host thông thường, hãy dùng tool hỗ trợ giao thức đó; backup restic từ VPS mô tả cách này.
Vì sao ZFS dùng nhiều RAM? ARC
ARC (adaptive replacement cache) là read cache của ZFS. Nó nằm trong kernel memory thay vì Linux page cache thông thường, nên free -h không hiển thị ARC trong mục buff/cache. ARC được tính là memory đang được sử dụng. Một máy chạy ZFS trông gần như đã dùng hết RAM thường là do cache đã được làm nóng, và đây là nguyên nhân của phần lớn các báo cáo kiểu “ZFS ăn hết RAM”.
Giới hạn mặc định được đặt cao một cách có chủ ý. OpenZFS 2.3 đặt kích thước ARC tối đa bằng giá trị lớn hơn giữa RAM trừ 1 GiB và 5/8 RAM. OpenZFS 2.2 trở về trước dùng một nửa RAM trên Linux, trong khi FreeBSD đã dùng quy tắc mới. Chạy zfs version để xem hệ thống của bạn áp dụng quy tắc nào.
The data behind this chart
[
{
"label": "2 GB VPS",
"openzfs_2_2_linux_gib": 1,
"openzfs_2_3_gib": 1.25
},
{
"label": "4 GB VPS",
"openzfs_2_2_linux_gib": 2,
"openzfs_2_3_gib": 3
},
{
"label": "8 GB VPS",
"openzfs_2_2_linux_gib": 4,
"openzfs_2_3_gib": 7
},
{
"label": "16 GB VPS",
"openzfs_2_2_linux_gib": 8,
"openzfs_2_3_gib": 15
}
]Các số liệu này là quy tắc mặc định được ghi trong tài liệu, áp dụng cho những kích thước instance phổ biến, không phải số đo từ một máy đang chạy. Trên instance 4 GB, quy tắc của 2.3 cho phép ARC đạt 3 GiB. Cùng máy đó trên 2.2 chỉ được 2 GiB. Instance 2 GB theo quy tắc của 2.3 vẫn cho phép ARC đạt 1.25 GiB. Ứng dụng của bạn sẽ dùng phần RAM còn lại.
Hãy đọc số liệu thực tế trên chính server của bạn thay vì chỉ dựa vào bảng:
grep -E '^(size|c_max) ' /proc/spl/kstat/zfs/arcstats
arc_summary | head -n 20Cột thứ ba là số byte. c_max là giới hạn tối đa đang có hiệu lực, còn size là dung lượng ARC đang giữ.
ARC có trả lại memory. Kernel phát tín hiệu memory pressure và ARC sẽ thu nhỏ. Vấn đề nằm ở thời điểm, vì việc thu nhỏ chỉ được kích hoạt bởi memory pressure. Do đó, một process yêu cầu nhiều trăm MiB cùng lúc có thể gặp OOM (out of memory) killer trong khi ARC vẫn đang giải phóng memory. Trên một máy 2 GB chạy database và web server, đây không phải tình huống hiếm. Tài liệu OpenZFS cũng nói rõ điều tương tự về việc thay đổi thủ công: hạ giới hạn “sẽ không làm ARC thu nhỏ nếu không có memory pressure để kích hoạt việc thu nhỏ”.
Giới hạn ARC trên VPS nhỏ
Trước tiên, xác định lượng memory workload cần dùng. Cộng memory mà database và application cần, chừa lại một phần cho operating system, rồi cấp phần còn lại cho ARC. Với instance 4 GB chạy Postgres và một web application, bắt đầu với ARC từ 512 MiB đến 1 GiB là hợp lý.
Đặt giá trị khi hệ thống đang chạy, theo đơn vị byte. Giá trị dưới đây là 1 GiB.
echo 1073741824 | sudo tee /sys/module/zfs/parameters/zfs_arc_maxĐể thiết lập này vẫn còn hiệu lực sau khi reboot.
echo 'options zfs zfs_arc_max=1073741824' | sudo tee /etc/modprobe.d/zfs.conf
sudo update-initramfs -uBước initramfs rất quan trọng vì module có thể được load từ initramfs trước khi root filesystem được mount. Khi đó, module sẽ không đọc file mà bạn vừa ghi. Sau khi reboot, xác nhận bằng dòng c_max trong arcstats.
Có 2 lưu ý được nêu trong chính manual. Bạn không thể đặt giá trị về 0 khi hệ thống đang chạy, nên muốn hoàn tác thì phải sửa file rồi reboot. Ngoài ra, giảm giá trị không làm ARC lớn hiện tại giảm ngay lập tức.
Trên FreeBSD, giới hạn tương tự là một sysctl dưới vfs.zfs.arc. Chạy sysctl vfs.zfs.arc để xem các giá trị hiện tại và tên chính xác mà version của bạn sử dụng, sau đó ghi giá trị tối đa vào /boot/loader.conf.
Có thêm 2 quy tắc về memory cho server nhỏ. Tắt deduplication, vì dedup table nằm trong memory và quy tắc kinh nghiệm thường được công bố là cần 1 đến 3 GB RAM cho mỗi TB dữ liệu duy nhất. Không đặt swap trên zvol (block device được tạo từ pool), vì swap thông qua filesystem đang cố giải phóng memory có thể làm máy bị deadlock. Giữ swap trên partition thông thường hoặc swap file nằm bên ngoài pool.
Khi ext4 hoặc XFS kết hợp với restic là lựa chọn phù hợp hơn
ZFS phát huy hiệu quả trên server có RAM dư và một volume thứ hai. Ngoài trường hợp đó, filesystem thông thường kết hợp với công cụ backup chuyên dụng thường phù hợp hơn. Hãy chọn ext4 hoặc XFS khi:
- Instance có 2 GB hoặc 4 GB RAM và workload cần dùng toàn bộ dung lượng đó.
- Chỉ có một virtual disk và không có bản sao thứ hai, nên ZFS chỉ giúp phát hiện lỗi mà không thể sửa lỗi.
- Backup target của bạn là object storage hoặc một Linux host thông thường, nên không có nơi nào có thể nhận stream
zfs send. - Bạn chạy Debian với DKMS và không thể chấp nhận một lần kernel upgrade khiến module không được build.
- Bạn cần dùng ZFS cho root filesystem nhưng image của provider chỉ cung cấp ext4.
Hãy tiếp tục dùng ZFS khi bạn có một data volume riêng, đủ RAM dư (8 GB trở lên là thoải mái) và có kế hoạch thực sự sử dụng snapshot cùng zfs send, thay vì chỉ bật chúng. Trong các trường hợp còn lại, ext4 kết hợp với restic để ghi backup đã mã hóa và loại bỏ dữ liệu trùng lặp vào storage mà server không kiểm soát sẽ đáp ứng phần lớn nhu cầu tương tự mà không tiêu tốn thêm RAM.
Các tình huống lỗi và chuỗi bạn sẽ thấy
Pool biến mất sau khi reboot. zpool status in no pools available. Import service đọc /etc/zfs/zpool.cache, nên pool không có trong file đó sẽ không bao giờ được import khi boot. sudo zpool import liệt kê những pool có thể import, sudo zpool import tank đưa pool trở lại, còn sudo zpool set cachefile=/etc/zfs/zpool.cache tank giúp trạng thái này được giữ lại. Pool chưa được export sạch từ một hệ thống khác sẽ báo cannot import 'tank': pool may be in use from other system, và sudo zpool import -f tank sẽ ghi đè cảnh báo đó sau khi bạn chắc chắn không có host nào khác đang sử dụng pool.
modprobe: FATAL: Module zfs not found in directory /lib/modules/6.12.0-... trên Debian sau khi nâng cấp kernel. DKMS chưa build cho kernel mới, thường vì chưa cài headers tương ứng. dkms status cho biết module nào đã được build cho kernel nào. Sau đó sudo apt install -y linux-headers-$(uname -r) rồi sudo dkms autoinstall sẽ build lại module, còn sudo zpool import tank đưa pool trở lại.
Pool đầy dù bạn đã xóa các file. Dữ liệu đã xóa vẫn chiếm chỗ trên disk khi snapshot còn tham chiếu đến dữ liệu đó, nên du và df cho kết quả khác nhau. zfs list -o space -r tank tách mức sử dụng thành USEDDS và USEDSNAP, và USEDSNAP lớn chính là nguyên nhân. Hủy các snapshot cũ bằng sudo zfs destroy tank/data@2026-06-01 để giải phóng dung lượng.
Số lượng CKSUM trong zpool status tăng dần. Một thành phần bên dưới ZFS đã trả về dữ liệu lỗi. Trên mirror, đây là cảnh báo và block đã được sửa. Trên pool chỉ có một disk, file bị mất; zpool status -v cho biết tên file đó. Bạn phải khôi phục riêng file này từ một bản backup không nằm trong pool này.
Server chậm và đang dùng swap. Giới hạn ARC như phần trên, sau đó chạy arc_summary và xem hit ratio. Nếu ARC quá nhỏ để chứa working set, mọi lần đọc đều phải truy cập disk. Khi đó, một filesystem thông thường dùng page cache sẽ phục vụ tốt hơn.
FAQ
Một ZFS cần bao nhiêu RAM trên VPS?
ZFS chạy được trên instance 2 GB. Câu hỏi thực tế là ứng dụng của bạn còn lại bao nhiêu RAM. Nếu không tuning, OpenZFS 2.3 cho phép ARC tăng đến giá trị lớn hơn giữa RAM trừ 1 GiB và 5/8 RAM, vì vậy máy 4 GB có thể dành 3 GiB cho cache. Đặt zfs_arc_max thành một giá trị mà workload của bạn có thể cấp, sau đó xác nhận bằng cách đọc dòng c_max từ /proc/spl/kstat/zfs/arcstats.
ZFS snapshot có phải là backup không?
Không. Snapshot nằm trong cùng pool với dữ liệu. Nó vẫn tồn tại sau khi rm gặp lỗi hoặc upgrade thất bại, nhưng sẽ mất cùng pool hoặc instance. Để biến snapshot thành backup, hãy gửi nó đến máy khác bằng zfs send hoặc chạy một công cụ backup ghi dữ liệu vào storage mà server này không kiểm soát.
ZFS trên FreeBSD và Linux có hoạt động giống nhau không?
Từ OpenZFS 2.0 vào tháng 12 năm 2020, hai nền tảng dùng cùng codebase, cùng command, cùng định dạng trên disk và có thể chuyển pool qua lại. Khác biệt nằm ở cách đóng gói. FreeBSD tích hợp ZFS trong base system. Trên Linux, mỗi distribution quyết định cách build: Ubuntu build module trong các kernel package, còn Debian build module trên máy của bạn bằng DKMS. Vì vậy, kernel upgrade có thể khiến bạn không còn module cho đến khi quá trình build lại hoàn tất.
ZFS có sửa được corruption trên VPS chỉ có một disk không?
ZFS phát hiện corruption và cho biết file bị ảnh hưởng, nhưng không thể sửa vì việc sửa cần bản sao thứ hai của block. zfs set copies=2 trên một dataset tạo bản sao thứ hai với dung lượng gấp đôi. Cách này xử lý được bad block nhưng không xử lý được volume bị mất. Mirror trên 2 volume mới là phương án thực sự có thể tự khôi phục.
Compression có làm server chậm hơn không?
lz4 thường giúp server nhanh hơn. Các block đã được nén cần ghi ít byte hơn và đọc ít byte hơn. Chi phí CPU cho mỗi block cũng nhỏ so với lượng disk I/O tiết kiệm được. Đặt compression=lz4 tại pool root để mọi dataset kế thừa cấu hình này, sau đó kiểm tra zfs get compressratio tank khi dữ liệu thực tế đã được ghi.