ZFS vận hành ra sao và những rủi ro cần tính trước
ZFS hợp nhất filesystem và volume manager với checksum, copy-on-write, redundancy, snapshot và replication để phát hiện lỗi dữ liệu, đồng thời có thể tự sửa khi còn bản dư thừa hợp lệ. Tuy nhiên, độ an toàn và hiệu năng phụ thuộc lớn vào topology pool/vdev, đặc tính workload, phần cứng và các thiết lập như record size, SLOG hay special vdev—nhiều lựa chọn rất khó thay đổi về sau. Vì vậy, cần xác định rõ loại lỗi phải chịu, kế hoạch dung lượng, giám sát và quy trình backup–khôi phục trước khi tạo pool.
Một ổ đĩa trả về đúng số byte mà hệ điều hành yêu cầu, nhưng một vài bit bên trong đã thay đổi. Với filesystem chỉ dựa vào trạng thái I/O của thiết bị, lần đọc ấy vẫn có thể kết thúc thành công vì controller không báo lỗi. Ứng dụng nhận dữ liệu hỏng mà không biết. ZFS được thiết kế để xử lý chính khoảng trống này: nó không chỉ hỏi thiết bị có đọc được block hay không, mà còn kiểm tra block nhận về có đúng nội dung đã ghi trước đó hay không.
Điều đó khiến ZFS thường được giới thiệu như một filesystem “an toàn dữ liệu”. Cách gọi này đúng nhưng chưa đủ. OpenZFS kết hợp vai trò của filesystem và volume manager, đồng thời đưa checksum, redundancy, snapshot, compression, encryption và replication vào chung một mô hình quản lý.1 Khi các lớp này cùng biết block nào thuộc file nào, checksum nằm ở đâu và bản dư thừa nào còn hợp lệ, ZFS có thể phát hiện rồi tự sửa một số lỗi mà mô hình filesystem đặt trên RAID controller khó xử lý trọn vẹn.
Đổi lại, người vận hành phải hiểu cấu trúc pool ngay từ đầu. Một topology chọn sai không phải lúc nào cũng sửa được bằng vài lệnh cấu hình. Hiệu năng cũng không thể suy ra từ nhãn “RAIDZ2” hay số lượng SSD; nó phụ thuộc kích thước I/O, tỷ lệ đọc ghi, mức độ đồng bộ, working set, độ đầy của pool và cả cách ứng dụng đặt dữ liệu lên dataset.
Ba lớp cần phân biệt: pool, vdev và dataset
Đơn vị lưu trữ cấp cao nhất là pool. Bên trong pool có một hoặc nhiều top-level vdev; mỗi vdev lại được tạo từ các thiết bị vật lý hoặc logical device do hệ điều hành cung cấp. ZFS phân phối block động qua các top-level vdev, còn khả năng chịu lỗi được quyết định bên trong từng vdev.2
flowchart TD
P[Pool: tank] --> V1[Mirror vdev 1]
P --> V2[Mirror vdev 2]
V1 --> D1[Disk A]
V1 --> D2[Disk B]
V2 --> D3[Disk C]
V2 --> D4[Disk D]
P --> F1[Dataset: tank/media]
P --> F2[Dataset: tank/vm]
P --> F3[Dataset: tank/backup]
Một điểm dễ hiểu nhầm nằm ở đây: pool có nhiều vdev không đồng nghĩa với việc pool chịu được mất nguyên một vdev. Trong sơ đồ trên, mỗi mirror có thể mất một thành viên mà vẫn còn dữ liệu. Nhưng nếu cả hai disk của cùng một mirror không còn đọc được, những block đã được cấp phát lên vdev đó có thể mất và toàn bộ pool bị ảnh hưởng. Redundancy không được cộng dồn tùy ý giữa các top-level vdev.
Phía trên pool là dataset, gồm filesystem hoặc volume dạng block, thường gọi là zvol. Mỗi dataset có thể đặt riêng compression, quota, reservation, recordsize, snapshot policy, cache policy hoặc encryption. Cách phân tầng này hữu ích hơn việc chia partition cố định: dung lượng vẫn được chia sẻ trong pool, trong khi policy được tách theo workload.
Chẳng hạn, tank/media có thể dùng record lớn để ưu tiên sequential throughput; tank/vm dùng record nhỏ hơn và snapshot ngắn hạn; tank/backup đặt quota cùng chế độ chỉ đọc ở phía nhận replication. Tạo dataset theo ranh giới vận hành còn giúp tránh một lỗi thường gặp: áp dụng một giá trị recordsize hoặc retention policy cho mọi loại dữ liệu chỉ vì chúng nằm trên cùng bộ disk.
Copy-on-write và transaction group
ZFS sử dụng copy-on-write (CoW). Khi một record thay đổi, ZFS không ghi đè phiên bản mới vào đúng vị trí của block cũ. Nó cấp phát block khác, ghi dữ liệu mới, tạo checksum rồi cập nhật dần cây metadata. Các thay đổi được gom thành transaction và transaction group; một transaction group chỉ được xem là hoàn tất sau khi dữ liệu cần thiết đã được đồng bộ xuống thiết bị lưu trữ.3

