SSD Nodes Learn 🎉 VPS เริ่ม $5.50/เดือน
คู่มือ Matt Connorโดย Matt Connor

VPS จำเป็นต้องมี swap หรือไม่? วิธีคำนวณขนาดที่เหมาะสม

Cloud image ส่วนใหญ่ไม่มี swap ติดตั้งมาให้ เรียนรู้วิธีตัดสินใจว่า VPS ของคุณควรเพิ่ม swap file หรือใช้ zram พร้อมคำแนะนำการตั้งค่า vm.swappiness เพื่อป้องกัน OOM killer

VPS ของคุณจำเป็นต้องมี swap หรือไม่

Cloud image ส่วนใหญ่ไม่ได้ติดตั้ง swap มาให้ และสำหรับ VPS ขนาดเล็ก คำตอบมักจะเป็นใช่ คุณควรเพิ่ม swap file เข้าไป ทั้งนี้ swap ไม่ได้ทำให้เซิร์ฟเวอร์ขนาด 1 GB ทำงานได้เหมือนเซิร์ฟเวอร์ขนาด 2 GB แต่มันช่วยให้ kernel มีพื้นที่สำหรับจัดเก็บ cold anonymous pages ซึ่งช่วยรักษาประสิทธิภาพของ page cache และทำให้ OOM killer (กระบวนการของ kernel ที่เลือกยุติการทำงานของ process เพื่อคืนหน่วยความจำ) เป็นทางเลือกสุดท้ายแทนที่จะเป็นทางเลือกแรก

สรุปสั้นๆ คือ บนเครื่องที่รันบริการระยะยาวเพียงไม่กี่อย่าง การมี swap file ขนาดเล็กนั้นคุ้มค่ากับพื้นที่ดิสก์ที่เสียไป แต่บนเครื่องที่ process หนึ่งพยายามจองหน่วยความจำเกินกว่าที่เครื่องมีอยู่เป็นประจำ swap จะไม่สามารถช่วยคุณได้ และจะทำให้ความล้มเหลวเกิดขึ้นช้าลงและตรวจสอบได้ยากขึ้น เนื้อหาที่เหลือในคู่มือนี้จะกล่าวถึงวิธีการแยกแยะสถานการณ์ทั้งสองแบบ รวมถึงต้นทุนสองประการที่พบได้เฉพาะบน VPS เท่านั้น

คำสั่งทั้งหมดด้านล่างจำเป็นต้องใช้สิทธิ์ root บนเซิร์ฟเวอร์ของคุณ ดังนั้นให้รันคำสั่งบนเซิร์ฟเวอร์ของคุณเอง แทนการคัดลอกผลลัพธ์จากเครื่องของผู้อื่นมาใช้งาน

หน้าที่ที่แท้จริงของ swap และสิ่งที่ไม่ใช่หน้าที่ของมัน

หน่วยความจำใน Linux มีสองประเภท ประเภทแรกคือ file backed pages ซึ่งเป็นสำเนาของข้อมูลที่มีอยู่บนดิสก์แล้ว เช่น โปรแกรมของคุณและไฟล์ทุกไฟล์ที่คุณเพิ่งอ่านไป ข้อมูลชุดนี้เรียกว่า page cache ประเภทที่สองคือ anonymous pages ซึ่งเป็นหน่วยความจำที่ไม่มีไฟล์รองรับ เช่น heap และ stack รวมถึงหน่วยความจำส่วนใหญ่ที่ฐานข้อมูลจัดสรรขึ้นในขณะทำงาน

เมื่อหน่วยความจำไม่เพียงพอ เคอร์เนลจำเป็นต้องเรียกคืนหน้าหน่วยความจำ (reclaim pages) การเรียกคืน file backed page ที่สะอาด (clean) นั้นทำได้ง่ายเพราะมีสำเนาอยู่บนดิสก์แล้วและสามารถอ่านกลับมาได้ในภายหลัง แต่สำหรับ anonymous page นั้นทำไม่ได้เพราะสำเนาเดียวที่มีอยู่คือสิ่งที่อยู่ใน RAM หากไม่มี swap เคอร์เนลจะมีทางเลือกสำหรับหน่วยความจำประเภท anonymous เพียงสองทางคือ เก็บไว้ หรือสั่งยุติ (kill) กระบวนการที่เป็นเจ้าของหน่วยความจำนั้น

