SSD Nodes Learn 🎉 VPS từ $5.50/tháng
Hướng dẫn Matt ConnorBởi Matt Connor

Lịch scrub ZFS cho pool VPS một disk

Scrub ZFS đọc mọi block đã cấp phát để kiểm tra checksum. Với pool VPS chỉ có một device, lỗi phát hiện được nhưng không thể tự sửa, nên hãy chọn lịch phù hợp.

ZFS scrub thực sự làm gì

ZFS scrub đọc mọi block đã được cấp phát trong pool, tính lại checksum của từng block rồi so sánh kết quả với checksum được lưu trong block pointer cha. Nếu hai giá trị không khớp, ZFS sẽ sửa block bằng phần dự phòng mà pool đang có. Không có cơ chế nào khác trong ZFS thực hiện công việc này. Các lần đọc thông thường chỉ xác minh những block mà bạn thực sự truy cập, nên một file bạn chưa mở trong hai năm vẫn chưa được xác minh cho đến khi scrub đọc đến file đó.

Scrub không phải là fsck, tức quy trình sửa chữa offline mà các filesystem khác cần. Không có giai đoạn sửa chữa cấu trúc, vì ZFS không bao giờ để định dạng trên disk rơi vào trạng thái hỏng: mỗi lần ghi đều ghi vào một vị trí mới, rồi chỉ cập nhật uberblock, root pointer của pool, ở bước cuối cùng. Scrub cũng không đọc toàn bộ thiết bị. Nó chỉ đọc các block đã được cấp phát. Vì vậy, một pool gần như trống chỉ scrub trong vài phút, còn cùng pool đó khi đầy 80% sẽ mất nhiều thời gian hơn đáng kể.

Scrub chạy với mức ưu tiên I/O thấp nhất mà ZFS có. Trên Linux, zfs_vdev_scrub_max_active mặc định là 2, nên mỗi vdev (virtual device, nhóm disk mà ZFS xem là một đơn vị) có tối đa 2 lần đọc scrub đang thực hiện đồng thời. zfs_scrub_min_time_ms mặc định là 750, là khoảng thời gian tối thiểu mà sync thread dành cho công việc scrub giữa các lần flush transaction group, tức các lần commit định kỳ mà ZFS dùng để gom các lần ghi. Trên máy đang rảnh, scrub sử dụng toàn bộ disk. Khi hệ thống có tải, scrub nhường tài nguyên. Với pool chỉ có 1 hoặc 2 thiết bị, không còn nơi khác để nhường tài nguyên, nên việc lập lịch quan trọng hơn so với một chassis lớn có 60 drive.

Vì sao phải scrub một pool không thể tự sửa lỗi?

Đây là câu hỏi quyết định mọi việc khác trên một pool nhỏ. Không có redundancy, scrub chỉ phát hiện corruption mà không thể sửa. Một virtual disk duy nhất trên VPS là pool không có mirror và cũng không có parity. ZFS sẽ đọc block bị lỗi, xác thực checksum thất bại, ghi nhận lỗi trong cột CKSUM, xác định tên file, rồi dừng ở đó vì không có bản sao thứ hai để rebuild.

Có 2 ngoại lệ một phần cần biết. Theo mặc định, ZFS lưu thêm một bản sao của metadata (redundant_metadata=all) tại một vùng khác trên thiết bị, nên scrub vẫn có thể sửa directory entry hoặc block pointer bị hỏng ngay cả trên pool chỉ có một thiết bị. Dataset có copies=2 sẽ giữ 2 bản sao của các data block, với chi phí dung lượng gấp đôi. Cả hai cách này đều không giúp được khi thiết bị bị mất. Tài liệu về property copies cảnh báo chính xác về trường hợp này: không được tạo striped pool, đặt copies=2, rồi tin rằng bạn đã có redundancy.

Vì vậy, trên pool chỉ có một thiết bị, scrub mang lại một giá trị: thông báo sớm và chính xác. Nó biến corruption âm thầm thành tên file trong zpool status -v trong khi backup của bạn vẫn còn bản tốt của file đó. Đây là lý do nên có backup, không phải lý do để bỏ scrub. Nếu bạn chưa phân biệt rõ giữa image tại một thời điểm và bản sao thực sự nằm ngoài máy, hãy bắt đầu với vì sao snapshot VPS không phải là backup, vì kết quả scrub chỉ hữu ích khi có nơi khác giữ một bản sao nguyên vẹn.

