-->
ads here

Caching technique - Redis with NodeJS Example

advertise here
Trong bài viết lần này mình sẽ viết về kỹ thuật caching nói chung và Redis nói riêng, sau đó sẽ hiện thực một ví dụ về sử dụng Redis với NodeJS.
Nội dung của bài viết gồm 3 phần

  1. Giới thiệu: Caching là gì? Redis là gì?
  2. Cách cài đặt và sử dụng Redis trong quá trình lập trình
  3. Demo
Chúng ta bắt đầu thôi!

1.Giới thiệu: Caching là gì? Redis là gì?

Caching technique

Đầu tiên chúng ta sẽ tìm hiểu xem Caching technique là gì?
Caching là quá trình lưu trữ dữ liệu ở cache - một loại bộ nhớ tạm. Cache là một loại data store tạm, giúp truy cập dữ liệu rất nhanh chóng và dễ dàng, ngược lại với permanent data store (nằm ở service khác) nhưng truy cập lâu hơn và tốn nhiều tài nguyên hơn.

Cách hoạt động của cache

Theo cách hoạt động thông thường: Mỗi lần client request đến server, server sẽ thực hiện câu truy vấn đến DB và chờ DB trả về kết quả, sau đó xử lý kết quả truy vấn đó và trả về thông tin cho client.
Giả sử mỗi request tốn 10s để thực hiện, và client thực hiện liên tục 30 request, khi đó sẽ mất tổng thời gian là 10*30 = 300 s = 5 min
Thông thường
Khi sử dụng cache: Với request đầu tiên, cũng mất 10s để thực hiện, nhưng đồng thời lúc này server lưu kết quả truy vấn ở cache nhằm phục vụ cho các request sau. Ở các request tiếp theo, thì server không cần query DB để lấy dữ liệu mà chỉ cần load từ cache ra và trả về cho server; quá trình này tất nhiên có thời gian thực hiện thấp hơn 10s, giả sử cho rằng 7s. Khi đó ta có tổng thời gian cho 30 request là: 10*1 + 7*29 = 213s = 3.55min
With cache
Như ta thấy, với việc sử dụng cache thì ta tiết kiệm được tới 87s (gần 1.5min). Hãy tưởng tưởng những con số này được scale up lên thì thời gian và chi phí tiết kiệm được là hiệu quả cỡ nào

Sau khi tìm hiểu cách hoạt động của kĩ thuật caching, tiếp theo chúng ta sẽ tìm hiểu xem Redis là gì?

Redis

Theo định nghĩa từ trang chủ
Redis is an open source (BSD licensed), in-memory data structure store, used as a database, cache and message broker.
Redis là một cấu trúc lưu trữ dữ liệu trên bộ nhớ, nguồn mở, được sử dụng như DB, bộ nhớ đệm hay message broker. Đồng thời, Redis hỗ trợ nhiều kiểu dữ liệu như: strings, hashes, lists, sets và sorted sets
Redis lưu trữ dữ liệu trên RAM dưới dạng key-value, rất dễ dàng và nhanh chóng truy xuất dữ liệu vì nó không có những ràng buộc phức tạp hay những thao tác  khác làm tăng thời gian truy vấn dữ liệu.
Ngoài ra, Redis còn có cơ chế sao lưu dữ liệu lên ổ cứng nhằm khôi phục hệ thống khi xảy ra sự cố
Image result for redis là gì

2. Cách cài đặt và sử dụng Redis

Để cài đặt Redis trên máy tính của mình, bạn có thể tải Redis installer tại đây. Sau đó làm theo hướng dẫn để cài đặt. Nếu bạn dùng MacOS bạn có thể cài Redis qua homebrew bằng cách như sau:
brew install redis
 Sau khi cài đặt xong, ta tiến hành mở server redis và test thử xem cài đặt thành công hay chưa bằng lệnh 
redis-server
Khi thấy kết quả như dưới đ ây là bạn đã cài đặt thành công

22353:C 18 Apr 2019 20:00:22.089 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo 22353:C 18 Apr 2019 20:00:22.089 # Redis version=5.0.4, bits=64, commit=00000000, modified=0, pid=22353, just started 22353:C 18 Apr 2019 20:00:22.089 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf 22353:M 18 Apr 2019 20:00:22.091 * Increased maximum number of open files to 10032 (it was originally set to 8096). _._ _.-``__ ''-._ _.-`` `. `_. ''-._ Redis 5.0.4 (00000000/0) 64 bit .-`` .-```. ```\/ _.,_ ''-._ ( ' , .-` | `, ) Running in standalone mode |`-._`-...-` __...-.``-._|'` _.-'| Port: 6379 | `-._ `._ / _.-' | PID: 22353 `-._ `-._ `-./ _.-' _.-' |`-._`-._ `-.__.-' _.-'_.-'| | `-._`-._ _.-'_.-' | http://redis.io `-._ `-._`-.__.-'_.-' _.-' |`-._`-._ `-.__.-' _.-'_.-'| | `-._`-._ _.-'_.-' | `-._ `-._`-.__.-'_.-' _.-' `-._ `-.__.-' _.-' `-._ _.-' `-.__.-' 22353:M 18 Apr 2019 20:00:22.092 # Server initialized 22353:M 18 Apr 2019 20:00:22.092 * Ready to accept connections