เซิร์ฟเวอร์ที่ไม่มี swap ก็ยังคงมีการทำ paging เพียงแต่เป็นการทำ paging กับหน่วยความจำที่ไม่ถูกต้อง เมื่อเกิดสภาวะกดดัน เคอร์เนลจะลดขนาดของ page cache ลงโดยการขับไฟล์หน้าหน่วยความจำที่กำลังจะถูกเรียกใช้ออกไป รวมถึงส่วนที่เป็น executable text ของโปรแกรมที่กำลังทำงานอยู่ด้วย หน้าหน่วยความจำเหล่านั้นจะถูกดึงกลับมาผ่านกระบวนการ major page faults คุณจะเห็นการอ่านดิสก์ในคอลัมน์ bi ของ vmstat และตัวนับ pgmajfault ที่เพิ่มขึ้นใน /proc/vmstat ในขณะที่ si และ so ยังคงเป็นศูนย์ตลอดเวลา เครื่องจะเกิดอาการ thrashing และตัวนับ swap จะไม่แสดงค่าใดๆ

สิ่งที่ swap ไม่ได้ทำคือการเพิ่มความจุ หาก working set ซึ่งหมายถึงหน้าหน่วยความจำที่กำลังถูกใช้งานจริง มีขนาดใหญ่กว่า RAM การมี swap จะเปลี่ยนสถานะจาก out of memory kill ให้กลายเป็นเซิร์ฟเวอร์ที่ทำงานช้ามาก บางครั้งนี่คือสิ่งที่คุณต้องการ เพราะเซิร์ฟเวอร์ที่ทำงานช้ายังสามารถล็อกอินเข้าไปแก้ไขได้ ในขณะที่ฐานข้อมูลที่ถูกสั่ง kill ไปแล้วนั้นไม่สามารถทำได้ แต่บางครั้งมันอาจแย่กว่าเดิม เพราะเซิร์ฟเวอร์ที่ทำงานช้าจะล้มเหลวในการทำ health checks อยู่ตลอดเวลาในขณะที่ยังคงเปิดการเชื่อมต่อค้างไว้ทั้งหมด คุณควรตัดสินใจให้แน่ชัดว่าต้องการผลลัพธ์แบบใดก่อนที่จะเพิ่ม swap เข้าไป

เหตุใด cloud image จึงไม่มี swap มาให้ตั้งแต่ต้น

นี่เป็นความตั้งใจในการออกแบบ image หนึ่งชุดต้องสามารถบูตได้บนทุกแผนบริการที่ผู้ให้บริการจำหน่าย ดังนั้นการกำหนด partition สำหรับ swap แบบตายตัวจะทำให้เสียพื้นที่ดิสก์บนแผนขนาดเล็กและไม่มีประโยชน์บนแผนขนาดใหญ่ นอกจากนี้ ความเร็วของ swap ยังขึ้นอยู่กับประสิทธิภาพของ storage ภายใต้ guest ซึ่ง image ไม่สามารถทราบได้ล่วงหน้า ผู้สร้าง image จึงปรับแต่งเพื่อให้ระบบมีพฤติกรรมที่คาดการณ์ได้ เพราะกระบวนการที่หยุดทำงานทันทีนั้นวินิจฉัยปัญหาได้ง่ายกว่าในระดับกลุ่มเซิร์ฟเวอร์ เมื่อเทียบกับเครื่องที่ยังทำงานอยู่แต่ตอบสนองทุกคำขอช้าลงหลายวินาที

เหตุผลเหล่านั้นใช้กับเครื่องที่เน้นการใช้งานแบบชั่วคราว แต่ VPS ที่คุณใช้งานในระยะยาวนั้นต่างออกไป คุณต้องซ่อมแซมแทนการเปลี่ยนใหม่ ดังนั้นการยอมให้ระบบหน่วงจากการทำ paging เล็กน้อยมักจะดีกว่าการที่ service ถูกสั่ง kill ให้มองว่าการไม่มี swap คือค่าเริ่มต้นที่สร้างมาเพื่อกรณีการใช้งานของผู้อื่น

Swap file หรือ swap partition บน VPS?

ให้ใช้ swap file การใช้ partition หมายถึงการต้องปรับขนาด root filesystem ในขณะที่ระบบกำลังทำงานบนดิสก์ที่แบ่ง partition มาแล้ว ซึ่งมีความเสี่ยงสูงโดยไม่ได้รับประโยชน์เพิ่มเติม ในขณะที่ swap file สามารถสร้างและลบได้ด้วยคำสั่งทั่วไป และคุณสามารถปรับเปลี่ยนขนาดได้ในภายหลังโดยไม่ต้องยุ่งกับ partition table

ความเร็วไม่ใช่ปัจจัยตัดสิน ในเวลา swapon kernel จะอ่าน extent map ของไฟล์เพียงครั้งเดียว จากนั้นจะส่ง I/O ไปยัง block device โดยตรง ดังนั้น filesystem จึงไม่ได้อยู่ในเส้นทางการทำงานของแต่ละ page in และ page out บนดิสก์เดียวกัน swap file และ swap partition จึงมีประสิทธิภาพเท่ากัน