Scrub không phát hiện lỗi cũng là một kết quả. Nó cho biết dữ liệu bạn sắp tin cậy vẫn nguyên vẹn. Đây là điều bạn cần biết trước khi restore hoặc migration.

Bao lâu nên scrub một pool VPS nhỏ?

Hàng tháng là mặc định phù hợp, và đó cũng là tần suất mà các package đã giả định sẵn. Debian và Ubuntu cung cấp một cron job để scrub các pool đang hoạt động bình thường vào Chủ nhật thứ hai mỗi tháng. Hệ thống periodic của FreeBSD dựa trên một ngưỡng tính theo ngày, và daily_scrub_zfs_default_threshold mặc định là 35; tài liệu mô tả giá trị này tương đương 5 tuần.

Scrub hàng tuần trên một pool nhỏ đang bận thường tốn nhiều hơn lợi ích nhận được. Với 1 hoặc 2 thiết bị, scrub phải cạnh tranh cùng queue với ứng dụng, và không có thiết bị dự phòng để tiếp nhận tải này. Trên VPS, hạn mức I/O là hữu hạn, nên số lượt đọc mà scrub sử dụng là số lượt đọc database của bạn không thể sử dụng. Đổi lại chi phí đó, scrub hàng tuần chỉ giúp cảnh báo sớm hơn tối đa 3 tuần về một lỗi mà bạn vốn không thể sửa chữa. Đánh đổi này chỉ hợp lý khi scrub không tốn nhiều tài nguyên.

Hãy đo thời gian trước rồi quyết định. Chạy một lần scrub thủ công và theo dõi thời gian hoàn tất.

  1. Chạy sudo zpool scrub tank vào một buổi tối ít tải và ghi lại tổng thời gian bắt đầu từ zpool status.
  2. Nếu quá trình hoàn tất trong thời gian thấp hơn nhiều so với 1 giờ và máy gần như rảnh suốt đêm, chạy hàng tuần là mức chi phí chấp nhận được.
  3. Nếu quá trình mất nhiều giờ trong khi pool vẫn đang phục vụ network traffic, hãy giữ lịch hàng tháng và để job do package cung cấp tự quản lý.
  4. Đo lại thời gian mỗi khi pool tăng đáng kể, vì thời lượng scrub phụ thuộc vào lượng dữ liệu đã cấp phát, không phải dung lượng disk.

Dù chọn lịch nào, hãy ghi lại lịch đó cùng với các công việc định kỳ khác trên server. Scrub nên nằm trong cùng danh sách với việc nâng cấp package và xoay vòng log: xem checklist bảo trì server Linux hàng tháng.

Bắt đầu, tạm dừng và dừng scrub

sudo zpool scrub tank
sudo zpool status tank

Tạm dừng và dừng là hai thao tác khác nhau. Chọn sai thao tác có thể khiến bạn phải mất thêm hàng giờ để thực hiện lại.

sudo zpool scrub -p tank
sudo zpool scrub tank
sudo zpool scrub -s tank

-p tạm dừng scrub. Trạng thái và tiến độ tạm dừng được đồng bộ định kỳ xuống disk. Vì vậy, scrub đang tạm dừng vẫn giữ nguyên trạng thái sau khi export hoặc reboot pool: pool hoạt động trở lại nhưng scrub vẫn tạm dừng và chờ bạn. Chạy lại zpool scrub sẽ tiếp tục từ checkpoint gần nhất đã được ghi xuống disk. Ngược lại, -s dừng scrub. Lần scrub tiếp theo sẽ bắt đầu lại từ đầu. Dùng -p khi bạn cần trả disk cho tác vụ khác trong một giờ. Dùng -s khi muốn xóa scrub khỏi trạng thái đang chạy.

Có thêm hai flag đáng biết. -w chờ đến khi scrub hoàn tất rồi mới trả về. Đây là tùy chọn cần dùng trong script để bước tiếp theo không chạy quá sớm. -e chỉ scrub các file có lỗi dữ liệu đã biết, theo thông tin do zpool status -v báo cáo. Đây là cách nhanh để xác nhận file vừa khôi phục từ backup hiện đã sạch.

Mỗi pool chỉ chạy một scrub hoặc resilver tại một thời điểm. Resilver là quá trình rebuild diễn ra sau khi thay một device. Cả hai đều sử dụng I/O nhiều. Nếu một device đang resilver, scrub phải chờ đến lượt.

