SSD Nodes Learn Hosting plans →
คู่มือ Matt Connorโดย Matt Connor · อัปเดตเมื่อ 2026-08-28

การใช้งาน ZFS บน VPS: จัดการ RAM และ ARC อย่างไรให้คุ้มค่า

ZFS มอบฟีเจอร์ checksum และ snapshot ที่ยอดเยี่ยม แต่ ARC มักกิน RAM จนหมดบน VPS ขนาดเล็ก เรียนรู้วิธีปรับแต่งค่า zfs_arc_max เพื่อรักษาเสถียรภาพของแอปพลิเคชัน

สิ่งที่ ZFS มอบให้และสิ่งที่ต้องแลก

ปัจจุบัน ZFS บน FreeBSD และ Linux ใช้ codebase เดียวกันคือ OpenZFS ดังนั้นฟีเจอร์ต่างๆ จึงเหมือนกันทั้งสองระบบ เซิร์ฟเวอร์ที่รัน ZFS จะได้รับประโยชน์จากการตรวจสอบ checksum ของข้อมูล, การทำ snapshot ที่ไม่กินพื้นที่จนกว่าข้อมูลจะมีการเปลี่ยนแปลง, การทำ replication ด้วย zfs send และการบีบอัดข้อมูลที่เปิดใช้งานได้เพียงแค่ตั้งค่า property เดียว สิ่งที่ต้องแลกคือหน่วยความจำ: โดยค่าเริ่มต้น ARC (adaptive replacement cache) จะจอง RAM จำนวนมากไว้ และบน VPS (virtual private server) ขนาด 2 GB หรือ 4 GB หน่วยความจำส่วนนั้นคือสิ่งที่แอปพลิเคชันของคุณต้องการใช้งาน

คู่มือนี้ประเมิน ZFS จากมุมมองของ VPS ที่เช่าใช้งานซึ่งมีดิสก์เสมือนเพียงหนึ่งหรือสองลูก ไม่ใช่จากตู้เก็บข้อมูลที่มีช่องใส่ไดรฟ์ถึงสี่สิบช่อง ฟีเจอร์ที่ยังคงมีประโยชน์ในสภาพแวดล้อมนี้คือสิ่งที่คุณควรให้ความสำคัญ ส่วนฟีเจอร์ที่ไม่เหมาะกับการใช้งานในลักษณะนี้คือสิ่งที่คุณควรทราบก่อนเริ่มสร้าง pool

OpenZFS บน FreeBSD และ Linux: โค้ดเบสเดียวกัน แต่การจัดการแพ็กเกจต่างกัน

FreeBSD ได้รวม ZFS ไว้ในระบบพื้นฐานมาตั้งแต่ FreeBSD 7.0 ในปี 2008 โดยเริ่มแรกเป็นฟีเจอร์ทดลอง นับตั้งแต่ OpenZFS 2.0 ในเดือนธันวาคม 2020 ทั้ง FreeBSD และ Linux ได้ใช้ซอร์สโค้ดชุดเดียวกันในการ build ดังนั้น zfs และ zpool จึงทำงานเหมือนกันบนทั้งสองระบบ และ pool ที่สร้างบนระบบหนึ่งสามารถนำไป import บนอีกระบบหนึ่งได้

สาเหตุที่ ZFS เป็นแพ็กเกจบน Linux แต่เป็นส่วนหนึ่งของระบบพื้นฐานบน FreeBSD คือเรื่องลิขสิทธิ์ OpenZFS อยู่ภายใต้สัญญาอนุญาต CDDL (Common Development and Distribution License) ในขณะที่ Linux kernel อยู่ภายใต้ GPL (General Public License) เวอร์ชัน 2 โครงการ kernel มองว่าสัญญาอนุญาตทั้งสองไม่สามารถใช้งานร่วมกันได้ โค้ดของ ZFS จึงไม่ถูกรวมเข้ากับ mainline Linux และแต่ละ distribution จึงต้องตัดสินใจเองว่าจะจัดการอย่างไร FreeBSD ไม่มีข้อขัดแย้งดังกล่าว ZFS จึงถูกรวมไว้ในระบบโดยตรง นี่คือเรื่องราวทั้งหมดในทางปฏิบัติ: มีความแตกต่างเพียงเรื่องการจัดการแพ็กเกจเท่านั้น และคุณไม่จำเป็นต้องเลือกข้างแต่อย่างใด

SSD Nodes ไม่มีอิมเมจ FreeBSD ให้บริการ ดังนั้นบนเซิร์ฟเวอร์ที่เช่าจากที่นี่ ส่วนของ Linux ในคู่มือนี้จึงเป็นสิ่งที่นำไปใช้ได้จริง หากคุณใช้งาน FreeBSD ที่อื่น เซิร์ฟเวอร์ FreeBSD จะมาพร้อมกับ ZFS โดยที่คุณไม่ต้อง build โมดูลเองและไม่ต้องกังวลเรื่องการอัปเกรด kernel แล้วระบบจะพัง