มีข้อจำกัด 2 ประการที่ควรทราบ ห้ามใช้ swap บน network filesystem เช่น NFS (network file system) และบน btrfs ไฟล์นั้นจะต้องปิดการใช้งาน copy on write และปิดการบีบอัดข้อมูล ซึ่งเป็นเหตุผลว่าทำไม btrfs จึงมีเครื่องมือช่วยสร้าง swap file ของตนเองมาให้

วิธีการเพิ่ม swap file บน Ubuntu หรือ Debian

ตรวจสอบสถานะปัจจุบันก่อนทำการเปลี่ยนแปลงใดๆ

swapon --show
free -h
findmnt -no FSTYPE /

หาก swapon --show ไม่แสดงผลลัพธ์ใดๆ หมายความว่าไม่มีการตั้งค่า swap ไว้ ซึ่งเป็นสถานะปกติของ cloud image ที่ติดตั้งใหม่ findmnt จะแสดงประเภทของ root filesystem ซึ่งเป็นตัวกำหนดวิธีการสร้างไฟล์ ในกรณีของ ext4 ซึ่งเป็นสิ่งที่ cloud image ส่วนใหญ่ใช้ การใช้ fallocate ถือว่าปลอดภัย

sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile

การใช้ chmod ก่อน mkswap นั้นมีจุดประสงค์ หากข้ามขั้นตอนนี้ไป mkswap จะแจ้งเตือนคุณว่า: mkswap: /swapfile: insecure permissions 0644, fix with: chmod 0600 /swapfile การตั้งค่า swap file ให้ทุกคนอ่านได้ (world readable) จะทำให้ผู้ใช้ทุกคนบนเครื่องสามารถเข้าถึงหน่วยความจำที่ process อื่นสลับออกไปเก็บไว้ได้ จากนั้นคำสั่ง mkswap จะยืนยันขนาดที่ถูกต้อง โดยแสดงบรรทัดในลักษณะ Setting up swapspace version 1, size = 2 GiB (2147479552 bytes)

บน xfs หรือ btrfs คำสั่งสุดท้ายอาจล้มเหลวพร้อมข้อความ swapon: /swapfile: swapon failed: Invalid argument บน XFS ปัญหานี้เกิดขึ้นเพราะ fallocate ทิ้ง unwritten extents ไว้ ดังนั้นให้เขียนข้อมูลลงไปโดยตรงแทน

sudo dd if=/dev/zero of=/swapfile bs=1M count=2048 status=progress

บน btrfs สาเหตุเกิดจาก copy on write ซึ่ง btrfs-progs ในปัจจุบันจะตั้งค่า flag ที่ถูกต้องให้คุณโดยอัตโนมัติ

sudo btrfs filesystem mkswapfile --size 2g /swapfile

ไม่ว่าจะใช้วิธีใด ให้ปิดท้ายด้วย chmod 600, mkswap ในกรณีที่เกี่ยวข้อง และ swapon จากนั้นตรวจสอบผลลัพธ์

swapon --show
free -h

swapon --show ควรแสดงรายการ /swapfile โดยมีประเภทเป็น file และขนาดตามที่คุณกำหนด ส่วน free -h ควรแสดงแถว Swap ที่มีการใช้งานเกือบเป็นศูนย์ การที่ swap ถูกใช้งานเป็นศูนย์บนระบบที่ติดตั้งใหม่ถือเป็นเรื่องปกติ kernel จะย้ายข้อมูลลงไปก็ต่อเมื่อมีความจำเป็นเท่านั้น

ตั้งค่าให้ระบบจดจำหลังการรีบูต จากนั้นทดสอบรายการที่เพิ่มเข้าไปทันที

echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
sudo swapoff /swapfile
sudo swapon -a
swapon --show

swapon -a จะอ่านค่าจาก /etc/fstab ดังนั้นหากมีบรรทัดที่ผิดพลาด ระบบจะแจ้งเตือนให้คุณทราบทันที การพิมพ์ผิดโดยไม่ทดสอบจะทำให้คุณพบปัญหาในระหว่างการรีบูตโดยไม่ได้วางแผน ซึ่งจะส่งผลให้เครื่องกลับมาทำงานโดยไม่มี swap ตามที่คุณคาดหวัง

หากต้องการลบ swap ในภายหลัง ให้รัน sudo swapoff /swapfile, ลบบรรทัดใน fstab ออก แล้วจึงใช้ sudo rm /swapfile ทั้งนี้ swapoff จำเป็นต้องอ่านข้อมูลทุกหน้าที่ถูกสลับออกไปกลับเข้าสู่ RAM ก่อน ดังนั้นบนเครื่องที่มีภาระงานสูง คำสั่งอาจล้มเหลวพร้อมข้อความ swapoff: /swapfile: swapoff failed: Cannot allocate memory ให้เพิ่มพื้นที่หน่วยความจำว่างแล้วลองใหม่อีกครั้ง