Cách đọc trạng thái zpool khi scrub đang chạy

Chạy sudo zpool status tank và đọc các con số của chính bạn, không đối chiếu với số liệu của người khác. Trong khi scrub chạy, dòng scan: hiển thị số đã quét, số đã gửi, tổng số, số đã sửa, phần trăm hoàn tất và thời gian còn lại ước tính.

Scanned là giai đoạn xử lý metadata: ZFS duyệt cây block và thu thập các địa chỉ cần đọc. Issued là giai đoạn xử lý dữ liệu: các lệnh đọc thực tế đã gửi đến thiết bị và được sắp xếp theo thứ tự trên disk. Scrub được sắp xếp là lý do có hai bộ đếm, và issued mới là bộ đếm phản ánh tiến độ thực tế. Khi mới bắt đầu, scanned tăng xa hơn nhiều so với issued, nên ước tính thời gian gần như không có ý nghĩa. Hãy đánh giá sau khi hoàn tất 10 phần trăm đầu tiên.

Repaired đếm số byte được ghi lại từ một bản sao còn tốt. Trên pool không có redundancy, giá trị này luôn bằng 0 dù scrub phát hiện gì. Đây là ý trước được thể hiện bằng một con số để bạn theo dõi.

Tiếp theo, đọc các cột của từng thiết bị. READ và WRITE đếm các lỗi I/O do chính thiết bị báo cáo. CKSUM đếm các block không vượt qua bước xác minh checksum, và CKSUM là cột mà scrub tồn tại để cập nhật. CKSUM khác 0 trên một thiết bị có vẻ vẫn khỏe là lỗi thật: dữ liệu đã được trả về, nhưng bị sai.

Dòng cuối cùng là kết luận. errors: No known data errors là trạng thái đạt. Bất kỳ giá trị nào khác đều có nghĩa là phải chạy sudo zpool status -v tank. Lệnh này in toàn bộ danh sách lỗi dữ liệu kể từ lần scrub hoàn tất gần nhất, bao gồm các filename bị ảnh hưởng. Khôi phục những file đó từ backup, chạy sudo zpool clear tank để đặt lại các bộ đếm, rồi scrub lại. Mỗi lần scrub hoàn tất sẽ tạo lại danh sách này, nên filename không còn xuất hiện sau một lần scrub sạch hoàn chỉnh thì thực sự đã hết lỗi.

Job scrub định kỳ nào đang chạy trên máy của bạn?

Đừng giả định máy luôn có một job scrub, hoặc chỉ có một job. Cơ chế này khác nhau tùy nền tảng và package. Định dạng pool giống nhau trên mọi nền tảng, nên dễ quên rằng bộ công cụ đi kèm lại không giống nhau. Cách ZFS được phát hành trên FreeBSD so với Linux là khác biệt quan trọng ở đây.

Trên FreeBSD, job này thuộc hệ thống periodic. Đặt các giá trị sau trong /etc/periodic.conf:

daily_scrub_zfs_enable="YES"
daily_scrub_zfs_pools="tank"
daily_scrub_zfs_default_threshold="35"

daily_scrub_zfs_pools là danh sách tên pool, phân tách bằng dấu cách. Để trống giá trị này sẽ scrub mọi pool. daily_scrub_zfs_default_threshold là số ngày giữa các lần scrub khi không đặt ngưỡng riêng cho từng pool. Manual ghi giá trị mặc định là 35. Job daily chạy mỗi ngày; nó chỉ bắt đầu scrub khi đã vượt ngưỡng.

Trên Linux, cơ chế này phụ thuộc vào package ZFS của distribution. Một số hệ thống có cả hai cơ chế cùng lúc. Có các systemd timer cho từng pool là zfs-scrub-monthly@tank.timerzfs-scrub-weekly@tank.timer; bạn enable từng pool một. Debian và Ubuntu cũng phát hành /etc/cron.d/zfsutils-linux. Job này chạy một script để scrub mọi pool ở trạng thái ONLINE vào Chủ nhật thứ hai của mỗi tháng. Kiểm tra hệ thống đang có gì trước khi thêm cấu hình:

systemctl list-timers 'zfs-*'
ls /etc/cron.d/ | grep -i zfs
sudo zpool history tank | grep scrub

zpool history là câu trả lời chính xác, vì lệnh này ghi lại những lần scrub pool thực sự đã bắt đầu, kèm ngày thực hiện. Nếu scrub chạy 2 lần mỗi tháng, cả hai cơ chế đều đang hoạt động và bạn nên tắt một cơ chế. Để enable một timer:

