☕ 5-Min Tech Story #30

Cache Penetration: เมื่อของไม่มีอยู่จริง กลายเป็นอาวุธเจาะทะลุเกราะ Redis ถล่ม Database

⏱️ ใช้เวลาอ่านประมาณ: 4 นาที 25 วินาที

คุณตั้งค่า Redis ไว้เป็นเกราะหน้าบ้านอย่างแน่นหนา ข้อมูลสินค้ายอดฮิตถูกแคชไว้ครบถ้วน Hit Rate สูงถึง 95%

คืนหนึ่ง มีสคริปต์ลึกลับยิงขอข้อมูลสินค้าด้วย ID แปลกๆ เข้ามาแบบรัวๆ: /products/-9999, /products/abc_fake_id, /products/999999999 นับแสนคำขอต่อวินาที

Redis ยืนงงเพราะค้นหา Key เหล่านี้ไม่เจอ... แล้วสิ่งที่เกิดขึ้นคือ คำขอทั้งหมดพุ่งทะลุผ่าน Redis วิ่งตรงลงไปกระแทก Database หลัก 100% เต็มๆ! ฐานข้อมูลเริ่มค้าง CPU พุ่งแตะ 100% แล้วทั้งระบบก็น็อกสนิท เกราะ Redis ที่ลงทุนสร้างไว้กลายเป็นไร้ความหมายในพริบตา

🕳️ กระสุนทะลวงเกราะ (Cache Penetration)

ในวงการแคช มีบั๊ก 2 ตัวที่ชื่อคล้ายกันแต่คนมักจำสลับ:

เพราะโค้ดแบบ Cache-Aside ส่วนใหญ่เขียนไว้แบบซื่อๆ:

val data = redis.get(id)
if (data == null) {
  val dbData = database.findById(id) // ค้นหาใน DB
  if (dbData != null) {
    redis.set(id, dbData)
  }
  return dbData // ถ้าหาไม่เจอ ก็คืน null โดยไม่แคชอะไรเลย!
}
"เมื่อ ID ไม่มีอยู่จริงใน DB โค้ดจะไม่บันทึกอะไรลง Redis เลย ทำให้ทุกครั้งที่ยิงขอ ID ขยะนี้เข้ามา มันจะวิ่งทะลุลงไปรบกวน Disk ของ Database ทุกรอบโดยไม่มีเกราะดักไว้แม้แต่ชั้นเดียว!"

🛡️ 2 คาถาอุดรอยรั่ว: แคชค่าว่าง & Bloom Filter

1. แคชความว่างเปล่าไว้สั้นๆ (Cache Null Values):

ถ้าลงไปถาม Database แล้วพบว่าไม่มีของ ให้บันทึกค่าว่าง (เช่น "" หรือ "NULL") ลงใน Redis ไว้ด้วย พร้อมตั้งเวลาหมดอายุสั้นๆ สัก 1-2 นาที:

if (dbData == null) {
  // บันทึกบอกไว้เลยว่า ID นี้ไม่มีของนะ หมดอายุใน 60 วิ
  redis.set(id, "EMPTY_MARKER", ttl = 60)
}

เมื่อ Request ถัดไปยิงขอ ID ปลอมนี้ซ้ำมาอีก Redis จะตอบดักไว้ทันทีว่าไม่มีของ โดยไม่ต้องให้ Database เสียแรงค้นหา

2. ตะแกรงร่อนความจริงระดับเทพ: Bloom Filter

ถ้าผู้โจมตีสุ่ม ID มั่วไม่ซ้ำกันเลย การแคชค่าว่างจะทำให้ Redis แรมบวมได้ ทางออกระดับวิศวกรรมคือใช้ Bloom Filter (เช่น โมดูล RedisBloom)

Bloom Filter คือโครงสร้างข้อมูลแบบประหยัดบิต ที่ใช้พื้นที่เพียงไม่กี่เมกะไบต์ในการจดจำ ID สินค้าหลายสิบล้านชิ้น โดยมีคุณสมบัติทางคณิตศาสตร์สุดอัศจรรย์:

💡 5-Min Takeaway

"ระบบที่แข็งแกร่งต้องรับมือกับข้อมูลที่ 'ไม่มีอยู่' ได้ดีพอๆ กับข้อมูลที่มีอยู่" อย่าปล่อยให้การค้นหาไม่เจอ (Missed Query) กลายเป็นช่องโหว่ที่ผู้ไม่หวังดีใช้ยิงถล่มฐานข้อมูลทางอ้อม การบันทึก Null Object ลงแคชแบบมี TTL หรือวางแนวป้องกันด้วย Bloom Filter ตั้งแต่ต้นทาง คือเกราะป้องกันชั้นยอดที่จะทำให้ Database ของคุณนอนหลับได้อย่างปลอดภัย