ขนาดของ swap file ควรเป็นเท่าใด

หน้าที่ของ swap คือการเก็บ anonymous pages ที่ไม่ได้ใช้งาน ดังนั้นขนาดที่สำคัญคือปริมาณหน่วยความจำที่ถูกจองไว้แต่ไม่ได้ใช้งานจริง ไม่ใช่ขนาด RAM ทั้งหมดของแผนบริการ หน่วยความจำที่ไม่ได้ใช้งานไม่ได้เพิ่มขึ้นตามขนาดของแผนบริการ ดังนั้นตัวคูณจึงลดลงเมื่อแผนบริการมีขนาดใหญ่ขึ้น นี่คือหลักการที่คู่มือนี้ใช้

ChartSwap file size this guide sets, by plan RAM
The data behind this chart
[
  {
    "label": "1 GB plan",
    "swap_gb": 2,
    "swap_x_ram": 2
  },
  {
    "label": "2 GB plan",
    "swap_gb": 2,
    "swap_x_ram": 1
  },
  {
    "label": "4 GB plan",
    "swap_gb": 2,
    "swap_x_ram": 0.5
  },
  {
    "label": "8 GB plan",
    "swap_gb": 4,
    "swap_x_ram": 0.5
  },
  {
    "label": "16 GB plan",
    "swap_gb": 4,
    "swap_x_ram": 0.25
  }
]

สำหรับแผนบริการขนาดเล็กที่สุด จะใช้ swap ขนาด 2 GB ซึ่งคิดเป็น 2 เท่าของ RAM เนื่องจากเซิร์ฟเวอร์ขนาด 1 GB มีพื้นที่ว่างน้อยมากจนการใช้งานพุ่งสูงขึ้นเพียงครั้งเดียวอาจทำให้ OOM killer ทำงานได้ สำหรับแผนบริการขนาดใหญ่ที่สุด ขนาดของไฟล์จะหยุดอยู่ที่ 4 GB หรือ 0.25 เท่าของ RAM เนื่องจากกระบวนการ paging ข้อมูลจำนวนมากบน shared storage ใช้เวลานานจนเซิร์ฟเวอร์แทบจะใช้งานไม่ได้ในระหว่างนั้น คุณสามารถปรับลดตัวเลขเหล่านี้ได้หากพื้นที่ดิสก์ของคุณมีจำกัด เนื่องจากไฟล์ดังกล่าวใช้พื้นที่ดิสก์จริง

เหตุผลคลาสสิกประการเดียวที่ทำให้ต้องกำหนดขนาด swap ให้เท่ากับหรือมากกว่า RAM คือการทำ hibernation ซึ่งเป็นการเขียนภาพหน่วยความจำทั้งหมดลงใน swap แต่เนื่องจาก VPS ไม่มีการทำ hibernation กฎข้อนี้จึงไม่มีผลกับคุณ

vm.swappiness เปลี่ยนแปลงอะไรกันแน่

vm.swappiness ไม่ใช่เปอร์เซ็นต์ของ RAM และไม่ใช่ค่าเกณฑ์ (threshold) แต่เป็นค่าต้นทุนสัมพัทธ์ที่ kernel กำหนดให้กับการเรียกคืน anonymous pages เมื่อเทียบกับ file pages ค่าเริ่มต้นคือ 60 หากลดค่านี้ลง kernel จะเลือกทิ้ง page cache มากขึ้น หากเพิ่มค่านี้ kernel จะเลือกย้าย anonymous memory ออกไปยัง swap มากขึ้น

นี่คือการแลกเปลี่ยนในทั้งสองทิศทาง ที่ค่า vm.swappiness = 10 ฐานข้อมูลจะเก็บการจัดสรรหน่วยความจำไว้ใน RAM ได้มากขึ้น แต่ต้องแลกมาด้วยการอ่านไฟล์ที่เพิ่งถูกทิ้งออกจาก cache ใหม่ สำหรับเครื่องที่ทำหน้าที่ให้บริการไฟล์เป็นหลัก การตั้งค่าเช่นนี้ถือว่าผิดทิศทาง เพราะ page cache คือส่วนที่ทำงานสำคัญในกรณีนั้น