การติดตั้ง ZFS และการสร้าง pool

บน Ubuntu โมดูลจะรวมอยู่ในแพ็กเกจ kernel อยู่แล้ว คุณจึงเพียงแค่ติดตั้งชุดคำสั่งเท่านั้น

sudo apt update
sudo apt install -y zfsutils-linux
zfs version

zfs version จะแสดงผลลัพธ์สองบรรทัด คือเวอร์ชันของ userland และเวอร์ชันของ kernel module หากแสดงเพียงบรรทัดเดียว หมายความว่าโมดูลไม่ได้ถูกโหลด แพ็กเกจนี้อยู่ในคอมโพเนนต์ universe ซึ่ง Ubuntu server images เปิดใช้งานไว้เป็นค่าเริ่มต้น หาก apt หาไม่พบ ให้รัน sudo add-apt-repository universe ก่อน

บน Debian แพ็กเกจจะอยู่ในคอมโพเนนต์ contrib และโมดูลจะถูก build บนเครื่องของคุณโดยใช้ DKMS (dynamic kernel module support) ให้เพิ่ม contrib ต่อท้ายบรรทัด Components: ในไฟล์ /etc/apt/sources.list.d/debian.sources จากนั้นรัน sudo apt update แล้วดำเนินการต่อดังนี้:

sudo apt install -y linux-headers-$(dpkg --print-architecture) zfs-dkms zfsutils-linux

การติดตั้งจะทำการคอมไพล์โมดูลและแสดงข้อความ Building initial module for 6.12.0-... ซึ่งอาจใช้เวลาสองสามนาที โปรดจำไว้ว่าทุกครั้งที่มีการอัปเกรด kernel ระบบจะทำการ build ใหม่ หากการ build ล้มเหลว คุณจะไม่สามารถ mount pool ได้จนกว่าจะแก้ไขให้เรียบร้อย

บน FreeBSD ไม่จำเป็นต้องติดตั้งอะไรเพิ่มเติม เพียงเปิดใช้งาน service และเริ่มการทำงาน:

sysrc zfs_enable=YES
service zfs start

ขั้นตอนถัดไปคือการสร้าง pool ให้ตรวจสอบ path ของอุปกรณ์ที่เสถียรก่อน เพราะ /dev/vdb จะถูกกำหนดตามลำดับการตรวจพบ ซึ่งอาจเปลี่ยนแปลงได้เมื่อคุณเชื่อมต่อ volume อื่นเพิ่ม

ls -l /dev/disk/by-id/
sudo zpool create -o ashift=12 tank /dev/disk/by-id/virtio-abc123def456
zpool status tank

zpool status ควรแสดงผลลัพธ์เป็น state: ONLINE โดยมีอุปกรณ์ของคุณปรากฏอยู่ภายใต้ tank คำสั่ง ashift=12 จะกำหนดขนาดบล็อกที่เล็กที่สุดของ pool ไว้ที่ 4 KiB ซึ่งสอดคล้องกับ SSD ในปัจจุบันและไม่สามารถเปลี่ยนแปลงได้หลังจากสร้าง pool ไปแล้ว

Image ของเซิร์ฟเวอร์เช่าส่วนใหญ่จะบูตจาก root ที่เป็น ext4 ดังนั้น ZFS ในที่นี้จึงเป็นเพียง data pool บน volume ที่สอง ไม่ใช่ root filesystem ให้ตรวจสอบให้แน่ใจว่าอุปกรณ์นั้นถูกต้องก่อนเริ่มสร้าง เพราะ การยืนยัน NVMe disk ที่คุณได้รับ ใช้เวลาเพียงหนึ่งนาที แต่การสร้างใหม่ทั้งหมดอาจต้องใช้เวลาทั้งบ่าย

Checksum จะซ่อมแซมได้ก็ต่อเมื่อ pool มีความซ้ำซ้อน (redundancy)

ทุกบล็อกข้อมูลที่ ZFS เขียนลงไปจะมี checksum กำกับไว้ และทุกครั้งที่มีการอ่าน ข้อมูลจะถูกตรวจสอบเสมอ การตรวจพบข้อผิดพลาดทำได้ตลอดเวลา แต่การซ่อมแซมจำเป็นต้องมีสำเนาชุดที่สอง

ใน pool ที่มีดิสก์เพียงลูกเดียว ZFS จะแจ้งความจริงให้คุณทราบและหยุดการทำงานเพียงแค่นั้น zpool status -v จะรายงานผลในลักษณะนี้:

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.tar

ไฟล์ที่เสียหายจะถูกระบุชื่อออกมา หากเป็น ext4 ระบบจะส่งคืนข้อมูลที่เสียหายนั้นให้คุณโดยไม่มีการแจ้งเตือนใดๆ ดังนั้นการที่ ZFS แจ้งเตือนจึงถือว่ามีประโยชน์มาก อย่างไรก็ตาม ZFS ยังคงไม่สามารถแก้ไขไฟล์นั้นได้ เนื่องจากไม่มีสำเนาชุดที่สองใน pool ให้ใช้สำหรับซ่อมแซม