sudo systemctl enable --now zfs-scrub-monthly@tank.timer

Dung lượng trống quan trọng hơn mọi tunable

Thời gian scrub trên pool nhỏ phụ thuộc vào lượng dữ liệu đã được cấp phát và mức độ phân tán của dữ liệu. Pool càng đầy thì cả hai yếu tố này càng bất lợi.

Khuyến nghị của OpenZFS là giữ dung lượng trống của pool trên 10%. Khi thấp hơn mức này, metaslab, tức các chunk mà allocator sử dụng, bắt đầu vượt ngưỡng trống 4%, và allocator chuyển từ first-fit sang best-fit. best-fit sử dụng CPU nhiều hơn đáng kể. Độ trễ ghi tăng, phân mảnh xuất hiện, và lần scrub tiếp theo còn chậm hơn vì cùng một lượng dữ liệu giờ được đọc thành nhiều lần đọc nhỏ hơn.

Vì vậy, biện pháp đầu tiên không phải là chỉnh tunable. Đó là xóa dữ liệu không cần thiết. Trên máy chạy ZFS, snapshot cũ thường là nguyên nhân chính, tiếp theo là Docker image và layer không còn được prunecác kernel package còn sót lại sau khi upgrade. Chạy zfs list -o space trước khi làm bất kỳ việc gì khác, vì lệnh này phân biệt dung lượng bị snapshot giữ lại với dung lượng đang được dữ liệu hoạt động sử dụng.

Tiếp theo là các tham số, nói ngắn gọn. Trên Linux, bạn có thể đọc các giá trị hiện tại:

cat /sys/module/zfs/parameters/zfs_scrub_min_time_ms
cat /sys/module/zfs/parameters/zfs_vdev_scrub_max_active

FreeBSD cung cấp các tham số tương tự qua sysctl, nên hãy tìm các giá trị của hệ thống bằng sysctl -a | grep scrub. Tăng các giá trị này giúp scrub hoàn tất sớm hơn nhưng làm ứng dụng của bạn chậm hơn. Giảm chúng sẽ cho kết quả ngược lại. Trên pool chỉ có một hoặc hai thiết bị, không có thiết lập nào cho phép đạt cả hai mục tiêu, vì chỉ có một queue để phân chia. Một tunable hiếm khi sửa được vấn đề thiết kế. Nếu scrub hàng tháng gây ảnh hưởng rõ rệt, nguyên nhân thực tế là pool quá đầy hoặc thiết bị quá chậm; tunable chỉ chuyển vấn đề sang chỗ khác.

Thời gian scrub là phép thử trước cho thời gian resilver

Resilver thực hiện cùng kiểu quét như scrub: đọc các block đã cấp phát, xác minh chúng rồi ghi những block bị thiếu vào thiết bị thay thế. Vì vậy, thời gian scrub là phép ước tính thực tế nhất cho thời gian rebuild, cũng như khoảng thời gian pool phải hoạt động với mức dự phòng giảm trong quá trình đó.

ZFS lập lịch công việc resilver tích cực hơn scrub, nên rebuild thường hoàn tất nhanh hơn scrub trên cùng một pool. Hãy xem thời gian scrub là giới hạn trên thận trọng. Nếu scrub mất chín giờ, hãy dự trù thời gian rebuild tương đương và hiểu rằng nếu một thiết bị thứ hai hỏng trong khoảng thời gian đó thì pool sẽ mất. Đây là lý do thực tế để chọn các cặp mirror thay vì một nhóm raidz rộng, vì raidz, layout parity mà ZFS dùng thay cho RAID 5, rebuild bằng cách đọc mọi thiết bị còn hoạt động.

Với pool chỉ có một thiết bị, không có resilver. Thiết bị hỏng thì pool cũng mất. Thời gian khôi phục chính là thời gian restore, vì vậy hãy đo thời gian restore thay thế. Một quy trình restore chưa từng được chạy không phải là kế hoạch khôi phục.

Điều gì thay đổi khi bạn thuê ổ đĩa

Trên VPS, thiết bị block là thiết bị ảo. Hypervisor cung cấp một volume; bên dưới có thể là NVMe cục bộ hoặc một network volume được replicate và có cơ chế parity riêng. Điều này dẫn đến 2 hệ quả đối với việc scrub.