การตั้งค่าเป็น 0 ไม่ได้เป็นการปิด swap แต่เป็นการสั่งให้ kernel หลีกเลี่ยงการเรียกคืน anonymous memory จนกว่าหน่วยความจำจะใกล้หมด ซึ่งจะทำให้ OOM killer ทำงานเร็วขึ้นแทนที่จะชะลอออกไป หากคุณไม่ต้องการใช้ swap ให้ลบไฟล์ swap ออก

sysctl vm.swappiness
printf 'vm.swappiness = 10\n' | sudo tee /etc/sysctl.d/99-swappiness.conf
sudo sysctl --system
sysctl vm.swappiness

การตั้งค่า sysctl -w โดยตรงจะมีผลจนกว่าจะ reboot ครั้งถัดไปแล้วจะหยุดทำงานโดยอัตโนมัติ ดังนั้นควรเขียนค่าลงในไฟล์ภายใต้ /etc/sysctl.d/ สำหรับ kernel ตั้งแต่เวอร์ชัน 5.8 เป็นต้นไป สามารถรับค่าได้ตั้งแต่ 0 ถึง 200 การตั้งค่าเกิน 100 จะมีประโยชน์ก็ต่อเมื่อ swap มีความเร็วใกล้เคียงกับ RAM ซึ่งหมายถึงการใช้งาน zram

zram: swap ที่ใช้ CPU แทนดิสก์

zram คือ block device แบบบีบอัดที่ทำงานอยู่ใน RAM เมื่อนำมาใช้เป็น swap หน้าข้อมูล (page) ที่ควรจะถูกเขียนลงดิสก์จะถูกบีบอัดและเก็บไว้ในหน่วยความจำแทน ทำให้ไม่มีการทำ disk I/O และไม่สิ้นเปลืองโควตาของดิสก์ สิ่งที่ต้องแลกคือการใช้เวลาของ CPU ในทุกครั้งที่มีการอ่านหรือเขียนหน้าข้อมูล รวมถึง RAM ที่ต้องถูกแบ่งไปเก็บข้อมูลที่บีบอัดแล้ว ซึ่งจะทำให้แอปพลิเคชันของคุณมีพื้นที่หน่วยความจำใช้งานลดลง

อัตราส่วนการบีบอัดที่มักพบได้ทั่วไปสำหรับ anonymous pages อยู่ที่ระหว่าง 2:1 ถึง 3:1 โดยคุณสามารถดูตัวเลขจริงของระบบคุณได้จาก zramctl ในคอลัมน์ DATA และ COMPR แนะนำให้วัดค่าจริงแทนการวางแผนตามตัวเลขมาตรฐาน เนื่องจากภาระงานบางประเภทอาจมีข้อมูลที่ไม่สามารถบีบอัดได้เลย

sudo apt install zram-tools

กำหนดค่า ALGO=zstd และ PERCENT=25 ใน /etc/default/zramswap จากนั้นให้รีสตาร์ท service และตรวจสอบผลลัพธ์

sudo systemctl restart zramswap
zramctl
swapon --show

PERCENT คือสัดส่วนของ RAM ทั้งหมด ดังนั้นการตั้งค่าเป็น 25 บนเครื่องที่มี RAM 4 GB จะเป็นการจองพื้นที่สูงสุด 1 GB สำหรับเก็บหน้าข้อมูลที่บีบอัด ให้เริ่มจากค่าต่ำๆ แล้วค่อยเพิ่มขึ้นหาก zramctl แสดงให้เห็นว่าอุปกรณ์เริ่มเต็ม การตั้งค่า PRIORITY ในไฟล์เดียวกันจะเป็นตัวกำหนดว่า kernel จะเลือกใช้ swap ใดก่อน โดยค่าที่สูงกว่าจะเป็นฝ่ายชนะ ทั้งนี้ swap file บนดิสก์ที่เพิ่มด้วยคำสั่ง swapon ปกติจะมีค่า priority เป็นลบ ทำให้ zram ถูกใช้งานก่อนและ swap file จะทำหน้าที่รองรับข้อมูลส่วนเกิน swapon --show จะแสดงค่าทั้งสองในคอลัมน์ PRIO สำหรับ distribution ที่ใช้ systemd-zram-generator แทน zram-tools การตั้งค่าเดียวกันจะอยู่ใน /etc/systemd/zram-generator.conf

zram เหมาะสำหรับเครื่องที่มี CPU เหลือเฟือแต่มีพื้นที่ดิสก์จำกัด และเป็นตัวเลือกที่ไม่เหมาะสมหากทรัพยากร CPU ของคุณมีจำกัดอยู่แล้ว เนื่องจากกระบวนการบีบอัดจะเข้าไปแย่งชิงทรัพยากรการประมวลผลกับแอปพลิเคชันของคุณ

กับดักสองประการของ swap บน VPS