ในกรณีที่เป็น mirror การอ่านข้อมูลจะถูกดึงมาจากฝั่งที่ปกติ บล็อกที่เสียหายจะถูกเขียนทับใหม่ และเหตุการณ์ดังกล่าวจะปรากฏในคอลัมน์ CKSUM ของ zpool status นี่คือกระบวนการซ่อมแซมตัวเอง (self-healing) ซึ่งจำเป็นต้องใช้อุปกรณ์จัดเก็บข้อมูลสองตัว

sudo zpool create -o ashift=12 tank mirror /dev/disk/by-id/DISK1 /dev/disk/by-id/DISK2

บน VPS พื้นที่จัดเก็บข้อมูลของโฮสต์มักจะมีความซ้ำซ้อนอยู่แล้ว โดยส่วนใหญ่มักเป็น RAID 10 ภายใต้ hypervisor ซึ่งช่วยป้องกันคุณจากกรณีดิสก์เสีย แต่ระบบจะไม่แจ้งให้คุณทราบเมื่อข้อมูลที่อ่านกลับมามีความผิดพลาด เนื่องจากตัว array ไม่มีทางทราบได้ว่าสำเนาชุดใดถูกต้อง แต่ ZFS ทราบเพราะมีการเปรียบเทียบข้อมูลกับ checksum ที่เขียนไว้ด้วยตัวเอง

หากคุณมี virtual disk เพียงลูกเดียวและต้องการความสามารถในการซ่อมแซม sudo zfs set copies=2 tank/important จะจัดเก็บสำเนาของทุกบล็อกใน dataset นั้นไว้สองชุดบนดิสก์ลูกเดียวกัน วิธีนี้จะทำให้พื้นที่ที่ใช้สำหรับ dataset นั้นเพิ่มขึ้นเป็นสองเท่า ช่วยให้รอดพ้นจากกรณีบล็อกข้อมูลเสียหาย แต่จะไม่ช่วยอะไรหาก volume ทั้งหมดหายไป

การทำ scrub คือการอ่านข้อมูลทั้งหมดใน pool เพื่อตรวจสอบความถูกต้อง

sudo zpool scrub tank
zpool status tank

pool ที่อยู่ในสถานะปกติจะจบด้วยบรรทัดลักษณะเดียวกับ scan: scrub repaired 0B in 00:04:11 with 0 errors ควรตั้งตารางเวลาสำหรับการทำ scrub ไว้ โดยรายเดือนถือว่าเหมาะสมสำหรับ pool ขนาดเล็ก

systemctl list-unit-files 'zfs-scrub*'
sudo systemctl enable --now zfs-scrub-monthly@tank.timer

Dataset คือหน่วยของการกำหนดนโยบาย

Dataset คือระบบไฟล์ภายใน pool และการสร้าง dataset นั้นทำได้ง่ายและประหยัดทรัพยากร จึงควรสร้างแยกตามงานแต่ละอย่าง คุณสมบัติต่างๆ จะถูกสืบทอดลงมาจาก pool ซึ่งหมายความว่าคุณตั้งค่าเริ่มต้นเพียงครั้งเดียวและกำหนดค่าทับเฉพาะจุดที่จำเป็น บน FreeBSD นี่คือวิธีที่ใช้รัน jails โดยทั่วไป คือใช้หนึ่ง dataset ต่อหนึ่ง jail เพื่อให้สามารถทำ snapshot และย้อนกลับเฉพาะ jail นั้นๆ ได้ ซึ่งเป็นส่วนหนึ่งของ สิ่งที่ทำให้ jail แตกต่างจาก 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 tank

Compression เป็นคุณสมบัติที่ผู้คนมักละเลยด้วยความระมัดระวัง ซึ่งเป็นความเข้าใจที่ผิด lz4 ใช้ CPU เพียงเล็กน้อยและลดจำนวนไบต์ที่ต้องเขียนลงดิสก์ ดังนั้นสำหรับข้อมูลที่บีบอัดได้ การตั้งค่านี้มักจะทำให้การอ่านและเขียนเร็วขึ้น zstd จะบีบอัดข้อมูลได้แน่นกว่าโดยแลกกับ CPU ที่สูงขึ้น ซึ่งเหมาะสำหรับไฟล์ log และไฟล์เก็บถาวรที่คุณไม่ค่อยได้เปิดอ่าน ตรวจสอบผลลัพธ์จริงด้วย zfs get compressratio tank และโปรดจำไว้ว่าอัตราส่วนการบีบอัดจะนับเฉพาะข้อมูลที่เขียนหลังจากตั้งค่าคุณสมบัตินี้แล้วเท่านั้น

