🛑 1. The Problem First: "Server ตายเงียบ" (Memory Leak & CPU Spike)
ลองนึกถึงแอปที่รันไปสักพักแล้วจู่ๆ ก็ดับ (Crash) หรืออืดจน User เข้าไม่ได้:
// ❌ Naive Approach: เก็บข้อมูล User ในตัวแปร Global โดยไม่มีวันลบ
const activeUsers = []; // 🌋 ระเบิดเวลา! ทุกคนที่เข้ามาจะถูกเก็บไว้ที่นี่ตลอดกาล
app.get("/login", (req, res) => {
activeUsers.push(req.user); // แรมจะเพิ่มขึ้นเรื่อยๆ จนเต็ม (Memory Leak)
res.send("Logged in");
});
ปัญหา: Node.js ทำงานบน Single Thread ถ้าคุณทำเรื่องที่กิน CPU หนักๆ (Sync tasks) หรือทำตัวแปรค้างไว้ใน RAM ระบบจะ "หยุดหายใจ" ทันที (Event Loop Lag) และ Request อื่นๆ ทั้งโลกรวมถึงการเช็ค Health Check จะค้างตามไปด้วย นี่คือเหตุผลที่ Senior ต้องรู้ว่า "ข้างในเครื่องยนต์กำลังทำอะไรอยู่" ครับ
💡 2. Real-Life Analogy: ร้านอาหารที่มีเชฟคนเดียว (Single Thread)
- Event Loop: เหมือน "เชฟที่ทำงานเร็วมาก". เขาทำหน้าที่แค่หยิบงานใส่เตา (Delegate) แล้วไปทำอย่างอื่นต่อ ถ้างานไหนใช้เวลา (ยิง API/DB) เขาจะไม่ยืนรอ
- CPU Block (Sync Task): เหมือนการสั่งเชฟว่า "จงนั่งปอกกระเทียม 1 ล้านลูกให้เสร็จก่อนค่อยทำอย่างอื่น". เชฟจะขยับไปไหนไม่ได้เลย ลูกค้าโต๊ะอื่นจะไม่ได้กินข้าวแม้จะสั่งแค่ไข่ดาว (Event Loop Lag)
- Memory Leak: เหมือนการสะสม "จานสกปรกไว้เต็มโต๊ะ" แล้วไม่เคยเอาไปล้าง. พื้นที่ในครัวจะน้อยลงเรื่อยๆ จนสุดท้ายเชฟไม่มีที่ขยับตัวและต้องปิดร้าน (Crash)
🚀 3. Execution Journey: ภารกิจตามล่ารูรั่ว (Profiling)
เมื่อ Server เริ่มอืด Senior จะไม่เดาสุ่ม แต่จะใช้เครื่องมือ Profiling
🛠 Step-by-step:
- The Inspector: รัน Node ด้วย Flag
--inspectเพื่อเปิดพอร์ตให้ Chrome เข้าไปดูไส้ใน - Heap Snapshot: ถ่ายรูปหน่วยความจำ (Snap 1) ตอนเริ่ม และถ่ายอีกรูป (Snap 2) ตอนแรมสูง
- Comparison: นำมาเทียบ "Diff" กัน เพื่อดูว่า Object ไหนที่งอกออกมาแล้วไม่ยอมหายไป (Garbage Collector ไม่เก็บ)
- Flame Graph: ดูกราฟเปลวไฟ เพื่อหาว่าฟังก์ชันไหนที่ "แถบแนวนอนยาวผิดปกติ" (นั่นคือจุดที่กิน CPU นานที่สุด)
# ✅ Best Practice: เปิดโหมดตรวจสอบ
node --inspect app.js # 🛠 แล้วเปิด chrome://inspect เพื่อเริ่มล่าบอส (Bugs)
🪤 4. The Junior Trap: โรค "Sync ใน Request"
จูเนียร์มักจะใช้ฟังก์ชันที่มีคำว่า Sync เพราะมันเขียนง่าย:
// ❌ Junior Trap: ขวางทางด่วนด้วยสิ่งกีดขวาง
app.get("/read-config", (req, res) => {
const data = fs.readFileSync("large-file.txt"); // 🌋 พัง! คนอื่นทั้งเครื่องจะหยุดรอจนกว่าไฟล์นี้จะอ่านเสร็จ
res.send(data);
});
ระวัง: คำว่า Sync ใน Node.js คือยาพิษสำหรับ High Traffic
✅ การแก้ไข: ใช้ fs.promises หรือเวอร์ชัน Callback เสมอ เพื่อให้เชฟ (Thread) ขยับไปรับงานคนอื่นได้ในขณะที่รอไฟล์โหลด
⚖️ 5. The Why Matrix: CPU vs Memory Problems
| หัวข้อ | ปัญหา CPU (Process) | ปัญหา Memory (RAM) |
|---|---|---|
| อาการ | เว็บหน่วง, พัดลมเครื่องดัง, CPU 100% | เว็บดับ (Crash), แรมเพิ่มเป็นขั้นบันได |
| สาเหตุหลัก | Loop เยอะเกิน, คำนวณ Hash, Regex หนักๆ | ลืมลบ Global, Closure ค้าง, Listener รั่ว |
| เครื่องมือแก้ | Flame Graph / Performance Tab | Heap Snapshot / Allocation Timeline |
| ผลกระทบ | กระทบทุก Request ทันที | ค่อยๆ ป่วย จนสุดท้ายตายสนิท |
🎓 6. Senior Mindset Summary
การเป็น Senior คือการมองว่า "ความเร็วไม่ใช่แค่เรื่องของอัลกอริทึม แต่คือเรื่องของการบริหารจัดการเวลาของระบบ (Event Loop Management)". เว็บที่เสถียรไม่ใช่เว็บที่ไม่มีบั๊ก แต่คือเว็บที่เรารู้ว่า 'รูรั่ว' อยู่ตรงไหนและอุดมันได้ก่อนที่จะเกิดเรื่องใหญ่ครับ!