กับดักแรกคือเรื่องพื้นที่ดิสก์ ไฟล์ swap ขนาด 2 GB จะกินพื้นที่ดิสก์ในแพ็กเกจของคุณทันทีที่สร้างขึ้น เนื่องจากต้องมีการจองพื้นที่ไว้ล่วงหน้า ค่า df -h / จะลดลงตามจำนวนนั้นทันทีและจะไม่คืนพื้นที่จนกว่าคุณจะลบไฟล์ดังกล่าวทิ้ง สำหรับแพ็กเกจขนาดเล็ก นี่ถือเป็นสัดส่วนที่เห็นได้ชัด และหากระบบไฟล์ root เต็มจะส่งผลเสียมากกว่าการมี swap หลายเท่า ไฟล์นี้จะถูกนับรวมในผลลัพธ์ของ du ด้วย ซึ่งเป็นสิ่งที่ควรจำไว้เมื่อคุณกำลังไล่หาพื้นที่ว่างและ df และ du แสดงผลไม่ตรงกันว่าพื้นที่ดิสก์หายไปไหน

กับดักที่สองคือเรื่องความหน่วง (latency) การทำ I/O ของ swap จะไปใช้พื้นที่จัดเก็บข้อมูลที่โฮสต์แชร์ร่วมกับ guest รายอื่น ซึ่งคุณไม่สามารถมองเห็นโหลดของ guest รายอื่นได้จากภายใน guest ของคุณเอง คุณจะเห็นเพียงผลกระทบที่เกิดขึ้นเท่านั้น นั่นคือการดึงข้อมูลหน้าหน่วยความจำ (page in) ที่ปกติควรจะรวดเร็ว บางครั้งกลับใช้เวลานานกว่าปกติมาก และกระบวนการที่รอข้อมูลนั้นอยู่จะหยุดชะงักจนกว่าข้อมูลจะมาถึง นี่เป็นเหตุผลเดียวกับ CPU steal time บนโฮสต์ที่ใช้ร่วมกัน เพียงแต่เปลี่ยนจากการรอในคิวประมวลผล (run queue) มาเป็นคิวของดิสก์แทน คุณควรวัดค่านี้ด้วยตัวเองบนเครื่องของคุณ เพราะตัวเลขความหน่วงที่เผยแพร่ทั่วไปเป็นเพียงข้อมูลของเพื่อนบ้านบนโฮสต์ของคนอื่นเท่านั้น

คุณจะทราบได้อย่างไรว่าการทำ swapping ส่งผลกระทบต่อระบบของคุณ?

การมีพื้นที่ swap ที่ถูกใช้งานอยู่ไม่ใช่ปัญหา แต่การรับส่งข้อมูล (traffic) ใน swap ต่างหากที่เป็นปัญหา เซิร์ฟเวอร์ที่มีข้อมูลหลายร้อยเมกะไบต์ค้างอยู่ใน swap โดยไม่มีกิจกรรมการ paging เกิดขึ้น หมายความว่าระบบได้ย้ายข้อมูลในหน่วยความจำที่ไม่มีการเข้าถึงมานานหลายชั่วโมงออกไปแล้ว ซึ่งนั่นคือผลลัพธ์ที่คุณต้องการ

ให้สังเกตที่อัตราการใช้งานแทนที่จะดูที่ยอดรวม

vmstat 1 5

si และ so คือหน่วย kibibytes ต่อวินาทีที่มีการ swap เข้าและออก ในเครื่องที่มีสถานะปกติ ค่าเหล่านี้ควรอยู่ที่หรือใกล้ศูนย์เสมอ ไม่ว่าคอลัมน์ swpd จะแสดงค่าเท่าใดก็ตาม หากมีค่า so เกิดขึ้นอย่างต่อเนื่องพร้อมกับค่า si ที่เพิ่มขึ้น แสดงว่ามีการเขียนหน้าข้อมูล (pages) ออกไปและดึงกลับมาทันที ซึ่งนั่นคือภาวะ thrashing

procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 2  3 1048572  38210   4096  61440  912 1180  2210  1290 1402 2890  9  7 12 72  0

ตัวอย่างนั้นแสดงให้เห็นถึงเครื่องที่มีปัญหา และสัญญาณที่ชัดเจนที่สุดไม่ได้อยู่ในคอลัมน์ swap แต่อยู่ที่ wa ซึ่งมีค่า 72 หมายความว่า CPU ใช้เวลาส่วนใหญ่ไปกับการรอ I/O และ b มีค่า 3 หมายความว่ามี 3 กระบวนการที่กำลังถูกบล็อกอยู่

PSI (pressure stall information) ช่วยตอบคำถามนี้ได้โดยตรงมากกว่า