Thứ nhất, cơ chế redundancy của nền tảng không hiển thị với ZFS và ZFS không thể sử dụng nó. Nếu nền tảng sửa lỗi media ở bên dưới, ZFS không bao giờ nhìn thấy lỗi đó. Nếu nền tảng cung cấp lên một block sai, ZFS phát hiện được nhưng không thể sửa, vì bản sao đúng nằm ở phía bên kia của ranh giới đó.

Thứ hai, bạn thường không thể đọc dữ liệu SMART (self-monitoring, analysis and reporting technology) của thiết bị bên dưới một virtual disk. Vì vậy, các cảnh báo sớm mà việc giám sát tình trạng ổ đĩa trên VPS dựa vào có thể hoàn toàn không khả dụng. Bộ đếm CKSUM từ các lần scrub trở thành tín hiệu chính mà bạn có thể kiểm soát.

Nếu muốn ZFS sửa lỗi thay vì chỉ báo cáo, pool cần có nhiều hơn một thiết bị bên trong cùng một instance. Đây là quyết định về plan, không phải vấn đề tuning. Chọn storage VPS thay cho VPS thông thường sẽ cung cấp dung lượng, nhưng việc có 2 thiết bị độc lập hay không còn phụ thuộc vào plan. Chạy lsblk và xác nhận trước khi tạo mirror trên 2 phân vùng mà thực tế chỉ thuộc về một volume. Chúng tôi cho thuê máy chủ Linux và FreeBSD, không cung cấp một ZFS appliance được quản lý. Vì vậy, bạn tự chạy lịch scrub và tự quản lý backup. Đó là sự đánh đổi: bạn toàn quyền kiểm soát pool và cũng hoàn toàn chịu trách nhiệm bảo trì pool.

FAQ

Nên scrub pool ZFS trên VPS bao lâu một lần?

Scrub hằng tháng phù hợp với hầu hết pool nhỏ và cũng khớp với lịch mặc định của các package: cron chạy vào Chủ nhật thứ hai trên Debian và Ubuntu, còn hệ thống periodic của FreeBSD có ngưỡng mặc định là 35 ngày. Chỉ nên scrub hằng tuần sau khi bạn đã đo thời gian chạy và xác nhận nó hoàn tất nhanh trên máy gần như không hoạt động. Với pool bận chỉ có một hoặc hai device, scrub hằng tuần tiêu tốn I/O thực của ứng dụng mỗi tuần nhưng chỉ giúp cảnh báo sớm hơn vài tuần.

Scrub pool ZFS chỉ có một disk có vô ích không?

Không, miễn là bạn hiểu rõ tác dụng của nó. Khi không có redundancy, scrub phát hiện corruption nhưng không thể sửa, ngoại trừ metadata vì ZFS mặc định giữ thêm một bản sao của metadata. Bạn nhận được danh sách có tên các file bị hỏng trong zpool status -v đủ sớm để khôi phục chúng khi vẫn còn một bản sao tốt ở nơi khác. Cách xử lý đúng là cải thiện backup, vì scrub cho biết chính xác file nào cần khôi phục.

Có thể tạm dừng scrub ZFS rồi tiếp tục sau không?

Có. zpool scrub -p tank sẽ tạm dừng scrub. Trạng thái tạm dừng và tiến độ được ghi định kỳ xuống disk, nên scrub vẫn giữ trạng thái tạm dừng sau khi export pool hoặc reboot. Chạy lại zpool scrub tank để tiếp tục từ checkpoint gần nhất. Không dùng zpool scrub -s tank cho việc này: -s dừng scrub, và lần scrub tiếp theo sẽ bắt đầu lại từ đầu.

Vì sao scrub ZFS của tôi quá chậm và có thể tăng tốc không?

Thời gian scrub phụ thuộc vào lượng data đã cấp phát và fragmentation, không phụ thuộc vào dung lượng disk. Pool đầy hơn 90% sẽ chậm vì các metaslab còn dưới 4% dung lượng trống khiến allocator chuyển từ first-fit sang best-fit. Fragmentation phát sinh sau đó biến scrub thành nhiều lần đọc nhỏ. Giải phóng dung lượng thường hiệu quả hơn bất kỳ tunable nào. Bạn có thể tăng zfs_scrub_min_time_ms hoặc zfs_vdev_scrub_max_active để scrub được cấp phần lớn hơn trong queue, nhưng với pool chỉ có một hoặc hai device, phần đó sẽ lấy trực tiếp từ ứng dụng của bạn.