Back to notes
mastery-data-sql
Featured

Caching Mastery: ศิลปะแห่งการจำเพื่อให้ระบบไม่ล่ม

Cache คือยาเสพติดของวงการ Tech ใส่แล้วเร็วปรี๊ด! แต่ถ้าวางแผนการ Invalidate ไม่ดี ข้อมูลจะผิดเพี้ยนจนแก้ไม่ตก เจาะลึกกลยุทธ์การทำ Cache ระดับ Senior

January 30, 20262 min read readNNexis by Seereen

🛑 1. The Problem First: "ข้อมูลผีหลอก" (Stale Data & DB Crash)

ลองนึกถึงแอปที่มีคนเข้าเยอะๆ แล้วคุณพยายามจะลดภาระ Database โดยการใส่ Cache:

HLJS JAVASCRIPT
// ❌ Naive Approach: ใส่ Cache แบบไม่มีวันตาย (No TTL)
const user = await redis.get("user:1");
if (!user) {
  const data = await db.user.find(1);
  await redis.set("user:1", data); // 🌋 ระเบิดเวลา! ถ้า User เปลี่ยนชื่อ
  // Cache เดิมจะยังคงชื่อเก่าไว้ตลอดกาล จนกว่า Server จะรีสตาร์ท!
}

ปัญหา: การใส่ Cache โดยไม่มีกลยุทธ์การลบ (Invalidation) จะทำให้เกิด "ข้อมูลไม่ตรงกัน" (Inconsistency) ซึ่งเป็นฝันร้ายของงานพาณิชย์ และที่แย่กว่านั้นคือถ้า Cache หมดอายุพร้อมกันหมื่นคน (Thundering Herd) Database ของคุณที่ไม่ได้เตรียมรับแรงกระแทกจะล่มสลายทันที นี่คือสาเหตุที่ Senior ต้องมองการ Cache เป็นเรื่องของ "การจัดการเวลา" ครับ


💡 2. Real-Life Analogy: สมุดจดออเดอร์หน้าเคาน์เตอร์

  • Cache-Aside (Lazy Loading): เหมือน "คนรับออเดอร์ที่จดเมนูโปรดไว้ในหัว". ถ้าลูกค้าสั่งเมนูที่มีในหัว (Hit) เขาก็ทำได้เลย ถ้าไม่มี (Miss) เขาต้องเดินไปดูตำราหลังบ้าน (Database) แล้วจดลงในกระดาษโน้ตแปะไว้ดูครั้งหน้า
  • Write-Through: เหมือนการ "จดออเดอร์ลงสมุดและส่งเข้าครัวพร้อมกัน". ข้อมูลในมือคนรับกับในครัวจะตรงกันเสมอ แต่พนักงานจะทำงานช้าลงนิดนึงเพราะต้องเขียนสองรอบ
  • TTL (Time to Live): เหมือน "อาหารที่ต้องมีวันหมดอายุ". แม้จะยังขายไม่หมด แต่ถ้าเกินเวลาที่กำหนด เราต้องทิ้ง (ลบ Cache) เพื่อความปลอดภัยของลูกค้า (ความถูกต้องของข้อมูล)

🚀 3. Execution Journey: ขั้นตอนการจำแบบเซียน (Cache-Aside)

เราจะใช้ Redis เป็นหน่วยความจำเสริมเพื่อช่วยลดภาระ Database

🛠 Step-by-step:

  1. The Request: แอปมองหาข้อมูลใน Redis (ความเร็วระดับ Millisecond)
  2. The Decision:
    • HIT: คืนข้อมูลทันที (จบงาน!)
    • MISS: เดินไปดึงข้อมูลจาก Database ที่ช้ากว่า 100 เท่า
  3. The Populate: นำข้อมูลใหม่ที่ได้มาใส่ใน Redis พร้อมตั้งเวลาตาย (TTL)
  4. The Buffer: เพิ่มค่า "Jitter" สุ่มเวลาหมดอายุ (เช่น 5 นาที +/- 10 วินาที) เพื่อไม่ให้ Cache ทุุกตัวตายพร้อมกัน
HLJS TYPESCRIPT
// ✅ Best Practice: กลยุทธ์ Cache-Aside พร้อมความปลอดภัย
async function getProduct(id: string) {
  const cacheKey = `product:${id}`;
  const cached = await redis.get(cacheKey);

  if (cached) return JSON.parse(cached); // ⚡ เร็วแรง!

  const product = await db.product.find(id);
  if (product) {
    // 🛠 ตั้งเวลาตาย 5 นาที + สุ่มเพิ่มลดเล็กน้อย (Prevent Thundering Herd)
    await redis.set(
      cacheKey,
      JSON.stringify(product),
      "EX",
      300 + Math.random() * 10,
    );
  }
  return product;
}

🪤 4. The Junior Trap: โรค "Cache ทุกอย่างที่ขวางหน้า"

จูเนียร์มักจะใส่ Cache ให้กับข้อมูลที่เปลี่ยนสีได้ตลอดเวลา:

HLJS JAVASCRIPT
// ❌ Junior Trap: ใส่ Cache ให้กับยอดเงินคงเหลือ (User Balance)
await redis.set(`balance:${userId}`, 100);
// 🌋 พัง! ถ้ายอดเงินจริงถูกหักไปแล้ว แต่ Cache ยังบอกว่ามี 100
// User อาจจะกดถอนเงินได้เกินจำนวนจริง (Double Spending)

ระวัง: อย่า Cache ข้อมูลที่ "ความผิดพลาดมีราคาแพง" ✅ การแก้ไข: ข้อมูลด้านการเงินหรือสถานะที่ต้อง Real-time 100% ควรดึงจาก Database ที่เป็น "Single Source of Truth" เท่านั้น


⚖️ 5. The Why Matrix: เลือกกลยุทธ์ให้ถูกงาน

กลยุทธ์ข้อดี (Pro)ข้อด้อย (Con)เหมาะกับ
Cache-Aside⚡ ประหยัดทรัพยากรRequest แรกช้า (Cold Start)ข้อมูลทั่วไป (Catalog)
Write-Through⚡⚡ ข้อมูลแม่นยำเสมอเขียนข้อมูลช้าลงข้อมูลสำคัญที่อ่านบ่อย
TTL Onlyง่ายที่สุด ไม่ต้องคุมเยอะข้อมูลอาจเก่าชั่วคราวข้อมูลที่ไม่ซีเรียสมาก
Manual Invalidate🚀 แม่นยำที่สุดเขียนโค้ดยาก (ซับซ้อน)ระบบต้องการความเป๊ะสูง

🎓 6. Senior Mindset Summary

การเป็น Senior คือการมองว่า "Cache ไม่ใช่คำตอบของทุุกปัญหา Performance". ก่อนจะใส่ Cache จงลอง Optimize Database ของคุณให้ดีที่สุดก่อน เพราะ Cache ที่ดีที่สุดคือ Cache ที่ 'ไม่มีอยู่จริง' แต่ระบบยังทำงานได้รวดเร็วด้วยตัวเองครับ!

Share this note

© 2026 My Notes by Seereen