Như vậy là chúng ta đã cài đặt thành công Redis trên máy và bây giờ có thể tiến hành demo thực tế xem Redis hoạt động ra sao.

3. Demo

Trong ví dụ thực tế này mình sẽ viết 1 API fetch data về với số lượng lớn và sử dụng cache để xem nó tiết kiệm thời gian của chúng ta như thế nào. API của chúng ta rất đơn giản, chỉ có 1 route duy nhất là /photos để lấy danh sách rầt nhiều ảnh về và trả về dạng json.

Ảnh sẽ được fetch về từ đây: https://jsonplaceholder.typicode.com/photos

Chúng ta bắt đầu!

Khởi tạo

Đầu tiên tạo 1 thư mục project với tên ví dụ như: redis-nodejs-demo
Trong thư mục này, mở terminal và gõ lệnh sau để khởi tạo project 
npm init --force
Tiếp theo tạo 1 file index.js, và ta sẽ thực hiện code trong file này

Cài đặt các package cần thiết

Để thực hiện demo này ta cần một số các npm package như sau:
  • express: để tạo HTTP server cho API và xử lý routing
  • redis: Nodejs client của redis
  • axios: Giúp gọi API qua các HTTP request 
  • response-time: Ghi lại thời gian thực hiện request vào header (dùng để so sánh thời gian xử lý giữa có cache và không có cache)
Chúng ta tiến hành cài đặt các package này vào project như sau
npm install --save axios express redis response-time
Ok, sau khi chuẩn bị xong chúng ta tiến hành code

Coding

Trong file index.js ta sử thêm code như sau

 const express = require('express');  
 const responseTime = require('response-time')  
 const axios = require('axios');  
 const redis = require('redis');  
 const app = express();  
 const client = redis.createClient();  
 // Print redis errors to the console  
 client.on('error', (err) => {  
     console.log("Error " + err);  
 });  
 // use response-time as a middlewar  
 app.use(responseTime());  
 const PHOTO_REDIS_KEY = 'cache:photos';  
 const URL = 'https://jsonplaceholder.typicode.com/photos';  
 app.get('/photos', async (req, res) => {  
     return client.get(PHOTO_REDIS_KEY, async (error, photos) => {  
         if (error) {  
             res.json(err)  
         }  
         if (photos) {  
             res.json({  
                 source: 'cache',  
                 data: JSON.parse(photos),  
             });  
         } else {  
             const { data } = await axios.get(URL);  
             client.setex(PHOTO_REDIS_KEY, 3600, JSON.stringify(data))  
             res.json({  
                 source: 'api',  
                 data  
             })  
         }  
     })  
 });  
 app.listen(3000, () => {  
     console.log('Server listening on port: ', 3000)  
 });  

Ta thấy, trước khi trả về kết quả, thay vì ngay lập tức gọi API, ta sẽ lấy dữ liệu từ cache trước thông qua client.get(KEY, callback), trong lúc này nếu trong cache có dữ liệu rồi thì ta chỉ việc lấy lên và trả về kết quả. Nếu trong cache không có dữ liệu (lần đầu fetch dữ liệu hoặc khi cache đã expire) thì ta mới gọi đến API để lấy dữ liệu thông qua axios.
Lúc này khi dữ liệu được lấy về từ API, ta tiến hành lưu nó vào cache bằng client.setex(KEY, ExpireTime, data) để lần tiếp theo gọi thì lấy dữ liệu từ cache.

Test kết quả:

Sau khi code xong, ta chạy lệnh sau để chạy server

node index.js
Tiếp theo chúng ta dùng Postman để  xem kết quả. Trong Postman thực hiện một GET request đến http://localhost:3000/photos và xem kết quả
Without cache
Như các bạn có thể thấy, trong lần đầu tiên, chúng ta mất tới 2567ms để fetch dữ liệu và nguồn dữ liệu được lấy bằng viẹc gọi API như trên hình.
Tiếp theo, ta thực hiện lại request này một lần nữa và xem điều kì diệu 
With cache
Ở lần thứ hai này chúng ta có thể thấy kết qủa cực kì ấn tượng, chỉ mất 52ms để trả về dữ liệu từ cache (nhanh gấp ~50 lần so với fetch API)

Kết

Vậy là chúng ta đã tìm hiểu về Redis và  thực hiện xong ví dụ về Cache để thấy được sự hiệu quả mà nó đem lại. Hi vọng bài viết này có thể giúp các bạn sử dụng cache tốt hơn trong quá trình làm việc của mình. Nếu thấy bài viết hay và có ích hãy chia s ẻ cho mọi người cùng biết, nếu các bạn có  bất kì ý kiến đóng góp nào thì đừng ngần ngại để lại bình luận ở cuối bài viết nhé. Thanks

Reference


Advertisement
COMMENTS ()