มาลองทำ Caching ด้วย Node.js และ Redis กันดีกว่า
สวัสดีครับ วันนี้เราจะมาลองทำการ Caching เพื่อเพิ่มความเร็วให้กับเว็บไซต์ของเราครับ ด้วย Redis
และสำหรับคนชอบเวอร์ชั่น Video Tutorial ผมอัพโหลดเป็น Youtube อีกช่องทางครับ
Link Youtube : https://www.youtube.com/watch?v=vCqvhSWEwR8
ข้อดีของการ Caching คือ เวลาที่เราทำการเรียก Service เดิมซ้ำๆ แทนที่จะต้องไป Query ฐานข้อมูล หรือ ไปดึงข้อมูลจาก Service อื่นๆมา ทั้งๆที่มันก็เหมือนเดิม ทำไมเราไม่ caching มันซะเลยหละ ทุกครั้งที่ข้อมูลเดิมถูกเรียก เราก็ใช้ได้เลย ไม่ต้องไป query ใหม่
ซึ่งการ Caching จริงๆมันมีหลาย Level ครับ Caching ที่ระดับ client ก็ได้ พวก web browser หรือ caching ผ่าน api server แต่สำหรับบทความนี้ จะพาทำการ caching ฝั่ง server ครับ ด้วย Node.js + Redis กัน
Step 1 : Redis คืออะไร แบบ Overview
Redis คือ Database ตัวนึงครับ แต่เป็น Database ที่เก็บข้อมูลใน memory ก็คือเก็บข้อมูลใน RAM นั่นเอง โดยข้อมูลที่เก็บจะเป็น Key Value อาจจะมองเป็น NoSQL ก็ได้เช่นกัน
ซึ่งการเก็บข้อมูลแบบ In memory ก็เหมือน RAM เลยคือข้อมูลจะบันทึกแค่ตอนที่เครื่องทำงาน ถ้า restart หรือปิด เปิดใหม่ ข้อมูลก็จะหายครับ (ซุึ่งจริงๆ เราสามารถ config ให้ข้อมูลไม่หาย หลังจาก reboot/restart ได้ครับ)
อ้าว แล้วมันดียังไง? เก็บแล้วข้อมูลหาย
ซึ่ง Redis มันไม่ได้ออกแบบมา ให้เก็บข้อมูลในระยะยาวอยู่แล้วครับ และ in memory ข้อดีคือความเร็ว ตัว Redis มันมาตอบโจทย์การเก็บข้อมูลที่เราใช้บ่อยๆ เอามาไว้ทำ caching หรือเก็บพวก temp file ใช้งานไม่นาน เป็นต้น
โดย Redis อย่างที่บอก เก็บข้อมูลแบบ Key Value ก็แค่ระบุว่า key ชื่อนี้ จะเก็บข้อมูลอะไรบ้าง? ซึ่งตัวข้อมูลที่เก็บ ก็เป็น String, Set, Hash เป็นต้นครับ (หลักๆ ก็มองเป็น String ก็ได้ครับ)
สำหรับใครอยากลองเล่น Redis สามารถไปลองเล่นได้ที่นี่ครับ https://try.redis.io/
Step 2 : ติดตั้ง Redis
สำหรับบทความนี้ผมติดตั้งบน Mac OS ด้วย Homebrew นะครับ
และสั่ง start redis ด้วย
หรือจะ Install ด้วย Binary ก็ได้เช่นกันครับ (สำหรับ Linux)
สำหรับ Windows ลองดูบล็อกของ redis ครับ https://redislabs.com/blog/redis-on-windows-8-1-and-previous-versions/
เมื่อติดตั้ง และ start redis เรียบร้อยแล้ว ก็ลอง เข้าผ่าน CLI ครับ
ลองพิมพ์
การเก็บค่า ใช้คำสั่ง SET <NAME> <VALUE>
เช่น
ดึงข้อมูลจาก key ที่เราบันทึกไว้ด้วยคำสั่ง GET <NAME>
เช่น
เราสามารถ set expire ให้ key
รวมถึงสามารถดูเวลา expire ของ key ได้ เช่น TTL <KEY>
โดย -1
คือ ไม่มี expire, -2
expire แล้ว และค่าอื่นๆ คือเวลาที่ยังเหลืออยู่ (วินาที)
คร่าวๆ ก็แบบนี้ก่อนละกันครับ จริงๆมีการเก็บแบบ HSET
, HGET
หรืออื่นๆ อีก สามารถอ่านเพิ่มได้ครับ
Step 3 : เริ่มต้น Project
ตัวโปรเจ็คที่จะสร้าง จะเป็น Node.js และจะเรียก request เพื่อไปดึง Github API อีกทีนะครับ
จากนั้นผมทำการสร้างไฟล์ app.js
ขึ้นมา มี endpoint แค่ root ครับ
ต่อมาก็ให้มันไปดึง github username จาก query string ครับ เป็นแบบนี้
ลองทดสอบ start server ขึ้นมา จะได้หน้าเว็บ http://localhost:9000?username=devahoy เป็น response จาก github api ครับ (ลองเปลี่ยน username เป็นชื่ออื่นๆดู)
ลองทดสอบด้วย Postman ดู (จริงๆ ก็สามารถทำผ่านหน้าเว็บได้) แต่ว่าเราจะดู response time ครับ บน Postman มันเห็นง่ายชัดเจนดีครับ
จะเห็นว่าทุกๆ ครั้งที่เรา request ไม่ว่าจะ username ซ้ำ ตัว api มันก็ไปดึงข้อมูล github api ตลอด ทั้งที่ข้อมูลเดิม ไม่จำเป็นต้องไปดึงใหม่ก็ได้
ซึ่งจริงๆแล้ว redis ก็สามารถเอาไปใช้กรณี user หรือข้อมูลซ้ำๆ แบบนี้ก็ได้เช่นกันครับ อาจจะไม่ใช้ดึง api อีก service อาจจะเป็นการ query database ที่อาจจะใช้เวลานานก็ได้ เป็นต้น
Step 5 : Caching ด้วย Redis
เอาละ ลองใช้ Redis cache แทนดีกว่า เราใช้ node-redis ครับ ติดตั้งผ่าน npm ได้เลย
จากนั้นทำการเพิ่ม redis ดังนี้
จำได้มั้ยครับ เราสามารถ get
และ set
ค่า ตัว node-redis มันก็ wrap มาเป็น function ให้เราแล้วครับ
ทีนี้มาที่โค๊ด ผมแก้ไขนิดหน่อย เป็นแบบนี้ เมื่อ request เข้ามา ที่ endpoint GET /
- เช็คก่อนว่า มี key เก็บไว้ใน redis มั้ย?
- ถ้ามี ก็ return ค่านั้นไปเลย (เร็ว ไม่ต้อง query หรือ fetch ค่า)
- ถ้าไม่มี ก็ดึงข้อมูล ปกติครับ เมื่อได้ response ก็ เก็บค่าลง redis ด้วย key ที่กำหนด
- เรียบร้อย
จากโค๊ดด้านบน จะเห็นว่า
redisClient.get()
เป็นแบบ callback function นะครับ- key ที่ผมจะเก็บคือ username ของ github เลย (จริงๆเราเก็บเป็น
user:<NAME>
ก็ได้ครับ จะได้แบ่งแยก และดูเป็นหมวดหมู่) - และก็สังเกตว่าผมเก็บค่า json เป็นแบบ string เลยต้องใช้
JSON.stringify()
และตอนแปลงจาก string เป็น json ก็ใช้JSON.parse()
ครับ
ทีนี้ลอง stop/start server ใหม่ และลองเปิด Postman เพื่อดูข้อมูลอีกครั้ง
จะเห็นว่าเวลาเรียกข้อมูลที่เคยดึงไปแล้ว และถูก cache นั้น response time ไวมากครับ
Step 6 : เรียก node-redis แบบ Promise
จากโค๊ดด้านบน เราเห็นการเรียกแบบ callback function ทีนี้ redis อยากใช้แบบ Promise ทำได้มั้ย (Node v8 ขึ้นไป)
ซึ่งจริงๆสามารถใช้ได้ครับ เพียงแค่ใช้ module utils
ครับ
สุดท้ายไฟล์ app.js
แบบ Promise ด้วย promisify
จะได้แบบนี้ครับ
เทียบกับแบบ callback
สรุป
ก็จบไปแล้วสำหรับ Example สำหรับการทำ Caching ด้วย Nodejs + Redis ซึ่งจะเห็นว่าไม่ยากเลยครับ และแน่นอนเราควรจะทำการ caching ให้เป็นพื้นฐานไปเลยครับ แต่ไม่ใช่จะ cache ทุกอย่างนะครับ เราต้องดูเป็นกรณีๆไปครับ และนอกจาก Redis จริงๆ ก็มีตระกูล cache อื่นๆ อีกเยอะครับ ไม่ว่าจะเป็น Memcached หรือแม้กระทั่ง MongoDB ก็ตาม หวังว่าบทความนี้จะมีประโยชน์กับคนที่สนใจ redis กันนะครับ
Happy Coding ❤️
สำหรับ Reference อ่านเพิ่มเติม
- Authors
-
Chai Phonbopit
เป็น Web Dev ในบริษัทแห่งหนึ่ง ทำงานมา 10 ปีกว่าๆ ด้วยภาษาและเทคโนโลยี เช่น JavaScript, Node.js, React, Vue และปัจจุบันกำลังสนใจในเรื่องของ Blockchain และ Crypto กำลังหัดเรียนภาษา Rust