recordsize คือขนาดบล็อกที่ใหญ่ที่สุดที่ dataset จะเขียน โดยค่าเริ่มต้นคือ 128K หากฐานข้อมูลเขียนหน้าข้อมูลขนาด 8 KiB ลงใน record ขนาด 128 KiB จะทำให้การเขียนขนาดเล็กหนึ่งครั้งกลายเป็นการอ่าน record ทั้งหมด การแก้ไขข้อมูล และการเขียนกลับลงไปใหม่ ให้ตั้งค่า recordsize=16K บน dataset ของฐานข้อมูลก่อนที่คุณจะโหลดข้อมูลเข้าไป เพราะคุณสมบัตินี้จะมีผลกับบล็อกที่เขียนใหม่เท่านั้น

quota คือวิธีที่คุณใช้ป้องกันไม่ให้ dataset ใด dataset หนึ่งใช้พื้นที่จนเต็ม pool หาก ZFS pool มีพื้นที่ใกล้เต็ม 100% จะทำงานช้าลงและจัดการพื้นที่คืนได้ยาก ดังนั้นควรเผื่อพื้นที่ว่างไว้โดยเจตนา

Snapshot ไม่มีค่าใช้จ่ายจนกว่าข้อมูลจะมีการเปลี่ยนแปลง

ZFS จะไม่เขียนทับบล็อกข้อมูลที่ใช้งานอยู่จริง แต่จะใช้วิธีเขียนบล็อกใหม่แล้วอัปเดตตัวชี้ตำแหน่ง (pointer) ซึ่งเป็นหลักการของ copy-on-write โดย Snapshot คือบันทึกที่ระบุว่า "ให้เก็บรักษาบล็อกข้อมูลที่ dataset นี้ชี้อยู่ ณ ขณะนี้ไว้" การสร้าง Snapshot จึงทำได้ทันทีและไม่มีค่าใช้จ่าย

sudo zfs snapshot tank/data@2026-08-11
zfs list -t snapshot -o name,used,refer -r tank/data

คอลัมน์ USED ของ Snapshot คือพื้นที่ที่ถูกจองไว้โดย Snapshot นั้นเพียงอย่างเดียว โดยจะเริ่มต้นที่ใกล้ศูนย์และเพิ่มขึ้นเมื่อมีการแก้ไขหรือลบข้อมูล เนื่องจากบล็อกข้อมูลเดิมไม่สามารถถูกปล่อยคืนพื้นที่ได้อีกต่อไป

การกู้คืนไฟล์ไม่จำเป็นต้องมีขั้นตอน restore

ls /tank/data/.zfs/snapshot/
cp /tank/data/.zfs/snapshot/2026-08-11/notes.txt /tank/data/notes.txt

ไดเรกทอรี .zfs จะถูกซ่อนไว้แม้กระทั่งจาก ls -a จนกว่าคุณจะรันคำสั่ง sudo zfs set snapdir=visible tank/data ควรสร้าง Snapshot ไว้ก่อนที่จะจำเป็นต้องใช้ เพราะหากไม่มี Snapshot การเผลอใช้คำสั่ง rm -rf จะทำให้คุณต้องเข้าสู่ เส้นทางการกู้คืนข้อมูลของ ext4 ซึ่งเริ่มต้นด้วยการ unmount ดิสก์และสถานการณ์จะเลวร้ายลงหลังจากนั้น

การ Rollback จะทิ้งข้อมูลทุกอย่างที่ถูกเขียนขึ้นหลังจาก Snapshot นั้น

sudo zfs rollback tank/data@2026-08-11

ระบบจะปฏิเสธการทำงานหากมี Snapshot ที่ใหม่กว่าอยู่ และการใช้ -r จะเป็นการทำลาย Snapshot ที่ใหม่กว่าเหล่านั้นเพื่อดำเนินการต่อ โปรดตรวจสอบชื่อ dataset ให้ถี่ถ้วนก่อนกด Enter

Snapshot ไม่ใช่การสำรองข้อมูล (Backup) เพราะมันอยู่ใน pool เดียวกัน บน volume เดียวกัน และบนเซิร์ฟเวอร์เดียวกัน หาก volume เสียหายหรือเกิดเหตุ zpool destroy ข้อมูลใน Snapshot ก็จะสูญหายไปพร้อมกับข้อมูลหลัก Snapshot ช่วยป้องกันความผิดพลาดจากตัวคุณเอง (rm) และการอัปเกรดที่ล้มเหลว ซึ่งครอบคลุมเหตุการณ์จริงส่วนใหญ่ แต่ไม่สามารถป้องกันความเสียหายที่เกิดขึ้นกับตัว pool เองได้ รายละเอียดทั้งหมดระบุไว้ที่นี่: เหตุผลที่ VPS snapshot ไม่ใช่การสำรองข้อมูล

การส่งและรับข้อมูล: การทำ replication ด้วยคำสั่งเดียว

