![translation](https://cdn.durumis.com/common/trans.png)
นี่คือโพสต์ที่แปลด้วย AI
เลือกภาษา
สรุปโดย AI ของ durumis
- แคชเป็นเทคนิคในการจัดเก็บข้อมูลที่อ่านบ่อยและเขียนน้อยเพื่อเพิ่มประสิทธิภาพของบริการ และสามารถเลือกเป้าหมายของการแคชโดยการวิเคราะห์ประวัติการเรียกใช้คิวรีของ RDB ผ่านทาง APM เช่น DataDog
- การแคชแบบโลคัลเป็นวิธีการจัดเก็บข้อมูลแคชในหน่วยความจำของเซิร์ฟเวอร์แอปพลิเคชัน ซึ่งมีความเร็วสูง แต่ปัญหาคือการซิงค์ข้อมูลแคชระหว่างอินสแตนซ์ ในขณะที่การแคชแบบโกลบอลใช้เซิร์ฟเวอร์แยกต่างหาก เช่น Redis เพื่อจัดเก็บข้อมูลแคช ซึ่งทำให้สามารถแชร์กันระหว่างอินสแตนซ์ แต่ความเร็วอาจช้าลงเนื่องจากการจราจรทางเครือข่าย
- ใช้ TTL (Time To Live) เพื่ออัปเดตแคช และโดยทั่วไปแล้วจะตั้งค่า TTL เป็นหน่วยเวลาขึ้นไปหาก read/write เกิดขึ้นบนเซิร์ฟเวอร์เดียว และตั้งค่า TTL เป็นหน่วยวินาทีหรือหน่วยนาที หากเกิดขึ้นบนเซิร์ฟเวอร์หลายเครื่อง
สวัสดีครับ ผมเจย์ออน
วันนี้ผมจะมาอธิบายเกณฑ์การตั้งค่าแคชนะครับ เนื่องจากเป็นบทความที่ผมเขียนจากประสบการณ์ทำงานจริง ดังนั้นโปรดรับทราบว่าเป็นเพียงข้อมูลอ้างอิง เท่านั้น ㅎㅎ
แคชคืออะไร?
แคชหมายถึงการเก็บผลลัพธ์ของการร้องขอไว้ล่วงหน้าเพื่อให้บริการได้รวดเร็วขึ้น นั่นคือ การเก็บผลลัพธ์ไว้ล่วงหน้าแล้วเมื่อมีการร้องขอ จะไม่ต้องอ้างอิง DB หรือ API แต่เข้าถึงแคชเพื่อประมวลผลการร้องขอ หลักการของแคชนี้เกิดขึ้นจากกฎของ Pareto
กฎของ Pareto หมายถึง 80% ของผลลัพธ์เกิดจาก 20% ของสาเหตุ คุณอาจจะดูรูปภาพด้านล่างเพื่อให้เข้าใจได้ง่ายขึ้น!
นั่นคือ แคชไม่จำเป็นต้องแคชผลลัพธ์ทั้งหมด แต่แคชเพียง 20% ที่ใช้บ่อยที่สุดในเวลาให้บริการ เพื่อเพิ่มประสิทธิภาพโดยรวม
ควรแคชข้อมูลอะไร?
ตามกฎของ Pareto เราไม่ควรแคชข้อมูลทั้งหมด แต่ควรแคชเฉพาะข้อมูลที่จำเป็น แล้วข้อมูลประเภทไหนที่ควรแคช?
ข้อมูลที่ต้องอ่านบ่อย แต่เขียนน้อย
โดยทั่วไปมักพูดกันว่า “ควรแคชข้อมูลที่ต้องอ่านบ่อย แต่เขียนน้อย” แต่เกณฑ์ “อ่านบ่อย” และ “เขียนน้อย” นั้นคลุมเครือมาก
ดังนั้น ผมจึงตรวจสอบข้อมูลที่จะแคชโดยใช้ขั้นตอนต่อไปนี้
- ตรวจสอบประวัติการเรียกใช้แบบสอบถาม RDB TOP 5 ผ่าน APM เช่น DataDog
- จากนั้นค้นหาแบบสอบถามการค้นหาและตรวจสอบว่าแบบสอบถามนั้นมาจากตารางใด
- ตรวจสอบจำนวนการเรียกใช้แบบสอบถามการอัปเดตในตารางนั้น
การทำเช่นนี้จะช่วยให้เห็นว่าแบบสอบถามการค้นหาเกิดขึ้นบ่อย แต่แบบสอบถามการอัปเดตเกิดขึ้นน้อย ตารางที่ผมตรวจสอบในงานจริงมีแบบสอบถาม การค้นหาเกิดขึ้นวันละ 1.74 ล้านครั้ง แต่แบบสอบถามการอัปเดตมีเพียง 500 ครั้งเท่านั้น นี่อาจถือว่าเป็นเงื่อนไขที่เหมาะสมกับการแคช ㅎㅎ
ข้อมูลที่ไวต่อการอัปเดต
ข้อมูลที่ไวต่อการอัปเดตหมายความว่าความไม่ตรงกันระหว่าง RDB และแคชต้องสั้น ดังนั้น แม้ข้อมูลจะตรงกับเงื่อนไขการแคชด้านบน แต่ก็ต้อง พิจารณาอย่างรอบคอบสำหรับข้อมูลที่เกี่ยวข้องกับการชำระเงิน เนื่องจากข้อมูลประเภทนี้ไวต่อการอัปเดตมาก
ผมต้องแคชตารางที่เกี่ยวข้องกับการชำระเงินที่ตรงกับลักษณะทั้งสองข้อข้างต้น ดังนั้น ผมจึงไม่ได้ใช้แคชในทุกตรรกะที่ใช้ตาราง ที่เกี่ยวข้องกับการชำระเงิน แต่ได้ตัดสินใจที่จะใช้แคชบางส่วนกับตรรกะที่ปลอดภัยกว่า ซึ่งไม่มีการชำระเงินจริง
การแคชแบบโลคัลเทียบกับการแคชแบบทั่วโลก
ตอนนี้เรารู้แล้วว่าควรแคชข้อมูลอะไรและขอบเขตของการแคช แต่เราต้องตัดสินใจว่าจะ “เก็บ” ข้อมูลแคชไว้ที่ไหน โดยทั่วไป สามารถเก็บข้อมูลแคชไว้ในหน่วยความจำโลคัลหรือเซิร์ฟเวอร์แยกต่างหาก เช่น Redis
การแคชแบบโลคัล
การแคชแบบโลคัลคือวิธีการเก็บข้อมูลแคชไว้ในหน่วยความจำของเซิร์ฟเวอร์แอปพลิเคชัน โดยทั่วไปมักใช้ Guava cache หรือ Caffeine cache
ข้อดี
- เนื่องจากสามารถเรียกใช้แบบสอบถามแคชได้จากหน่วยความจำภายในเซิร์ฟเวอร์เดียวกันกับที่ดำเนินการตรรกะของแอปพลิเคชัน จึงทำให้มีความเร็วสูง
- ใช้งานง่าย
ข้อเสีย
- หากมีอินสแตนซ์หลาย ๆ อินสแตนซ์ อาจเกิดปัญหาหลายอย่าง
- ไม่สามารถเผยแพร่แคชที่ถูกแก้ไขในอินสแตนซ์หนึ่งไปยังอินสแตนซ์อื่นได้ แต่มีไลบรารีแคชแบบโลคัลที่สามารถเผยแพร่การ แก้ไขไปยังอินสแตนซ์อื่นได้
- เนื่องจากแต่ละอินสแตนซ์มีการเก็บแคชไว้ ดังนั้นเมื่อมีอินสแตนซ์ใหม่เปิดขึ้น จะต้องใส่แคชใหม่ จึงทำให้เกิดแคช miss บ่อยครั้ง ส่งผลให้ทราฟฟิกไม่สามารถรับไหวและอินสแตนซ์ล่มได้
การแคชแบบทั่วโลก
การแคชแบบทั่วโลกคือวิธีการใช้เซิร์ฟเวอร์แยกต่างหาก เช่น Redis เพื่อเก็บข้อมูลแคช
ข้อดี
- สามารถแชร์แคชระหว่างอินสแตนซ์ ดังนั้นการแก้ไขแคชในอินสแตนซ์หนึ่งจะทำให้ทุกอินสแตนซ์ได้รับค่าแคชเดียวกัน
- เมื่อเปิดอินสแตนซ์ใหม่ จะสามารถดูที่ที่เก็บแคชเดิมได้ จึงไม่จำเป็นต้องใส่แคชใหม่
ข้อเสีย
- ต้องผ่านการรับส่งข้อมูลบนเครือข่าย จึงทำให้ความเร็วช้ากว่าการแคชแบบโลคัล
- ต้องใช้เซิร์ฟเวอร์แคชแยกต่างหาก จึงทำให้เกิดค่าใช้จ่ายในการดูแลระบบ
- ค่าใช้จ่ายในการดูแลระบบ? → ค่าใช้จ่ายของเซิร์ฟเวอร์ เวลาในการตั้งค่าและบำรุงรักษาอินฟราสตรักเจอร์ การวางแผนการจัดการความผิดพลาด ฯลฯ
ผมเลือกแบบไหน?
ปัจจุบันเซิร์ฟเวอร์แอปพลิเคชันของบริษัทของผมมีการเปิดหลาย ๆ อินสแตนซ์ แต่ผมเลือกใช้การแคชแบบโลคัล
เหตุผลหลัก ๆ มี 3 ประการ
- ข้อมูลที่จะแคชใน RDB มีประมาณ 40,000 รายการ ดังนั้นการนำข้อมูลทั้งหมดขึ้นบนหน่วยความจำจะใช้พื้นที่ไม่เกิน 4 MB
- ต้องการให้ประสิทธิภาพการค้นหาข้อมูลที่เกี่ยวข้องกับการชำระเงินดีขึ้น
- มี Redis อยู่แล้ว แต่การเก็บแคชใหม่ไว้ใน Redis จะทำให้เกิดค่าใช้จ่ายในการดูแลระบบ
จะอัปเดตแคชอย่างไร?
หากมีเซิร์ฟเวอร์แอปพลิเคชันหลาย ๆ ตัวและใช้การแคชแบบโลคัล ค่าแคชที่เก็บไว้ในแต่ละเซิร์ฟเวอร์แอปพลิเคชันอาจแตกต่างกัน ตัวอย่างเช่น ค่าแคชที่เก็บไว้ในเซิร์ฟเวอร์ A คือ “1” แต่ค่าแคชที่เก็บไว้ในเซิร์ฟเวอร์ B คือ “2” ซึ่งอาจถูกแก้ไขในเซิร์ฟเวอร์ B เมื่อผู้ใช้ส่งคำร้องไปยังล็อดบาลานเซอร์ จะทำให้เซิร์ฟเวอร์ A และ B ส่งกลับค่าที่แตกต่างกัน
ดังนั้น เราจำเป็นต้องกำหนดค่าให้แต่ละอินสแตนซ์ลบแคชโดยอัตโนมัติเพื่อค้นหาข้อมูลจาก RDB ในกรณีนี้มักใช้ TTL
ควรตั้งค่า TTL เป็นเท่าไหร่?
TTL ย่อมาจาก Time To Live ซึ่งเป็นการตั้งค่าที่ใช้ลบแคชเมื่อเวลาผ่านไป ตัวอย่างเช่น หากตั้งค่า TTL เป็น 5 วินาที ข้อมูลแคชจะถูกลบโดยอัตโนมัติหลังจาก 5 วินาที จากนั้นจะเกิดแคช miss และจะค้นหาข้อมูลจาก RDB และบันทึกไว้
แล้วควรตั้งค่า TTL เป็นเท่าไหร่?
read/write เกิดขึ้นในเซิร์ฟเวอร์แคชเดียว
หาก read/write เกิดขึ้นในเซิร์ฟเวอร์แคชทั่วโลก เช่น Redis เพียงเซิร์ฟเวอร์เดียว หรือเกิดขึ้นในเซิร์ฟเวอร์แอปพลิเคชันเพียง เซิร์ฟเวอร์เดียวที่มีการแคชแบบโลคัล การตั้งค่า TTL เป็นหน่วยเวลาหรือมากกว่านั้นก็ไม่เป็นไร เพราะเมื่อใดก็ตามที่มีการ write แคชเก่าจะถูกแก้ไข และเซิร์ฟเวอร์ที่ดึงข้อมูลจากแคชนั้นจะได้รับข้อมูลล่าสุดเสมอ
ในกรณีนี้ เราสามารถกำหนดค่าให้เซิร์ฟเวอร์แคชลบแคชออกทีละน้อยโดยใช้ Algorithm LRU เมื่อแคชเต็มโดยไม่ต้องตั้งค่า TTL
read/write เกิดขึ้นในเซิร์ฟเวอร์แคชหลาย ๆ เซิร์ฟเวอร์
หาก read/write เกิดขึ้นในเซิร์ฟเวอร์แคชแบบกระจายหลาย ๆ เซิร์ฟเวอร์ หรือเกิดขึ้นในเซิร์ฟเวอร์แอปพลิเคชันหลาย ๆ เซิร์ฟเวอร์ที่ใช้ การแคชแบบโลคัล การตั้งค่า TTL เป็นหน่วยวินาทีถึงนาทีจะดีกว่า เพราะอาจมีโอกาสที่เซิร์ฟเวอร์แคชจะอ่านข้อมูลเก่าที่ยังไม่ได้ อัปเดต
การตั้งค่า TTL ในกรณีนี้จะขึ้นอยู่กับหลาย ๆ ปัจจัย ยิ่งข้อมูลสำคัญและมีโอกาสเปลี่ยนแปลงค่ามากเท่าไหร่ ก็ยิ่งต้องตั้งค่า TTL ให้สั้นลง และยิ่งข้อมูลไม่สำคัญและมีโอกาสเปลี่ยนแปลงค่าน้อยเท่าไหร่ ก็ยิ่งสามารถตั้งค่า TTL ให้ยาวขึ้นได้
ผมตั้งค่า TTL อย่างไร?
ข้อมูลที่ผมจะแคชนั้นเป็นข้อมูลที่เกี่ยวข้องกับการชำระเงิน และแม้ว่าผมจะไม่ได้ใช้แคชในตรรกะที่เกิดการชำระเงินจริง ๆ แต่โดยธรรมชาติของการชำระเงินนั้น ต้องอัปเดตข้อมูลให้ทันเวลา แต่เนื่องจากมีโอกาสอัปเดตน้อย ดังนั้นผมจึงตั้งค่า TTL เป็น 5 วินาทีเพื่อความปลอดภัย
สรุป
สรุปแล้ว วิธีการแคชที่ผมเลือกคือ
- ข้อมูลที่เกี่ยวข้องกับการชำระเงิน
- มีการค้นหาบ่อยมาก แต่แทบไม่มีการแก้ไข
- ใช้แคชเฉพาะตรรกะที่ไม่มีการชำระเงินจริง แต่มีการค้นหาข้อมูล
- ใช้การแคชแบบโลคัลและตั้งค่า TTL เป็น 5 วินาที
สิ่งที่ต้องทำต่อไปคือการทดสอบประสิทธิภาพสำหรับวิธีการแคชที่ใช้จริง ขณะนี้ยังไม่ได้วางแผนว่าจะทำการทดสอบประสิทธิภาพ อย่างไร ดังนั้นผมจะเขียนบทความต่อไปเพื่ออธิบายขั้นตอนการทดสอบประสิทธิภาพ!