In-Memory Cache ง่ายๆ บรรทัดเดียวด้วย Spring Cache

Thanatach Assavarattanakorn
SCB Engineer
Published in
3 min readFeb 28, 2023

สวัสดีผู้อ่านทุกท่านครับผม 👋 หลายๆท่านที่กำลังอ่านอยู่นี้ ผมเชื่อเลยว่าอาจจะต้องคุ้นเคยกับการ Cache ในหลายๆรูปแบบมาไม่มากก็น้อย ไม่ว่าจะเป็นการใช้งานร่วมกับซอฟต์แวร์สุดคุ้นเคยหลากหลายเจ้า ไม่ว่าจะเป็น Redis, Memcached, Apache Ignite แต่รู้หรือไม่ เจ้าตัว Spring ที่เรารักเนี่ย เค้าก็มี Cache สุดแจ่มมาให้ใช้งานเหมือนกันนะ 😮

Photo by Fredy Jacob on Unsplash

ก่อนจะไปเริ่มเรื่องกัน ขอปูทางกันซักนิดนึงนะครับผม 😅 คือเจ้าเทคโนโลยีการ Cache เนี่ย แน่นอนว่ามันเข้ามาทำให้เราประหยัดทั้งเวลา หรือทรัพยากรได้มากโขเลย ไม่ว่าจะเป็นการ Cache ส่วนของหน้าเว็บเมื่อมีผู้ใช้งานระดับมหิมา หน้าเว็บนั้นๆก็ไม่จำเป็นที่จะต้องถูกดึงมาจากต้นทางทุกครั้ง หรือแม้แต่ส่วนของหลังบ้านที่มีการทำ Cache ระหว่าง Database ทำให้เมื่อเรียกข้อมูลที่คาดว่ายังไม่มีการเปลี่ยนแปลง แทนที่จะไปเรียกข้อมูลชุดใหม่มาเลย ก็ส่งข้อมูลที่เก็บไว้ชั่วคราวไว้ก่อนหน้าส่งกลับไปทันทีแทน 😎

Photo by Matt Hudson on Unsplash

แต่อนิจจา ใช่ว่าจะไม่มีข้อเสียนะ เพราะการทำ Cache ที่ออกแบบมาไม่ดี อาจเกิดความวุ่นวายตามมาได้ ….. 🤕

สวัสดี Spring Cache

มาถึงอาหารมื้อหลักของเรากันซักทีนะครับ ฮ่า ๆ 😋 ยังไงขอออกตัวก่อนเลยนะครับ ว่า Feature ที่ผมกำลังพูดเนี่ยพี่แกเขาปล่อยมาตั้งแต่ Spring Framework 3.1 ช่วงปี 2011 แล้วโน่น 🤣 เพราะฉะนั้น สิ่งนี้ไม่ใช่ของใหม่เลยครับ ไม่ต้องไปหาอ่าน Release Log ในเร็ว ๆ นี้กันน้า ฮ่า ๆ

แน่นอนว่าทุกคนก็สามารถเข้าไปสำรวจ New Features and Enhancements in Spring Framework 3.1 ที่มีเรื่องของ Cache Abstraction ได้เช่นกันนะครับ

และซึ่งในแวดวงของซอฟต์แวร์ที่ทำ Cache เนี่ย 🥸 จะมีรูปแบบการทำ Cache หลากหลายมาก ไม่ว่าจะเป็น Distributed caching, Disk-based caching, CDN caching, In-Memory Cache ซึ่งเจ้า Spring Cache ที่เรากำลังพูดอยู่เนี่ย เป็น Cache ในรูปแบบของ In-Memory Cache ครับผมม

Photo by Harrison Broadbent on Unsplash

อย่างย่อๆเลยนะ เจ้า In-Memory Cache เนี่ย คือเก็บลง Memory นั่นแหล่ะ หรือถ้าให้เข้าใจง่ายกว่านั้น ก็คือเก็บลง Ram ที่ Application นั้นจองอยู่นั้นเอง

บรรทัดเดียวจริงๆนะ 🤫

อันดับแรก ก็คงต้องเพิ่ม Dependency เพื่อใช้งาน Cache ของ Spring นะครับ แต่อย่าเพิ่งยกใบแดงใส่นะคร้าบ เพราะ บรรทัดเดียวที่ว่า คือไม่รวมไฟล์ pom.xml นะคร้าบ

spring-boot-starter-cache Dependency

เอาหล่ะ ต่อมาต้องเพิ่ม Annotation สำหรับใช้งาน Cache ใน Spring Application โดยเพิ่ม @EnableCaching

@EnableCaching in Spring Application

ต่อมาเป็นส่วนที่เราจะนำไป implement กับงานของเราแล้ว ซึ่งจาก Code นี้เป็นโจทย์ว่าเราต้องการ Fetch ข้อมูลมาจาก Mock API ตัวนึงที่จะสุ่มประโยคเกี่ยวกับ Fact ของแมว แล้วส่งกลับครับ 👌

