คำถามมักออกมาเหมือนกันแทบทุกครั้ง: เมื่อคืนเว็บไซต์ใช้เวลาตอบสนองยี่สิบวินาที พอถึงเช้าทุกอย่างก็กลับมาเป็นปกติเอง ตอนนี้ไม่เหลืออะไรให้ดูแล้ว — top ตอบเรื่องวินาทีปัจจุบัน ในขณะที่คำถามคือเรื่องตีสาม ด้านล่างนี้คือความหมายที่แท้จริงของตัวเลขโหลด ตัวไหนต้องอ่านคู่กัน และทำไมการวัดครั้งเดียวจึงทำให้เข้าใจผิดบ่อยกว่าจะช่วย
Load average: สามตัวเลขกับความเข้าใจผิดที่พบบ่อย
uptime
cat /proc/loadavg
nproc
ตัวเลขสามตัวคือค่าเฉลี่ยของหนึ่ง ห้า และสิบห้านาที ไม่ได้เทียบกับศูนย์ แต่เทียบกับจำนวนคอร์ที่ nproc แสดง ค่า 8 บนเครื่องแปดคอร์คือโหลดเต็มแต่ยังปกติดี: มีงานพอดีกับที่เซิร์ฟเวอร์ทำไหว ส่วนค่า 2 บน VPS คอร์เดียวคือคิวที่ยาวเป็นสองเท่าของกำลังที่มี และทุกคำขอต้องรอคิวของตน
ความสัมพันธ์ระหว่างตัวเลขทั้งสามบอกทิศทาง ค่าหนึ่งนาทีสูงกว่าค่าสิบห้านาทีอย่างชัดเจนแปลว่าโหลดกำลังไต่ขึ้นในขณะนี้ ตรงกันข้ามแปลว่าจุดสูงสุดผ่านไปแล้วและสิ่งที่เห็นคือหางของมัน
ทีนี้มาถึงความเข้าใจผิดที่ทำให้อ่านตัวเลขเหล่านี้พลาดมากที่สุด ใน Linux นั้น load average ไม่ใช่ «อัตราการใช้ซีพียู» ต่างจากระบบ Unix อื่น Linux นับรวมไม่เพียงโปรเซสที่กำลังทำงานหรือพร้อมทำงาน แต่รวมถึงโปรเซสในสถานะ D ด้วย — การหลับที่ขัดจังหวะไม่ได้ นั่นคือการรอดิสก์หรือรอระบบไฟล์บนเครือข่าย จากตรงนี้จึงเกิดเซิร์ฟเวอร์ที่โหลด 12 ขณะที่ซีพียูแทบว่าง: งานไม่เดินหน้า ทุกอย่างเข้าคิวรออยู่
ซีพียูหรือดิสก์
การแยกสองกรณีนี้ออกจากกันคือสิ่งแรกที่ควรทำ:
vmstat 1 5
iostat -x 1 3
ในผลลัพธ์ของ vmstat มีสามคอลัมน์ที่สำคัญ r คือจำนวนโปรเซสที่รอคิวซีพียู b คือจำนวนที่ถูกบล็อกเพราะรออินพุตและเอาต์พุต ส่วน wa คือสัดส่วนเวลาที่ซีพียูอยู่ว่างเพื่อรอดิสก์ หาก wa ค้างอยู่เหนือ 10–15 % ขณะที่ us และ sy ต่ำ แปลว่าเซิร์ฟเวอร์ติดที่ดิสก์: การเพิ่มคอร์ไม่ช่วยอะไร เพราะคอร์ที่มีก็ว่างอยู่แล้ว
โปรเซสไหนกำลังรอ ดูเป็นรายชื่อได้:
ps -eo state,pid,comm,wchan:30 | awk '$1 ~ /^D/'
ตัวอย่างจากประสบการณ์ของเราเอง ด้วยค่าตั้งต้น Suricata เขียนเหตุการณ์ราวสามสิบประเภทและไม่ตั้งการหมุนไฟล์ไว้ให้เลย — บนเซิร์ฟเวอร์ที่ใช้งานจริงสิ่งนี้ให้ล็อก 15 GB ภายในสองวัน โหลดที่เกิดขึ้นไม่ได้ปรากฏเป็นซีพียูที่ทำงานหนัก แต่ปรากฏเป็น I/O wait พอดี: ระบบเขียนไม่หยุดและทุกอย่างที่เหลือเข้าคิวอยู่ข้างหลัง ทางแก้ไม่ใช่แพ็กเกจที่ใหญ่ขึ้น แต่คือรายการประเภทเหตุการณ์ที่สั้นลงและการหมุนไฟล์ที่ตั้งค่าไว้
กรณีตรงข้าม เป็นเรื่องของซีพียูล้วนและเห็นได้ยากกว่ามาก หน้าเว็บหนึ่งเรียก apt ในนามผู้ใช้ที่ PHP-FPM ทำงานอยู่ ผู้ใช้ root เก็บแคชไบนารีไว้ที่ /var/cache/apt/pkgcache.bin — บนโฮสต์ที่มีคลังแพ็กเกจสิบกว่าแห่งไฟล์นี้มีขนาด 70 MB — และแมปเข้าหน่วยความจำได้ฟรี ส่วนผู้ใช้ทั่วไปเขียนลงไดเรกทอรีนั้นไม่ได้ จึงสร้างแคชใหม่ทุกครั้งที่เรียก วัดบนเครื่องเดียวกัน: 0.01 วินาทีของเวลาซีพียูเมื่อเป็น root เทียบกับ 4.2 วินาทีเมื่อเป็นผู้ใช้ที่ไม่มีสิทธิ์ คำสั่งเดียวกัน ต่างกันสี่ร้อยเท่า และคูณด้วยจำนวนครั้งที่หน้าเว็บถูกเปิด
ข้อสรุปจากทั้งสองกรณีเหมือนกัน: โหลดต้องวัด ไม่ใช่เดา การจับเวลาแต่ละคำสั่งที่น่าสงสัยแยกกันใช้เวลาครึ่งชั่วโมง และมักชี้ไปยังจุดอื่นที่ไม่ใช่จุดที่ความสงสัยเริ่มต้น
หน่วยความจำ: free ไม่ได้แสดงอย่างที่ดูเหมือน
free -h
คอลัมน์ used เพียงลำพังบอกอะไรได้น้อยมาก ส่วนคอลัมน์ free ทำให้เข้าใจผิดตรง ๆ: Linux ยกหน่วยความจำที่ไม่ได้ใช้ให้แคชหน้าและคืนให้แอปพลิเคชันทันทีที่ร้องขอ คอลัมน์ที่ต้องอ่านคือ available — จองได้เท่าไรโดยไม่ต้องลง swap ค่า buff/cache ที่สูงไม่ใช่ปัญหา แต่เป็นสัญญาณว่าระบบทำงานอย่างที่ควรเป็น
สำหรับ swap สิ่งที่สำคัญไม่ใช่ค่าปัจจุบันแต่เป็นรูปทรง ขึ้นแล้วกลับมาที่ศูนย์: มีจุดสูงสุดช่วงสั้น ๆ ขึ้นครั้งเดียวแล้วค้างอยู่อย่างนั้น: จุดสูงสุดเกิดไปแล้ว หน้าถูกผลักออกและไม่มีใครดึงกลับ — เซิร์ฟเวอร์ดูสงบทั้งที่ครั้งหนึ่งหน่วยความจำเคยไม่พอ ส่วนการสลับกำลังเกิดขึ้นตอนนี้หรือไม่ ดูได้จากคอลัมน์ si และ so ใน vmstat; ค่าที่ไม่เป็นศูนย์ตรงนั้นคือรูปแบบความช้าที่ผู้ใช้รู้สึกได้ชัดที่สุด
ถ้าระหว่างช่วงตกกลางดึกมีโปรเซสหายไปเฉย ๆ คำอธิบายมักอยู่ตรงนี้:
journalctl -k --since yesterday | grep -i "out of memory"
dmesg -T | grep -i "killed process"
บรรทัดแบบ Out of memory: Killed process 1234 (mysqld) ปิดเรื่องได้ดีกว่ากราฟใด ๆ: ฐานข้อมูลไม่ได้ «ล้มไปเอง» เคอร์เนลเป็นผู้หยุดมันเพราะหน่วยความจำหมด
ใครเป็นต้นเหตุ
ps aux --sort=-%cpu | head -10
ps aux --sort=-%mem | head -10
ข้อควรระวังหนึ่งข้อ: %CPU ใน ps เป็นค่าเฉลี่ยตลอดอายุของโปรเซส การพุ่งขึ้นสั้น ๆ จึงหายไปในรายการนั้น สำหรับกรณีนั้นต้องใช้ top หรือ pidstat 1 5 ซึ่งวัดเป็นช่วงเวลา
เมื่อไรที่โหลดกลายเป็นเรื่องความปลอดภัย
ซีพียู 100 % เรียบ ๆ ตลอดคืน พร้อมโปรเซสที่ชื่อไม่สื่ออะไรและมีไดเรกทอรีทำงานอยู่ใน /tmp หรือ /dev/shm คือภาพคลาสสิกของนักขุดเหรียญ ไม่ใช่ภาพของเว็บไซต์ที่โตขึ้น การพุ่งขึ้นของทราฟฟิกขาเข้าพร้อมกับการเขียนล็อกที่มากขึ้นคือการโจมตีรหัสผ่านที่กำลังดำเนินอยู่ ส่วนปริมาณล็อกที่กระโดดขึ้นทันทีมักเป็นพายุการแจ้งเตือนผิดพลาดของตัวกรองบางตัว
เครื่องมือป้องกันเองก็เป็นอีกหมวดหนึ่ง บนเซิร์ฟเวอร์เครื่องหนึ่งของเรา โหลดค้างอยู่ราวสามทั้งที่ไม่มีผู้เข้าชมเลย และหัวตารางของ ps เรียงตามเวลาซีพียูสะสมไม่ใช่เว็บไซต์และไม่ใช่ฐานข้อมูล แต่เป็น CrowdSec, fail2ban, Falco และ Suricata นี่ไม่ใช่ความเสียหายและไม่ใช่เหตุผลให้ปิดมัน แต่ควรรู้ราคาของการป้องกันเป็นตัวเลข: บน VPS เล็ก ๆ จะรู้สึกได้
เฝ้าดูไปเพื่ออะไร
ทั้งหมดข้างต้นตอบคำถามว่า «ตอนนี้เกิดอะไรขึ้น» ส่วนคำถามยามเช้า — ตีสามเกิดอะไรขึ้น — คำสั่งเหล่านี้ตอบไม่ได้: คืนที่ผ่านมาไม่มีข้อมูลอยู่เลยถ้าไม่มีใครบันทึกไว้ และการตั้ง Prometheus กับ Grafana เพื่อ VPS เพียงเครื่องเดียวก็น่าสงสัย เพราะสแตกที่คอยเฝ้าดูกลับหนักกว่าเซิร์ฟเวอร์ที่ถูกเฝ้าดู
เพียงหนึ่งแถวในฐานข้อมูลทุกห้านาทีกับหนึ่งหน้าที่วาดยี่สิบสี่ชั่วโมงล่าสุดจากข้อมูลนั้นก็พอ: load average, การใช้ซีพียูและ I/O wait แยกกัน, หน่วยความจำและ swap, การอ่านและเขียนดิสก์, ความเต็มของพาร์ทิชัน, inode, ตัวระบุไฟล์, การเชื่อมต่อ บนแกนเวลาเดียวกันคู่ต่าง ๆ อ่านได้ด้วยตาเปล่า: wa สูงขณะที่ซีพียูสงบ, swap ที่ไม่เคยกลับมาที่ศูนย์, ตัวระบุไฟล์ที่ใกล้ขีดจำกัด — ข้อผิดพลาด too many open files ที่กำลังจะมาถึงจะมองเห็นล่วงหน้าหลายชั่วโมง ทั้งหมดนี้เมื่อประกอบเข้าด้วยกันมีหน้าตาอย่างไร ดูได้จากหน้าเดโมด้านล่าง