zfs send จะเปลี่ยน snapshot ให้เป็น byte stream บน standard output และ zfs receive จะเปลี่ยน stream นั้นกลับมาเป็น dataset การคัดลอกครั้งแรกจะเป็นการส่งแบบเต็ม (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"

หลังจากนั้น ให้ส่งเฉพาะส่วนที่มีการเปลี่ยนแปลงระหว่าง 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"

ฝั่งรับจะต้องมี snapshot ที่คุณใช้เป็นจุดเริ่มต้นในการส่งอยู่ หากไม่มี การรับข้อมูลจะหยุดลงพร้อมกับ cannot receive incremental stream: most recent snapshot of backup/data does not match incremental source เนื่องจาก ZFS ไม่มีฐานข้อมูลอ้างอิงเพื่อนำส่วนต่างไปปรับใช้ ให้ส่งจาก snapshot ที่ทั้งสองฝั่งมีเหมือนกัน หรือเริ่มการส่งแบบเต็มใหม่อีกครั้ง

กำหนดสิทธิ์บนฝั่งปลายทางแทนการใช้ root จากระยะไกลด้วยคำสั่ง: sudo zfs allow -u backupuser create,mount,receive backup/data

นี่คือการสำรองข้อมูลนอกสถานที่ (off-site backup) ที่แท้จริงโดยมีเงื่อนไขเดียว คือฝั่งปลายทางต้องเป็น ZFS pool เนื่องจาก object storage ไม่สามารถรับ stream ได้ หากปลายทางของคุณเป็น storage ที่รองรับ S3 หรือโฮสต์ Linux ทั่วไป ให้ใช้เครื่องมือที่สื่อสารกับปลายทางนั้นได้ โดย การสำรองข้อมูลด้วย restic จาก VPS จะครอบคลุมแนวทางดังกล่าว

ทำไม ZFS ถึงใช้ RAM มาก? ARC

ARC (adaptive replacement cache) คือแคชสำหรับการอ่านของ ZFS ซึ่งทำงานอยู่ในหน่วยความจำเคอร์เนลแทนที่จะเป็น page cache ปกติของ Linux ดังนั้น free -h จึงไม่รายงานส่วนนี้ภายใต้ buff/cache แต่จะแสดงเป็นหน่วยความจำที่ถูกใช้งานอยู่ เครื่องที่ใช้ ZFS ซึ่งดูเหมือน RAM เต็มเกือบตลอดเวลามักเป็นเพราะมีแคชที่พร้อมใช้งาน (warm cache) ซึ่งเป็นสาเหตุส่วนใหญ่ของรายงานที่ว่า "ZFS กิน RAM ของฉัน"

ค่าจำกัดเริ่มต้นถูกตั้งไว้สูงโดยเจตนา OpenZFS 2.3 กำหนดขนาด ARC สูงสุดไว้ที่ค่าที่มากกว่าระหว่าง RAM ลบด้วย 1 GiB หรือ 5/8 ของ RAM ทั้งหมด ส่วน OpenZFS 2.2 และเวอร์ชันก่อนหน้าบน Linux จะใช้ค่าครึ่งหนึ่งของ RAM ในขณะที่ FreeBSD ใช้กฎใหม่นี้มานานแล้ว ให้รัน zfs version เพื่อดูว่าระบบของคุณใช้กฎใด

ChartDefault maximum ARC size by instance RAM, from the OpenZFS default rule (GiB)
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
  }
]

ตัวเลขเหล่านี้เป็นกฎเริ่มต้นตามเอกสารที่ใช้กับขนาด instance ทั่วไป ไม่ใช่การวัดค่าจากเครื่องที่กำลังทำงานอยู่ บน instance ขนาด 4 GB กฎของเวอร์ชัน 2.3 อนุญาตให้ ARC มีขนาดได้ 3 GiB ในขณะที่เครื่องเดียวกันบนเวอร์ชัน 2.2 จะจำกัดไว้ที่ 2 GiB สำหรับ instance ขนาด 2 GB กฎของเวอร์ชัน 2.3 ยังคงอนุญาตให้ใช้ได้ 1.25 GiB ส่วนที่เหลือจึงจะเป็นพื้นที่สำหรับแอปพลิเคชันของคุณ

ให้ตรวจสอบตัวเลขจริงจากเซิร์ฟเวอร์ของคุณเองแทนการเชื่อตาราง:

grep -E '^(size|c_max) ' /proc/spl/kstat/zfs/arcstats
arc_summary | head -n 20

คอลัมน์ที่สามคือหน่วยเป็นไบต์ c_max คือเพดานสูงสุดที่บังคับใช้อยู่ในขณะนี้ และ size คือขนาดที่ ARC ใช้งานจริงในปัจจุบัน