Mock API จากลิงค์นี้เลยเผื่อใครอยากเข้าไปดูนะครับ

👉 https://catfact.ninja/fact

เพิ่ม Annotation

@Cacheable(“myCachingName”)

ในส่วนที่เป็น Post Controller ตามโค้ดตัวอย่างสุดเท่ห์นี้ได้เลยนะครับ 🤓 ซึ่ง myCachingName เนี่ย คือชื่อของ Cache นั้นๆซึ่งเราสามารถตั้งเองได้เลยนะครับ

Cacheable(“myCachingName”) annotation

เอาหล่ะ มาทดสอบกัน 🤩

ทดลองยิงไป Path ของ Controller ที่เราสร้างไว้เมื่อซักครู่เลยนะครับจะเห็นได้ว่าใช้เวลาทั้งสิ้น 885 ms ซึ่งอาจจะรู้สึกว่าไม่เยอะ แต่พอมาลองเทียบกับข้อมูลที่ได้ ก็นับว่าไม่คุ้มเลยกับชุดข้อความเพียงแค่นี้ 🤨

Test fetch api controller

แต่ไม่เป็นไรครับ เราจะมาลองยิงรอบที่สองกัน 🙃

ทาด๊า ! 😍 เหลือ 5 ms แล้วนะครับ เป็นเพราะในรอบแรกนั้น Controller เราเพิ่งได้มีโอกาส เข้าถึงข้อมูลเป็นครั้งแรก และเพิ่ง Cache ข้อมูลชุดนั้นเอาไว้ครับ และรอบต่อมาเมื่อมีการเรียกข้อมูลชุดเดิม Spring ก็จะเอา Cache ที่เก็บไว้มาแสดงแทนครับ 😗

Test fetch api controller

เป็นไงหล่ะครับ บอกแล้วว่าบรรทัดเดียวจริง ๆ ฮ่า ๆ แต่สำหรับหลายๆท่านอย่าเพิ่งส่ายหัวนะครับผม เพราะจริง ๆ แล้วเนี่ย Cache ใน Spring นั้นยังมีความสามารถที่มากกว่าที่ผม Demo ให้ดูมากนัก และแน่นอนผมกำลังแนะนำให้ทุกท่านไปอ่าน Doc เพิ่มเติมจากทาง Spring ครับ แฮ่ะๆ 😅 👉 Cache Abstraction

เราได้เรียนรู้อะไรจากแลปนี้บ้างนะ 🧐

จากแลปที่เราได้ทดลองกันไปนั้น จะเห็นได้ว่าการทำ Cache ลดเวลาเรียกข้อมูลของเราได้จริง แต่ทุกคนสังเกตเห็นอะไรไหมครับ ให้โอกาสหยุดสายตาจากบทความแล้วเลื่อนไปดูอีกครั้งนะครับ ติ๊กต็อก ๆ … 🤐

เฉลย ! ✌️

จากเนื้อหาหลักของเรานั้น ตามที่ได้อธิบายไปข้างต้นนะครับ ว่าการ Cache นั้นมันทำให้เร็วขึ้นจริง เพราะเป็นการนำข้อมูลจากปลายทางมาพักเก็บไว้ และไม่เรียกซ้ำอีก เพราะฉะนั้น จะสังเกตุได้ว่า การเรียกครั้งที่สองของเราที่เวลาเหลือเพียง 5 ms จะเป็นข้อมูลเดียวกับชุดแรก ทั้งๆที่การทำงานของ Mock API ที่เป็นโจทย์ของเรานั้น จะสุ่มประโยคใหม่ ๆ ออกมาเสมอ 😦 ดังนั้น แลปนี้ก็เป็นอีกหนึ่งตัวอย่างที่ดีเลยครับ ที่จะแสดงให้เห็นถึงการวางแผนการใช้ Cache ว่าหากวางแผนไม่ดี Logic ที่วางไว้ก็อาจจะผิดเพี้ยนไปได้ครับ 😱

ตัวอย่างการทำ Cache ที่น่าสนใจ

  • Cache ในกรณีที่ตัวแปร userId ที่ส่งเข้ามาเป็น 123 เท่านั้น
Cache with condition
  • ล้าง Cache ของ userIdList ทั้งหมด
CacheEvict Annotation
  • Update Cache ของ userId
CachePut Annotation

จะเห็นได้ว่าความสามารถของ Annotation Cache ของ Spring นั้น สามารถไปประยุกต์ได้หลากหลายมาก 😲 ซึ่งถ้าในความเห็นของผมนั้น ถ้าเป็นโปรเจ็คที่ไม่ใหญ่มาก มีโครงสร้างที่ไม่ได้ซับซ้อนมากมาย และต้องการหลีกเลี่ยงการใช้ Third-Party อื่นๆมาทำ Cache แล้วยังอยากได้เครื่องมือที่ Learning Curve ต่ำๆละก็ Spring Cache อันนี้หล่ะตอบโจทย์เลย

Reference

--

--

Thanatach Assavarattanakorn
SCB Engineer

Software Engineer, QA spin my head right round right round