cat /proc/pressure/memory
some avg10=8.42 avg60=5.11 avg300=2.03 total=1284729
full avg10=3.10 avg60=1.94 avg300=0.71 total=498210

some avg10=8.42 หมายความว่าในช่วง 10 วินาทีที่ผ่านมา มีอย่างน้อยหนึ่งงานที่ต้องหยุดชะงักขณะรอหน่วยความจำคิดเป็น 8.42 เปอร์เซ็นต์ของเวลาทั้งหมด ส่วน full จะนับเวลาที่งานที่ไม่ใช่ idle ทั้งหมดหยุดชะงัก ดังนั้นค่า full ที่สูงอย่างต่อเนื่องถือเป็นความเสียหายที่วัดผลได้ ไม่ใช่เพียงแค่สัญญาณเตือน หากไฟล์นี้ไม่มีอยู่ แสดงว่า kernel ของคุณปิดการใช้งาน PSI ไว้เป็นค่าเริ่มต้น และจำเป็นต้องเพิ่ม psi=1 ลงใน kernel command line

หากต้องการดูว่ากระบวนการใดถือครองหน้าข้อมูล (pages) อยู่ใน swap:

sudo awk '/^Name:/{n=$2} /^VmSwap:/ && $2+0 > 0 {printf "%10d kB  %s\n", $2, n}' /proc/[0-9]*/status | sort -rn | head

และหากต้องการตรวจสอบว่า OOM killer ได้ทำงานไปแล้วหรือไม่:

sudo journalctl -k --grep "Out of memory"

หากพบการทำงาน ระบบจะแสดงข้อความเช่น Out of memory: Killed process 2199 (mysqld) total-vm:1275860kB, anon-rss:129252kB, file-rss:0kB, shmem-rss:0kB, UID:114 pgtables:504kB oom_score_adj:0 และ log ของบริการในช่วงเวลาเดียวกันจะระบุว่า Main process exited, code=killed, status=9/KILL หากคุณพบข้อความเหล่านี้บนเครื่องที่ไม่มีการตั้งค่า swap การเพิ่ม swap file เป็นวิธีที่ประหยัดที่สุดที่ควรลองทำเป็นลำดับถัดไป

เมื่อ swap ไม่ใช่การแก้ไขที่ถูกต้อง

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

ให้จำกัดขีดความสามารถของกระบวนการแทน บริการของ systemd รองรับ MemoryMax= และ MemorySwapMax= ในไฟล์ drop-in ซึ่งเป็นวิธีที่คุณจะ จำกัดหน่วยความจำและ CPU สำหรับบริการด้วย systemd โดยไม่ต้องแก้ไขตัวแอปพลิเคชัน คอนเทนเนอร์มีการควบคุมในระดับเดียวกัน และการตั้งค่าเหล่านี้คือวิธีที่คุณจะหยุด ไม่ให้บริการใน Compose หนึ่งตัวกินทรัพยากรทั้งเครื่อง ทั้งสองวิธีช่วยให้คุณสั่ง kill กระบวนการโดยระบุชื่อไว้ใน log ที่ค้นหาได้ แทนที่จะปล่อยให้ kernel เลือกเหยื่อตามคะแนน (score)

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

FAQ

การเพิ่ม swap จะทำให้ VPS ขนาด 1 GB ทำงานได้เหมือน VPS ขนาด 2 GB หรือไม่?

ไม่ Swap มีความเร็วต่ำกว่า RAM มาก และ kernel จะย้ายเฉพาะหน้าหน่วยความจำที่ประเมินว่าไม่มีการใช้งาน (cold pages) ไปไว้ที่นั่นเท่านั้น สิ่งที่คุณได้รับคือพื้นที่สำรองสำหรับช่วงที่มีภาระงานสูงและเป็นที่พักสำหรับหน่วยความจำที่ถูกจองไว้แต่ไม่ได้ใช้งานจริง หากภาระงานของคุณมีการอ่านและเขียนหน่วยความจำมากกว่าที่เครื่องมีอยู่จริง Swap จะเปลี่ยนสถานะจาก out of memory kill ไปเป็นการทำ paging อย่างต่อเนื่อง ซึ่งจะทำให้เซิร์ฟเวอร์ยังคงทำงานอยู่แต่ตอบสนองช้าจนไม่สามารถใช้งานได้ ในกรณีนี้ให้เพิ่ม RAM หรือจำกัดการใช้ทรัพยากรของ process ที่ขยายตัว

VPS ขนาด 1 GB หรือ 2 GB ต้องการ swap เท่าใด?