ARC สามารถคืนหน่วยความจำได้ เมื่อเคอร์เนลส่งสัญญาณว่ามีแรงกดดันด้านหน่วยความจำ ARC จะลดขนาดลง ปัญหาคือเรื่องของจังหวะเวลา เพราะการลดขนาดจะเกิดขึ้นก็ต่อเมื่อมีแรงกดดันนั้น ดังนั้นกระบวนการที่ต้องการหน่วยความจำหลายร้อย MiB ในคราวเดียวอาจถูก OOM (out of memory) killer จัดการก่อนที่ ARC จะคืนหน่วยความจำเสร็จ บนเครื่องขนาด 2 GB ที่รันฐานข้อมูลและเว็บเซิร์ฟเวอร์ เหตุการณ์นี้ไม่ใช่เรื่องแปลก คู่มือของ OpenZFS ระบุไว้เช่นเดียวกันเกี่ยวกับการปรับค่าด้วยตนเองว่า การลดค่าจำกัด "จะไม่ทำให้ ARC ลดขนาดลงหากไม่มีแรงกดดันด้านหน่วยความจำมากระตุ้นให้เกิดการลดขนาด"

วิธีการจำกัดขนาด ARC บน VPS ขนาดเล็ก

ให้ตัดสินใจเรื่องปริมาณหน่วยความจำสำหรับภาระงานก่อน โดยรวมความต้องการของฐานข้อมูลและแอปพลิเคชันเข้าด้วยกัน เผื่อพื้นที่สำหรับระบบปฏิบัติการไว้เล็กน้อย แล้วจึงจัดสรรส่วนที่เหลือให้กับ ARC สำหรับอินสแตนซ์ขนาด 4 GB ที่รัน Postgres และเว็บแอปพลิเคชันหนึ่งตัว การกำหนด ARC ไว้ที่ 512 MiB ถึง 1 GiB ถือเป็นจุดเริ่มต้นที่เหมาะสม

กำหนดค่าแบบสดโดยใช้หน่วยเป็นไบต์ ตัวอย่างนี้คือ 1 GiB

echo 1073741824 | sudo tee /sys/module/zfs/parameters/zfs_arc_max

ทำให้การตั้งค่าคงอยู่หลังการรีบูต

echo 'options zfs zfs_arc_max=1073741824' | sudo tee /etc/modprobe.d/zfs.conf
sudo update-initramfs -u

ขั้นตอนการทำ initramfs มีความสำคัญเนื่องจากโมดูลอาจโหลดจาก initramfs ก่อนที่ระบบไฟล์ root จะถูก mount ซึ่งหมายความว่าระบบจะไม่อ่านไฟล์ที่คุณเพิ่งเขียนลงไป หลังจากรีบูตแล้ว ให้ตรวจสอบด้วยบรรทัด c_max จาก arcstats

มีข้อควรระวังสองประการจากคู่มือการใช้งาน คุณไม่สามารถตั้งค่ากลับเป็น 0 ในขณะที่ระบบกำลังทำงาน ดังนั้นการยกเลิกการตั้งค่านี้ต้องทำโดยการแก้ไขไฟล์และรีบูตเครื่อง และการลดตัวเลขลงจะไม่ทำให้ ARC ที่มีขนาดใหญ่ลดลงในทันที

บน FreeBSD การจำกัดค่านี้จะใช้ sysctl ภายใต้ vfs.zfs.arc ให้รัน sysctl vfs.zfs.arc เพื่อดูค่าปัจจุบันและชื่อที่ถูกต้องซึ่งเวอร์ชันของคุณใช้งานอยู่ จากนั้นจึงเขียนค่าสูงสุดลงใน /boot/loader.conf

กฎเพิ่มเติมอีกสองข้อสำหรับหน่วยความจำบนเซิร์ฟเวอร์ขนาดเล็ก คือให้ปิดการใช้งาน deduplication เนื่องจากตาราง dedup จะอยู่ในหน่วยความจำ โดยกฎทั่วไปที่ยอมรับกันคือต้องใช้ RAM 1 ถึง 3 GB ต่อข้อมูลที่ไม่ซ้ำกัน 1 TB และห้ามทำ swap บน zvol (อุปกรณ์บล็อกที่แบ่งออกมาจาก pool) เพราะการทำ swap ผ่านระบบไฟล์ที่กำลังพยายามคืนหน่วยความจำอาจทำให้เครื่องค้าง (deadlock) ได้ ให้เก็บ swap ไว้บน partition ปกติหรือ swap file ที่อยู่นอก pool แทน

เมื่อ ext4 หรือ XFS ร่วมกับ restic เป็นทางเลือกที่ดีกว่า

ZFS จะคุ้มค่าเมื่อใช้งานบนเซิร์ฟเวอร์ที่มีหน่วยความจำเหลือเฟือและมีดิสก์ลูกที่สอง นอกเหนือจากกรณีนั้น การใช้ระบบไฟล์ทั่วไปร่วมกับเครื่องมือสำรองข้อมูลที่แท้จริงจะให้ผลลัพธ์ที่ดีกว่า เลือกใช้ ext4 หรือ XFS เมื่อ:

  • อินสแตนซ์มี RAM ขนาด 2 GB หรือ 4 GB และภาระงานต้องการใช้หน่วยความจำทั้งหมดนั้น
  • มีดิสก์เสมือนเพียงลูกเดียวและไม่มีสำเนาที่สอง ดังนั้น ZFS จะทำได้เพียงตรวจพบข้อผิดพลาดแต่ไม่สามารถซ่อมแซมได้
  • ปลายทางการสำรองข้อมูลของคุณคือ object storage หรือโฮสต์ Linux ทั่วไป ซึ่งไม่มีที่ใดสามารถรับสตรีม zfs send ได้
  • คุณใช้งาน Debian ร่วมกับ DKMS และไม่สามารถรับความเสี่ยงจากการอัปเกรดเคอร์เนลที่อาจทำให้โมดูลไม่ถูกคอมไพล์
  • คุณต้องการใช้ ZFS บนระบบไฟล์ root แต่ image ของผู้ให้บริการมีให้เลือกเพียง ext4 เท่านั้น

