เมื่อออกแบบและพัฒนาระบบที่มีความพร้อมใช้งานสูง แคชเป็นสิ่งที่ต้องพิจารณาที่สำคัญมาก การแคชข้อมูลที่เข้าถึงบ่อยๆ จะมีประโยชน์เพื่อให้เข้าถึงข้อมูลได้อย่างรวดเร็ว และแคชยังสามารถป้องกันระบบปลายทาง เช่น DB จากการถูกเข้าถึงบ่อยเกินไปได้ด้วย
เพื่อให้การออกแบบแคชในระบบขนาดใหญ่ดีขึ้น อาจต้องพิจารณาปัญหาบางอย่างก่อน ในโพสต์นี้ เราจะพูดถึงปัญหาแคชที่มักมีการพูดถึงกันบ่อยๆ และแผนการบรรเทาปัญหา
Cache penetration
Cache penetration เป็นสถานการณ์ที่ข้อมูลที่ต้องการค้นหาไม่มีอยู่ใน DB และชุดผลลัพธ์ที่ว่างเปล่าที่ส่งคืนก็ไม่ได้ถูกแคชไว้ด้วย ดังนั้นทุกครั้งที่ค้นหาคีย์นั้นก็จะเข้าถึง DB ในที่สุด หากแฮกเกอร์พยายามเริ่มการโจมตีโดยการเปิดการค้นหาจำนวนมากด้วยคีย์ดังกล่าว เลเยอร์ DB ที่อยู่เบื้องล่างจะถูกเข้าถึงบ่อยเกินไปและอาจถูกทำให้ล่มได้ในที่สุด
ในกรณีเช่นนี้ มีแผนการบรรเทาปัญหาอยู่สองสามอย่าง
- หากไม่มีข้อมูลสำหรับคีย์ใน DB ให้ส่งคืนผลลัพธ์ที่ว่างเปล่าและแคชไว้ในช่วงเวลาสั้นๆ (อย่าตั้งเวลาหมดอายุที่นาน)
- ใช้ Bloom filter Bloom filter คล้ายกับ hbase set ซึ่งสามารถใช้ตรวจสอบว่ามีคีย์อยู่ในชุดข้อมูลหรือไม่ หากมีคีย์อยู่ ให้ไปที่เลเยอร์แคชหรือเลเยอร์ DB หากไม่มีอยู่ในชุดข้อมูล ก็ให้ส่งคืนเลย
หากคีย์ที่ค้นหามีอัตราการเกิดซ้ำสูง ก็สามารถนำวิธีแก้ปัญหาแรกมาใช้ได้ มิฉะนั้น หากคีย์ที่ค้นหามีอัตราการเกิดซ้ำต่ำและคีย์ที่ค้นหามีจำนวนมากเกินไป ก็สามารถนำวิธีแก้ปัญหาที่สองมาใช้เพื่อกรองคีย์ส่วนใหญ่ออกไปก่อนได้
Cache breakdown
Cache breakdown เป็นสถานการณ์ที่ข้อมูลที่แคชไว้หมดอายุ และในขณะเดียวกันก็มีการค้นหาข้อมูลที่หมดอายุจำนวนมาก ซึ่งทำให้การค้นหาเข้าถึง DB โดยตรงอย่างกะทันหัน และเพิ่มภาระให้กับเลเยอร์ DB อย่างมาก
สิ่งนี้จะเกิดขึ้นในสภาพแวดล้อมที่มีการทำงานพร้อมกันสูง โดยปกติในกรณีนี้ จะต้องมีการล็อกคีย์ที่ค้นหา เพื่อให้เธรดอื่นๆ ต้องรอเมื่อมีเธรดกำลังพยายามค้นหาคีย์และอัปเดตแคช หลังจากที่แคชได้รับการอัปเดตและปลดล็อกแล้ว เธรดอื่นๆ จะสามารถอ่านข้อมูลที่แคชใหม่ได้
อีกวิธีที่เป็นไปได้คือการอัปเดตข้อมูลที่แคชไว้แบบอะซิงโครนัสผ่านเธรด worker เพื่อให้ข้อมูลที่ใช้งานบ่อยไม่หมดอายุ
Cache avalanche
Cache avalanche เป็นสถานการณ์ที่ข้อมูลที่แคชไว้จำนวนมากหมดอายุในเวลาเดียวกัน หรือบริการแคชล่ม และทันใดนั้นการค้นหาข้อมูลทั้งหมดนี้จะเข้าถึง DB และทำให้เกิดภาระสูงกับเลเยอร์ DB และส่งผลกระทบต่อประสิทธิภาพ
เพื่อบรรเทาปัญหา สามารถนำวิธีการบางอย่างมาใช้ได้
- ใช้คลัสเตอร์เพื่อให้แน่ใจว่ามีอินสแตนซ์เซิร์ฟเวอร์แคชบางตัวกำลังให้บริการอยู่ตลอดเวลา หากใช้ Redis ก็สามารถมี redis clusters ได้
- แนวทางอื่นๆ เช่น hystrix circuit breaker และ rate limit สามารถกำหนดค่าได้ เพื่อให้ระบบเบื้องล่างยังคงสามารถให้บริการทราฟฟิกและหลีกเลี่ยงภาระสูงได้
- สามารถปรับเวลาหมดอายุสำหรับคีย์ต่างๆ เพื่อไม่ให้หมดอายุในเวลาเดียวกันได้
วิธีการบรรเทาปัญหาทั้งหมดต้องนำไปใช้ตามกรณีการใช้งานจริงและข้อกำหนดการออกแบบระบบ