2 GB เพียงพอสำหรับทั้งสองขนาด และไม่จำเป็นต้องเพิ่มตามขนาด RAM หลังจากจุดนี้ Swap ใช้เก็บหน้าหน่วยความจำที่ไม่มีการใช้งานจริง และปริมาณหน่วยความจำที่ไม่มีการใช้งานบนเซิร์ฟเวอร์ไม่ได้เพิ่มขึ้นตามขนาด RAM ทั้งหมด กฎเก่าที่ให้ตั้งค่าเป็นสองเท่าของ RAM มาจากการทำ hibernation ซึ่งต้องเขียนภาพหน่วยความจำทั้งหมดลงดิสก์ แต่ VPS ไม่มีการทำ hibernation การตั้งค่าเกิน 4 GB ส่วนใหญ่จะส่งผลให้เกิดความล้มเหลวที่ยาวนานและช้าลงบนพื้นที่จัดเก็บข้อมูลที่คุณใช้งานร่วมกับผู้ใช้อื่น

การตั้งค่า vm.swappiness เป็น 0 คือวิธีที่ถูกต้องในการหยุดการทำ swap ใช่หรือไม่?

ไม่ และมันไม่ได้ทำหน้าที่ตามชื่อที่สื่อออกมา vm.swappiness = 0 ไม่ได้เป็นการปิดการใช้งาน swap แต่เป็นการสั่งให้ kernel หลีกเลี่ยงการดึงหน้าหน่วยความจำ anonymous pages กลับมาจนกว่าหน่วยความจำจะใกล้หมด ซึ่งจะทำให้เกิด OOM kill ได้ง่ายขึ้นแทนที่จะลดลง นอกจากนี้ยังผลักภาระการดึงข้อมูลไปไว้ที่ page cache ทำให้การอ่านไฟล์ต้องกลับไปดึงจากดิสก์บ่อยขึ้น หากคุณไม่ต้องการใช้ swap เลย ให้รัน sudo swapoff -a และลบบรรทัดที่เกี่ยวข้องใน fstab ออก หากคุณต้องการลดการทำ swap ให้ลองใช้ vm.swappiness = 10 และเปรียบเทียบค่าในคอลัมน์ si และ so ใน vmstat ก่อนและหลังการปรับค่า

ฉันควรใช้ zram แทน swap file หรือไม่?

ให้ใช้ zram เมื่อคุณมีทรัพยากร CPU เหลือเฟือแต่มีพื้นที่ดิสก์จำกัด และใช้ swap file ในกรณีที่ตรงกันข้าม zram จะบีบอัดหน้าหน่วยความจำและเก็บไว้ใน RAM จึงช่วยหลีกเลี่ยงการทำ disk I/O ได้ทั้งหมด แต่ต้องแลกมาด้วยการใช้ CPU ในทุกครั้งที่มีการอ่านหรือเขียนหน้าหน่วยความจำ และพื้นที่ที่ใช้ไปคือ RAM ที่แอปพลิเคชันจะไม่สามารถใช้งานได้ บน VPS ที่มีข้อจำกัดด้าน CPU ต้นทุนนี้จะไปตกอยู่กับทรัพยากรที่คุณขาดแคลนอยู่แล้ว การใช้งานทั้งสองอย่างร่วมกันเป็นเรื่องปกติ โดยให้กำหนดลำดับความสำคัญของ zram ให้สูงกว่าด้วย PRIORITY ใน /etc/default/zramswap และเก็บ disk swap file ไว้ด้านล่างเพื่อรองรับข้อมูลส่วนเกิน

ทำไม OOM killer ถึงทำงานในขณะที่คำสั่ง free แสดงว่ายังมีหน่วยความจำเหลืออยู่?

free รายงานสถานะ ณ ขณะหนึ่งเท่านั้น แต่การจองหน่วยความจำเกิดขึ้นในเสี้ยววินาที กระบวนการที่ร้องขอหน่วยความจำขนาดใหญ่เร็วกว่าที่ระบบจะคืนหน่วยความจำได้ทันจะถูกสั่งปิด (kill) แม้ว่าค่าเฉลี่ยจะดูปกติก็ตาม ให้ตรวจสอบ kernel log ด้วย sudo journalctl -k --grep "Out of memory" ซึ่งจะระบุชื่อกระบวนการที่ถูกปิดและขนาดหน่วยความจำที่ใช้งานอยู่ (resident size) ในขณะนั้น จากนั้นตรวจสอบว่าการปิดกระบวนการเกิดจากขีดจำกัดของ cgroup หรือไม่ แทนที่จะเป็นทั้งเครื่อง เพราะ container หรือ systemd unit ที่ตั้งค่า MemoryMax= ไว้จะถูกปิดเมื่อถึงขีดจำกัดของตนเอง แม้ว่าโฮสต์จะยังมีหน่วยความจำเหลืออยู่ก็ตาม

#swap#memory#oom#zram#linux-performance