ให้คงการใช้งาน ZFS ไว้เมื่อคุณมีโวลุ่มข้อมูลแยกต่างหาก มี RAM เหลือเฟือ (ขนาด 8 GB ขึ้นไปถือว่าเหมาะสม) และมีแผนการใช้งาน snapshot และ zfs send ที่ชัดเจนมากกว่าแค่การเปิดใช้งานทิ้งไว้ สำหรับกรณีอื่นทั้งหมด การใช้ ext4 ร่วมกับ restic เพื่อเขียนข้อมูลสำรองที่เข้ารหัสและทำ deduplication ไปยังพื้นที่จัดเก็บที่เซิร์ฟเวอร์ไม่ได้ควบคุม จะให้ผลลัพธ์ที่ครอบคลุมในลักษณะเดียวกันโดยไม่กินทรัพยากรหน่วยความจำเลย

รูปแบบความล้มเหลวและข้อความที่คุณจะพบ

Pool หายไปหลังจากรีบูต zpool status จะแสดงผลเป็น no pools available บริการ import จะอ่านค่าจาก /etc/zfs/zpool.cache ดังนั้นหากไม่มีชื่อ pool ในไฟล์ดังกล่าว ระบบจะไม่ทำการ import pool นั้นโดยอัตโนมัติเมื่อบูตเครื่อง sudo zpool import จะแสดงรายการ pool ที่สามารถ import ได้ sudo zpool import tank ใช้สำหรับนำ pool กลับมาใช้งาน และ sudo zpool set cachefile=/etc/zfs/zpool.cache tank ใช้เพื่อบันทึกการตั้งค่าให้คงอยู่ถาวร หาก pool ไม่ได้ถูก export อย่างถูกต้องจากระบบอื่น ระบบจะแจ้งเตือน cannot import 'tank': pool may be in use from other system และ sudo zpool import -f tank จะใช้เพื่อข้ามการตรวจสอบดังกล่าวเมื่อคุณมั่นใจแล้วว่าไม่มีโฮสต์อื่นใช้งาน pool นั้นอยู่

modprobe: FATAL: Module zfs not found in directory /lib/modules/6.12.0-... บน Debian หลังจากอัปเกรด kernel สาเหตุเกิดจาก DKMS ไม่ได้ build โมดูลสำหรับ kernel ใหม่ ซึ่งมักเป็นเพราะไม่ได้ติดตั้ง header ที่ตรงกัน dkms status จะแสดงรายการสิ่งที่ถูก build ไว้สำหรับแต่ละ kernel ให้ใช้ sudo apt install -y linux-headers-$(uname -r) ตามด้วย sudo dkms autoinstall เพื่อ build ใหม่ จากนั้นใช้ sudo zpool import tank เพื่อนำ pool กลับมาใช้งาน

Pool เต็มทั้งที่ลบไฟล์ไปแล้ว ข้อมูลที่ถูกลบจะยังคงอยู่บนดิสก์ตราบใดที่ยังมี snapshot อ้างอิงถึงข้อมูลนั้นอยู่ ทำให้ค่าที่แสดงใน du และ df ไม่ตรงกัน zfs list -o space -r tank จะแยกการใช้งานออกเป็น USEDDS และ USEDSNAP หากค่า USEDSNAP สูง นั่นคือสาเหตุของปัญหา ให้ลบ snapshot เก่าทิ้งด้วย sudo zfs destroy tank/data@2026-06-01 แล้วพื้นที่ว่างจะกลับคืนมา

ค่า CKSUM เพิ่มขึ้นใน zpool status มีบางอย่างในระดับที่ต่ำกว่า ZFS ส่งข้อมูลที่ผิดพลาดกลับมา ในกรณีที่เป็น mirror ค่านี้จะเป็นเพียงคำเตือนและบล็อกข้อมูลนั้นได้รับการซ่อมแซมแล้ว แต่หากเป็น pool ที่มีดิสก์ลูกเดียว ไฟล์นั้นจะสูญหาย ให้ใช้ zpool status -v เพื่อระบุชื่อไฟล์ดังกล่าว แล้วทำการกู้คืนไฟล์นั้นจากข้อมูลสำรองที่ไม่ได้เก็บไว้ใน pool นี้