Cơ chế này giúp filesystem duy trì một cây block nhất quán khi hệ thống dừng đột ngột. Pool có thể quay về trạng thái đã commit gần nhất thay vì cần ghi đè tại chỗ rồi cố suy luận phần nào của cấu trúc metadata đã được cập nhật. Tuy nhiên, tính nhất quán của filesystem không thay thế transaction của ứng dụng. Nếu một database ghi nhiều page nhưng không dùng đúng cơ chế fsync, WAL hoặc transaction của chính nó, ZFS không thể tự suy ra các page đó phải được commit như một đơn vị nghiệp vụ.
CoW cũng là nền tảng của snapshot. Snapshot ban đầu không sao chép toàn bộ dataset; nó giữ các tham chiếu tới block đang tồn tại. Khi dataset tiếp tục ghi, phiên bản mới được đặt ở block khác, còn snapshot vẫn trỏ tới phiên bản cũ.4 Vì thế thao tác tạo snapshot diễn ra nhanh, nhưng dung lượng snapshot không cố định. Một workload thường xuyên sửa dữ liệu trong tập block lớn có thể làm lượng space được snapshot giữ lại tăng nhanh.
Chi phí còn xuất hiện ở write amplification và fragmentation. Nếu ứng dụng liên tục sửa 4 KiB bên trong record 128 KiB, ZFS có thể phải xử lý nhiều dữ liệu hơn kích thước ứng dụng vừa thay đổi. Khi pool đã hoạt động lâu và các vùng trống bị chia nhỏ, việc tìm vị trí cấp phát phù hợp cũng phức tạp hơn. CoW bảo vệ trạng thái cũ; nó không bảo đảm mọi workload đều có latency thấp.
ZIL, synchronous write và giới hạn của SLOG
Ứng dụng có thể phát sinh asynchronous write hoặc yêu cầu synchronous write qua các cơ chế như fsync. Với asynchronous write, dữ liệu thường được gom trong bộ nhớ rồi đồng bộ theo transaction group. Với synchronous write, ứng dụng chỉ được nhận xác nhận sau khi dữ liệu cần thiết đã được ghi vào nơi có thể phục hồi sau sự cố.
ZFS Intent Log (ZIL) lưu thông tin cần thiết cho các synchronous write chưa nằm trong transaction group đã hoàn tất. Sau khi transaction group tương ứng được commit, bản ghi log đó không còn cần thiết. Trong quá trình hoạt động bình thường, ZIL không phải nơi ứng dụng đọc lại dữ liệu; nó chủ yếu được replay sau một lần dừng bất thường.
SLOG là thiết bị riêng dành cho ZIL. Một SLOG có latency thấp và bảo đảm dữ liệu khi mất điện có thể giảm latency của synchronous write, nhất là khi normal vdev dùng HDD. Nhưng SLOG không phải write cache tổng quát, không tăng tốc toàn bộ asynchronous write và không làm pool có thêm dung lượng sử dụng.10
Điều này đặc biệt quan trọng với NFS, database và VM datastore. Nếu workload thực sự chờ fsync, SLOG có thể tạo khác biệt đáng kể. Nếu phần lớn write là asynchronous, thêm SLOG thường không giải quyết nút thắt. Trước khi mua thiết bị, cần đo tỷ lệ synchronous write, latency phân vị cao và khả năng chịu ghi của SSD. Một SSD consumer không có power-loss protection có thể xác nhận write trước khi dữ liệu thực sự ổn định trên NAND; đặt nó vào đường ghi đồng bộ làm thay đổi mô hình rủi ro chứ không chỉ thay đổi hiệu năng.