เซิร์ฟเวอร์ทำงานช้าและมีการทำ swapping ให้จำกัดขนาด ARC ตามที่ระบุไว้ข้างต้น จากนั้นรัน arc_summary เพื่อตรวจสอบอัตรา hit ratio หาก ARC มีขนาดเล็กเกินกว่าจะเก็บ working set ได้ จะทำให้การอ่านทุกครั้งต้องไปที่ดิสก์ ซึ่งในจุดนี้การใช้ระบบไฟล์ทั่วไปที่อาศัย page cache จะให้ประสิทธิภาพที่ดีกว่า

FAQ

ZFS ต้องการ RAM เท่าไรบน VPS?

ZFS สามารถทำงานบนอินสแตนซ์ขนาด 2 GB ได้ คำถามที่สำคัญกว่าคือเหลือ RAM เท่าไรสำหรับแอปพลิเคชันของคุณ หากไม่มีการปรับแต่ง OpenZFS 2.3 จะอนุญาตให้ ARC ขยายขนาดได้สูงสุดระหว่าง RAM ลบด้วย 1 GiB กับ 5/8 ของ RAM ทั้งหมด ดังนั้นเซิร์ฟเวอร์ขนาด 4 GB จึงอาจจัดสรร RAM ให้กับแคชได้ถึง 3 GiB ให้ตั้งค่า zfs_arc_max เป็นตัวเลขที่เหมาะสมกับภาระงานของคุณ จากนั้นตรวจสอบความถูกต้องโดยอ่านบรรทัด c_max จาก /proc/spl/kstat/zfs/arcstats

ZFS snapshot ถือเป็นข้อมูลสำรองหรือไม่?

ไม่ถือเป็นข้อมูลสำรอง Snapshot จะอยู่ใน pool เดียวกับข้อมูลต้นฉบับ มันช่วยป้องกันความเสียหายจาก rm และการอัปเกรดที่ล้มเหลวได้ แต่หาก pool หรืออินสแตนซ์เสียหาย ข้อมูล snapshot ก็จะสูญหายไปด้วย การจะทำให้เป็นข้อมูลสำรอง คุณต้องส่ง snapshot ไปยังเครื่องอื่นด้วย zfs send หรือใช้เครื่องมือสำรองข้อมูลที่เขียนข้อมูลลงในพื้นที่จัดเก็บที่เซิร์ฟเวอร์นี้ไม่ได้เป็นผู้ควบคุม

ZFS ทำงานเหมือนกันบน FreeBSD และ Linux หรือไม่?

ใช้ codebase เดียวกันตั้งแต่ OpenZFS 2.0 ในเดือนธันวาคม 2020 ใช้คำสั่งเดียวกัน รูปแบบข้อมูลบนดิสก์เหมือนกัน และสามารถย้าย pool ระหว่างกันได้ ความแตกต่างอยู่ที่การจัดการแพ็กเกจ FreeBSD รวม ZFS มาในระบบพื้นฐาน ส่วนบน Linux แต่ละ distribution จะตัดสินใจเอง เช่น Ubuntu จะ build โมดูลมาพร้อมกับแพ็กเกจ kernel ในขณะที่ Debian จะ build โมดูลบนเครื่องของคุณด้วย DKMS ดังนั้นการอัปเกรด kernel อาจทำให้คุณไม่มีโมดูลใช้งานจนกว่าการ build ใหม่จะสำเร็จ

ZFS สามารถซ่อมแซมข้อมูลที่เสียหายบน VPS ที่มีดิสก์ลูกเดียวได้หรือไม่?

ZFS สามารถตรวจพบความเสียหายและระบุชื่อไฟล์ได้ แต่ไม่สามารถซ่อมแซมได้เนื่องจากการซ่อมแซมจำเป็นต้องมีสำเนาที่สองของบล็อกข้อมูลนั้น การตั้งค่า zfs set copies=2 บน dataset จะช่วยให้คุณมีสำเนาที่สองโดยใช้พื้นที่เพิ่มขึ้นเป็นสองเท่า ซึ่งช่วยแก้ปัญหาบล็อกข้อมูลเสียได้ แต่ไม่สามารถแก้ปัญหาในกรณีที่ volume สูญหายได้ การทำ mirror ข้ามสอง volume คือคำตอบที่ช่วยซ่อมแซมข้อมูลได้จริง

การบีบอัดข้อมูลทำให้เซิร์ฟเวอร์ทำงานช้าลงหรือไม่?

lz4 มักจะช่วยให้ทำงานเร็วขึ้น บล็อกที่ถูกบีบอัดหมายถึงจำนวนไบต์ที่เขียนและอ่านน้อยลง และภาระงานของ CPU ต่อบล็อกนั้นถือว่าน้อยมากเมื่อเทียบกับพื้นที่ดิสก์ที่ประหยัดได้ ให้ตั้งค่า compression=lz4 ไว้ที่ระดับ root ของ pool เพื่อให้ทุก dataset สืบทอดการตั้งค่านี้ จากนั้นตรวจสอบ zfs get compressratio tank หลังจากที่มีการเขียนข้อมูลจริงลงไปแล้ว