Không nên đặt sync=disabled chỉ để benchmark đẹp hơn trên dữ liệu quan trọng. Thuộc tính đó cho phép ZFS xử lý yêu cầu synchronous write như asynchronous write. Khi mất điện, ứng dụng có thể đã nhận xác nhận cho dữ liệu chưa được lưu bền vững. Đây là thay đổi về semantics mà database hoặc hypervisor đang dựa vào.
Checksum phát hiện lỗi, redundancy mới sửa được lỗi
Mỗi block có checksum được lưu trong block pointer của metadata cấp trên thay vì nằm cạnh chính block dữ liệu. Khi đọc, ZFS tính lại checksum và so sánh với giá trị đã ghi. Sai lệch cho biết dữ liệu không còn nguyên vẹn, kể cả khi thiết bị vẫn trả I/O thành công. Chuỗi checksum từ dữ liệu lên metadata cấp cao giúp ZFS xác định bản nào phù hợp với cây block hiện hành.
Nếu pool có mirror hoặc RAIDZ còn đủ bản dữ liệu hay parity, ZFS có thể đọc một bản hợp lệ, trả dữ liệu đúng cho ứng dụng và sửa block hỏng. Nếu không có redundancy, checksum vẫn phát hiện corruption nhưng không tự tạo ra dữ liệu đúng để phục hồi. Đây là khác biệt giữa phát hiện lỗi và chịu lỗi.
scrub mở rộng việc kiểm tra ra toàn bộ dữ liệu đang được tham chiếu trong pool. Thay vì chờ một file được đọc tình cờ, scrub đọc các block, kiểm tra checksum và sửa lỗi khi còn bản dư thừa phù hợp. resilver có phạm vi khác: nó tái tạo dữ liệu được biết là thiếu hoặc không còn cập nhật trên thiết bị vừa thay thế, trong khi scrub chủ động tìm cả lỗi tiềm ẩn chưa được quan sát trước đó.6
Lịch scrub cần dựa trên dung lượng, loại thiết bị, tải I/O và thời gian hoàn tất thực tế. Scrub là thao tác I/O-intensive, có thể cạnh tranh bandwidth với workload chính. Nhưng không chạy scrub cũng có giá: corruption trên một disk có thể chỉ được phát hiện đúng lúc một disk khác đang lỗi, khi số bản hợp lệ đã giảm. Điều cần theo dõi không chỉ là lịch bắt đầu, mà còn là scrub có hoàn tất hay không, đã sửa bao nhiêu byte và zpool status còn báo lỗi nào.
Mirror, RAIDZ và cách I/O đi qua từng layout
ZFS hỗ trợ mirror cùng ba mức parity RAIDZ. RAIDZ1 chịu được một thiết bị lỗi, RAIDZ2 chịu được hai và RAIDZ3 chịu được ba thiết bị lỗi trong cùng vdev.7 Tuy nhiên, số disk chịu lỗi chỉ là một phần của quyết định.
| Layout | Đặc tính kỹ thuật | Trường hợp thường phù hợp |
|---|---|---|
| Mirror | Nhiều bản đầy đủ, random I/O và resilver thường thuận lợi; hiệu quả dung lượng thấp hơn | VM, database, metadata server, workload nhạy latency |
| RAIDZ1 | Một parity, hiệu quả dung lượng cao hơn mirror nhưng biên chịu lỗi thấp | Pool nhỏ, dữ liệu có backup tốt và chấp nhận thời gian phục hồi tương ứng |
| RAIDZ2 | Hai parity, cân bằng giữa dung lượng và khả năng chịu lỗi | NAS nhiều ổ, kho tài liệu, media và backup repository |
| RAIDZ3 | Ba parity, chi phí dung lượng lớn hơn nhưng tăng biên an toàn | Vdev rộng, thiết bị dung lượng lớn, thời gian thay và tái tạo dài |
Với nhiều mirror vdev, các I/O độc lập có thể được phân phối qua nhiều vdev. Điều này thường phù hợp với random I/O có queue depth đáng kể. RAIDZ dùng dynamic stripe gồm dữ liệu và parity. Một write phải hoàn tất các phần liên quan của stripe; trong trường hợp xấu, write IOPS của vdev bị giới hạn bởi thiết bị chậm nhất tham gia thao tác.7 Read không nhất thiết truy cập mọi disk cho mọi block, nhưng latency vẫn phụ thuộc các cột chứa block đó.
Record nhỏ trên RAIDZ còn chịu chi phí parity và sector alignment. Ví dụ, nếu một record chỉ chiếm một sector dữ liệu, ZFS vẫn cần sector parity tương ứng; hiệu quả dung lượng lúc ấy có thể thấp hơn nhiều so với phép tính đơn giản “tổng disk trừ số disk parity”. Vì vậy, một RAIDZ vdev rộng không tự động vừa tiết kiệm dung lượng vừa cung cấp nhiều random IOPS.
ashift xác định kích thước sector nhỏ nhất mà ZFS dùng trên vdev. Giá trị này được chọn khi tạo vdev và không thể tùy ý hạ xuống sau đó. Disk báo sector 512 byte nhưng thực tế ghi theo page 4 KiB có thể chịu read-modify-write nếu cấu hình không phù hợp. Khi dự kiến thay disk trong tương lai, cần tính cả sector size của thiết bị thay thế, không chỉ đặc tính của disk đang có.
Các phiên bản OpenZFS mới có thể hỗ trợ mở rộng một RAIDZ vdev bằng cách thêm thiết bị, nhưng tính năng này phụ thuộc phiên bản và pool feature. Quá trình mở rộng phải đọc rồi phân phối lại dữ liệu đã cấp phát; mức parity không thay đổi, và block cũ giữ tỷ lệ data-to-parity ban đầu cho tới khi được ghi lại.11 Vì vậy, không nên thiết kế capacity plan dựa trên RAIDZ expansion trước khi xác nhận chính xác phiên bản chạy ở cả hệ thống hiện tại lẫn môi trường phục hồi.
recordsize, volblocksize và compression
recordsize là kích thước record tối đa cho file trong ZFS filesystem, mặc định thường là 128 KiB. File nhỏ hoặc phần cuối file không nhất thiết chiếm trọn một record. Giá trị này cũng không phải kích thước I/O bắt buộc mà mọi ứng dụng phải dùng. ZFS có thể gom hoặc chia I/O, còn compression có thể làm kích thước vật lý nhỏ hơn kích thước logical.5
Với media, backup file lớn và workload sequential, record lớn thường giảm lượng metadata và hỗ trợ throughput. Với database thường xuyên cập nhật page nhỏ, record quá lớn có thể tăng read-modify-write. Tuy nhiên, việc đặt recordsize bằng đúng database page size không phải quy tắc tuyệt đối: compression, cache của database, WAL và kiểu truy vấn đều ảnh hưởng kết quả. Cách an toàn là tách dataset, chọn một baseline có căn cứ rồi benchmark bằng workload gần production.
Zvol dùng volblocksize, không dùng recordsize. Đây là block size cố định của volume và có ảnh hưởng lâu dài tới hiệu quả dung lượng, write amplification và snapshot. Khi zvol chứa filesystem của VM, đường I/O có ít nhất hai lớp block: guest filesystem và ZFS. Nếu guest gửi write nhỏ, zvol dùng block lớn, bên dưới lại là RAIDZ có parity, một thay đổi nhỏ có thể kéo theo nhiều thao tác hơn dự kiến.
Compression, thường là lz4 trong các cấu hình phổ biến, có thể vừa tiết kiệm dung lượng vừa giảm lượng dữ liệu phải chuyển tới disk. Nếu dữ liệu nén tốt và CPU còn dư, throughput thực tế có thể tăng. Ngược lại, video đã nén, archive hoặc dữ liệu mã hóa gần như không còn nhiều dư địa. Compression nên được đánh giá theo compressratio, CPU usage và latency thực tế, không chỉ theo dung lượng logical mà ứng dụng báo.
Thay đổi recordsize, volblocksize hay thuật toán compression không viết lại toàn bộ dữ liệu cũ. Thuộc tính mới chủ yếu áp dụng cho block được tạo hoặc ghi lại sau đó. Một benchmark ngay sau khi đổi property có thể trộn hai layout vật lý và dẫn tới kết luận sai.
ARC, L2ARC và special vdev không cùng một vai trò
ARC là read cache chính trong RAM. Nó lưu dữ liệu và metadata dựa trên lịch sử truy cập, nhờ đó giảm read phải đi xuống thiết bị. ZFS sử dụng RAM khả dụng cho cache nhưng có thể thu hồi khi hệ thống cần; tuy nhiên, giới hạn ARC, ứng dụng khác và hành vi reclaim còn phụ thuộc hệ điều hành. Khi chẩn đoán thiếu RAM, cần xem ARC statistics, memory pressure và cache của ứng dụng thay vì kết luận chỉ từ lượng RAM “đang dùng”.
L2ARC là read cache cấp hai trên SSD hoặc thiết bị nhanh hơn normal vdev. Nó hữu ích khi working set lớn hơn ARC, truy cập thiên về random read và dữ liệu được tái sử dụng đủ nhiều. L2ARC không tăng tốc write. Mỗi block trong L2ARC còn cần metadata trong RAM, nên một cache quá lớn có thể làm giảm phần bộ nhớ dành cho ARC và các cấu trúc khác.10 Nếu workload chủ yếu sequential scan một lần hoặc dữ liệu hiếm khi được đọc lại, L2ARC có thể cung cấp ít lợi ích.
Special vdev hoàn toàn khác cache. Nó lưu metadata, indirect block và có thể lưu block dữ liệu nhỏ theo special_small_blocks. Đây là vị trí chính thức của các block đó, không phải bản sao tạm thời. Mất special vdev không đủ redundancy có thể làm mất pool.12
Special vdev có thể cải thiện mạnh thao tác duyệt thư mục, truy cập nhiều file nhỏ hoặc workload phụ thuộc metadata khi normal vdev là HDD. Nhưng threshold của special_small_blocks được xét theo kích thước vật lý sau compression và encryption. Một record logical 128 KiB nén còn 20 KiB có thể được đặt lên special vdev nếu threshold là 32 KiB. Đặt threshold quá cao vì tưởng chỉ bắt file nhỏ có thể khiến lượng dữ liệu ghi lên SSD lớn hơn nhiều so với dự toán.
Use case 1: NAS gia đình và kho media
NAS gia đình thường có workload hỗn hợp: file ảnh nhỏ, tài liệu, video lớn, backup từ laptop và đôi khi cả container. ZFS phù hợp vì có checksum, snapshot, compression và quota theo dataset. Với bốn đến tám HDD, RAIDZ2 thường được cân nhắc khi ưu tiên dung lượng và khả năng chịu hai disk lỗi trong cùng vdev. Nếu NAS đồng thời chạy VM hoặc nhiều dịch vụ có random I/O, hai hoặc nhiều mirror vdev có thể cung cấp latency ổn định hơn, đổi lại dung lượng sử dụng thấp hơn.
Không nên đặt tất cả dữ liệu trong một dataset. Có thể tách:
tank/mediacho video và ảnh gốc, dùng record lớn và snapshot thưa hơn;tank/documentscho tài liệu nhỏ, snapshot thường xuyên và retention dài hơn;tank/client-backupđặt quota để một máy không chiếm hết pool;tank/appsdành cho dữ liệu ứng dụng, với policy khác media;tank/shareddùng ACL phù hợp với SMB hoặc NFS.
Với SMB, việc duyệt thư mục có hàng trăm nghìn file phụ thuộc nhiều vào metadata. RAM lớn hơn, normal vdev nhanh hơn hoặc special vdev có redundancy có thể giúp ích. L2ARC chỉ đáng cân nhắc sau khi đo cache hit và xác nhận working set được đọc lặp lại. Thêm SSD theo suy đoán thường không giải quyết đúng nút thắt.
NAS còn cần UPS, giám sát nhiệt độ, SMART, lỗi link và cảnh báo zpool status. ZFS phát hiện checksum mismatch nhưng không tự gửi thông báo nếu không có dịch vụ giám sát. Một pool đã DEGRADED nhiều tuần vì email cảnh báo chưa cấu hình vẫn có thể tiếp tục phục vụ file, cho tới khi thêm một thiết bị lỗi và vượt quá mức redundancy.
Use case 2: VM, container và database
VM tạo ra random I/O, nhiều write nhỏ, snapshot và flush thường xuyên. Với workload này, mirror vdev thường dễ dự đoán hơn RAIDZ rộng. Zvol cần volblocksize phù hợp; nếu đặt quá lớn, write amplification và chi phí snapshot tăng, còn đặt quá nhỏ làm metadata cùng parity overhead tăng. Không có một giá trị đúng cho mọi hypervisor: block size của guest filesystem, database page, tỷ lệ thin provisioning và layout bên dưới đều phải được xét cùng nhau.
Snapshot VM chỉ bảo đảm trạng thái block tại một thời điểm. Nếu guest đang chạy, snapshot có thể tương đương việc máy bị mất điện ở thời điểm đó, trừ khi hypervisor phối hợp quiesce filesystem hoặc ứng dụng. Với database, application-consistent snapshot đòi hỏi flush, freeze hoặc cơ chế backup mà database hỗ trợ. Crash-consistent không đồng nghĩa transaction-consistent trong mọi trường hợp.
Database trên filesystem ZFS nên có dataset riêng cho data file và WAL hoặc transaction log khi cần policy khác nhau. Tài liệu OpenZFS đưa ra các gợi ý riêng cho MySQL, PostgreSQL và SQLite, nhưng đó là điểm bắt đầu chứ không phải cấu hình có thể sao chép nguyên xi.5 Database còn có buffer cache riêng; nếu ARC cũng cache toàn bộ data page, RAM có thể bị dùng cho hai lớp cache. primarycache=metadata đôi khi hợp lý, nhưng chỉ nên áp dụng sau khi đo hit ratio, read latency và memory pressure.
SLOG có thể hữu ích khi VM hoặc database phát sinh nhiều synchronous write. Nó phải có latency thấp, endurance phù hợp và power-loss protection. Hai SLOG device mirror có thể được dùng khi yêu cầu availability cao hơn, nhưng SLOG không thay thế redundancy của normal vdev. Nếu database bị giới hạn bởi random read, thêm SLOG sẽ không xử lý nguyên nhân đó.
Use case 3: backup server và replication
Snapshot kết hợp zfs send và zfs receive là một use case mạnh của ZFS. Full send tạo stream từ toàn bộ snapshot; incremental send chỉ truyền các block thay đổi giữa hai snapshot hoặc bookmark. Cách làm này dựa trên block bookkeeping của ZFS, không phải quét toàn bộ cây thư mục để tìm file có timestamp khác.8
sequenceDiagram
participant S as Pool nguồn
participant N as Kết nối
participant B as Pool backup
S->>S: Tạo snapshot @day-1
S->>N: zfs send full
N->>B: zfs receive
S->>S: Tạo snapshot @day-2
S->>N: zfs send incremental
N->>B: Nhận block đã thay đổi
B->>B: Scrub và kiểm tra restore
Replication vẫn cần thiết kế retention. Incremental send yêu cầu nguồn và đích còn một snapshot hoặc bookmark chung. Nếu snapshot gốc bị xóa ở cả hai phía mà không còn bookmark phù hợp, lần tiếp theo có thể phải gửi full stream. Với đường truyền không ổn định, resumable receive giúp tiếp tục từ trạng thái dở thay vì gửi lại nhiều terabyte.
Dataset nhận nên được unmount hoặc đặt readonly=on để tránh write ngoài ý muốn làm đứt chuỗi incremental. Những tùy chọn như zfs receive -F có thể rollback và xóa snapshot hay dataset ở đích để khớp nguồn; đây là thao tác cần dry run và kiểm soát chặt, không nên đưa vào script khi chưa hiểu phạm vi.
Với native encryption, raw send bằng zfs send -w giữ dữ liệu ở dạng mã hóa và cho phép máy backup nhận stream mà không cần khóa giải mã.13 Nhưng khóa vẫn phải được backup độc lập. Mất pool nguồn, pool backup còn nguyên nhưng không còn key material thì dữ liệu vẫn không thể phục hồi.
Một pool backup trong cùng chassis, cùng nguồn điện và cùng tài khoản quản trị chưa phải miền lỗi độc lập. Replication bảo vệ tốt hơn khi đích khác thiết bị, khác quyền truy cập và, tùy yêu cầu, khác địa điểm. Quan trọng hơn, phải thử receive hoặc restore file định kỳ. Một job replication báo thành công chỉ chứng minh stream đã được nhận, chưa chứng minh ứng dụng có thể phục hồi đúng RPO và RTO.
Use case 4: workstation hoặc server chỉ có một disk
ZFS vẫn có giá trị trên một SSD: checksum, snapshot, compression, dataset và quota không phụ thuộc mirror. Nó có thể phù hợp cho workstation cần snapshot trước khi nâng cấp, máy build chứa nhiều dataset hoặc server nhỏ có backup ngoài máy.
Nhưng single-disk pool không tự sửa được block hỏng nếu không còn bản khác. Thuộc tính copies=2 có thể lưu thêm bản của data block trên cùng pool, song hai bản vẫn có thể nằm trên cùng thiết bị vật lý. Nó giúp trong một số lỗi cục bộ, không bảo vệ trước việc SSD hỏng hoàn toàn, controller làm mất thiết bị hoặc máy bị đánh cắp.
Snapshot cũng không thay thế backup. Xóa nhầm file có thể khôi phục từ snapshot; lệnh phá hủy pool, lỗi thiết bị hoặc ransomware có quyền xóa snapshot có thể loại bỏ cả dữ liệu gốc lẫn lịch sử. Vì vậy, single-disk ZFS chỉ hợp lý khi người vận hành mô tả rõ lớp nào phát hiện lỗi, lớp nào giữ lịch sử và bản sao nào nằm ngoài máy.
Các rủi ro thường bị đánh giá thấp
Topology và khả năng mở rộng
Thêm một top-level vdev làm tăng capacity và có thể tăng aggregate throughput, nhưng dữ liệu cũ không tự cân bằng đều sang vdev mới. Các block mới được phân phối theo trạng thái free space và allocator hiện tại. Nếu một pool ban đầu có một vdev gần đầy rồi mới thêm vdev khác, phân bố dữ liệu và hiệu năng có thể khác một pool được tạo với hai vdev ngay từ đầu.
Khả năng tháo top-level vdev còn phụ thuộc layout, ashift, encryption key và pool feature. Special vdev trên pool có RAIDZ có thể trở thành quyết định lâu dài. Trước zpool add, cần xem thao tác đó là thay đổi cấu trúc bền vững, không phải gắn thêm một disk có thể tháo ra tùy ý.
Pool quá đầy và fragmentation
Dung lượng “còn trống” không có nghĩa allocator vẫn tìm được block lớn với cùng chi phí như lúc pool mới tạo. CoW cần vị trí mới trước khi giải phóng block cũ, snapshot có thể giữ block cũ lâu hơn, còn free space bị chia nhỏ theo thời gian. Khi pool tiến gần giới hạn, latency write có thể tăng và thao tác giải phóng dung lượng cũng khó hơn.
Quota, reservation và cảnh báo capacity cần được đặt trước khi có sự cố. Không nên tính capacity chỉ từ tổng dung lượng file hiện tại; phải cộng tăng trưởng, snapshot retention, khoảng trống cho resilver hoặc expansion và dữ liệu tạm thời trong các đợt backup.
Snapshot retention không được kiểm soát
Snapshot nhỏ tại thời điểm tạo nhưng có thể giữ lượng lớn block cũ. Xóa file khỏi dataset không giải phóng dung lượng nếu snapshot vẫn tham chiếu file đó. Một job snapshot chạy đều nhưng retention bị lỗi có thể làm pool tăng mức sử dụng chậm và khó nhận ra.
Cần theo dõi usedbysnapshots, kiểm thử policy xóa snapshot và phân biệt snapshot tự động với snapshot đang được replication hoặc hold bảo vệ. Xóa một snapshot ở giữa chuỗi không nhất thiết giải phóng lượng dung lượng mà tên snapshot gợi ý, vì block còn có thể được snapshot khác tham chiếu.
Controller, cabling và thiết bị không phù hợp
ZFS cần nhìn thấy từng thiết bị và trạng thái lỗi của chúng càng trực tiếp càng tốt. RAID controller che disk phía sau một logical volume có thể làm mất thông tin, thay đổi semantics của flush hoặc tự thực hiện recovery theo cách ZFS không quan sát được. HBA ở chế độ phù hợp thường dễ kiểm soát hơn cho một pool ZFS.
Checksum error không luôn có nghĩa platter hoặc NAND đã hỏng. Cáp, backplane, controller, nguồn điện và RAM đều có thể làm dữ liệu thay đổi hoặc I/O thất bại. zpool clear chỉ xóa bộ đếm sau khi nguyên nhân đã được xử lý; nó không sửa hardware và không khôi phục dữ liệu đã mất.
Dedup có chi phí lớn
Deduplication diễn ra ở cấp block và cần tra cứu Deduplication Table khi ghi. Bảng này cạnh tranh RAM, metadata I/O và CPU với phần còn lại của hệ thống. OpenZFS cung cấp cách ước lượng DDT trước khi bật dedup, nhưng kết quả vẫn phụ thuộc số block duy nhất, block size và tỷ lệ trùng thực tế.5
Compression thường ít tốn tài nguyên hơn và nên được thử trước. Backup từ nhiều máy có thể trông giống nhau ở cấp file nhưng không bảo đảm block alignment đủ giống để dedup đạt tỷ lệ mong muốn. Bật dedup trên pool lớn rồi mới phát hiện DDT không vừa RAM có thể làm write, scrub và import chậm đáng kể.
Encryption và quản lý khóa
Native encryption bảo vệ nội dung dataset khi thiết bị hoặc bản raw replication rơi vào tay người không có khóa. Nó không bảo vệ hệ thống đã mount dataset và đang bị truy cập bằng tài khoản hợp lệ. Encryption cũng không thay thế permission, backup hoặc checksum.
Phải backup key material, passphrase và quy trình load key ở một nơi tách khỏi pool. Cần thử phục hồi trên máy khác trước khi coi kế hoạch hoàn tất. Raw send và non-raw send có semantics khác nhau; trộn hai kiểu trong một chuỗi incremental có thể tạo giới hạn cho các lần receive sau.13
RAM lỗi và ECC
Checksum trên disk không loại bỏ rủi ro dữ liệu bị thay đổi trong RAM trước khi checksum được tính hoặc trước khi write hoàn tất. OpenZFS khuyến nghị ECC memory cho hệ thống coi trọng tính toàn vẹn dữ liệu.9 ECC không phải điều kiện bắt buộc để ZFS khởi chạy, và non-ECC không khiến mọi pool chắc chắn hỏng. Tuy nhiên, mức bảo vệ phần cứng phải tương xứng với giá trị dữ liệu, thời gian lưu giữ và khả năng khôi phục.
Một checklist trước khi tạo pool
Trước lệnh zpool create, tôi sẽ yêu cầu trả lời rõ các câu hỏi sau:
- Pool cần chịu được bao nhiêu disk lỗi trong cùng một vdev?
- Workload chủ yếu là sequential hay random I/O?
- Tỷ lệ synchronous write là bao nhiêu, và ứng dụng dựa vào
fsyncở đâu? - Kích thước I/O, working set và latency mục tiêu đã được đo hay mới suy đoán?
- Dataset nào cần
recordsize,volblocksize, compression, quota hoặc cache policy riêng? - Capacity plan đã tính snapshot retention, tăng trưởng và khoảng trống vận hành chưa?
- Hệ thống sẽ mở rộng bằng cách thêm vdev, thay toàn bộ disk hay dùng RAIDZ expansion?
- Phiên bản OpenZFS ở máy nguồn và máy phục hồi hỗ trợ những pool feature nào?
- Có backup ở miền lỗi khác và đã thử restore chưa?
- Encryption key được lưu và kiểm thử phục hồi ở đâu?
- Có giám sát
zpool status, SMART, nhiệt độ, capacity và thời gian scrub không? - Khi một disk lỗi, ai nhận cảnh báo, disk thay thế nằm ở đâu và thời gian phản ứng là bao lâu?
ZFS cung cấp nhiều cơ chế để bảo vệ dữ liệu, nhưng các cơ chế ấy chỉ phát huy tác dụng khi topology, phần cứng và quy trình phục hồi cùng hướng tới một mục tiêu. Checksum cho biết block đã sai; redundancy tạo cơ hội sửa; snapshot giữ lịch sử; replication tạo thêm bản sao; backup ở miền lỗi độc lập mới bảo vệ trước việc mất cả pool.
Điều đáng cân nhắc nhất trước khi dùng ZFS không phải là nên bật bao nhiêu feature. Câu hỏi đúng hơn là hệ thống cần chịu loại lỗi nào, trong bao lâu và với mức suy giảm hiệu năng nào. Khi câu trả lời đã rõ, việc chọn mirror hay RAIDZ, có cần SLOG hay special vdev, đặt record size bao nhiêu và giữ snapshot thế nào mới trở thành một quyết định kỹ thuật có thể kiểm chứng.
Tài liệu tham khảo
- OpenZFS Project. OpenZFS Documentation. OpenZFS Documentation.
- OpenZFS Project. VDEVs. OpenZFS Documentation.
- OpenZFS Project. OpenZFS Transaction Delay. OpenZFS Documentation.
- OpenZFS Project. zfsconcepts(7): overview of ZFS concepts. OpenZFS Manual.
- OpenZFS Project. Workload Tuning. OpenZFS Documentation.
- OpenZFS Project. Scrub and Resilver. OpenZFS Documentation.
- OpenZFS Project. RAIDZ. OpenZFS Documentation.
- OpenZFS Project. Send and Receive. OpenZFS Documentation.
- OpenZFS Project. Hardware. OpenZFS Documentation.
- OpenZFS Project. Caching and Auxiliary Devices. OpenZFS Documentation.
- OpenZFS Project. Changing Pool Layout. OpenZFS Documentation.
- OpenZFS Project. Special vdev. OpenZFS Documentation.
- OpenZFS Project. zfs-send(8): generate a ZFS send stream. OpenZFS Manual.