I. Định nghĩa Redis Pub/Sub
1. Cơ chế hoạt động
Redis Pub/Sub là một kiểu messaging pattern lâu đời nhất được Redis hỗ trợ và sử dụng loại dữ liệu gọi là "channel". Redis Pub/Sub có cơ chế giống với pub/sub messaging, là 1 trong 2 message broker phổ biến.
Publish/subscribe messaging, hay pub/sub messaging, là một hình thức giao tiếp service-to-service bất đồng bộ được sử dụng trong các kiến trúc phân tán. Pub/sub messaging có cơ chế hoạt động như sau:
- Pub - Publish: Publisher sẽ đẩy message(data) vào một hoặc nhiều topic(channel).
- Sub - Subscribe: Subscriber sẽ đăng ký nhận message(data) từ một hoặc nhiều topic(channel)
Một channel có thể có 0 hoặc nhiều subscribers, và message sẽ được gửi tới tất cả các subscribers đã được kết nối. Redis Pub/Sub hỗ trợ linh hoạt nhiều cấu trúc liên kết bao gồm fan-in(multiple publishers, single subscriber), fan-out(single publisher, multiple subscribers), and 1-1(one, one).
Cơ chế này giống như trong việc bạn sử dụng Youtube. Khi bạn subcribe một channel, mỗi lần channel được đăng tải(publish) một nội dung mới thì bạn sẽ nhận được thông báo. Khi những người khác cũng subscribe channel đó, thì cả bạn và những người khác sẽ nhận được thông báo. Và tất nhiên là bạn có thể đăng ký nhiều channel. Redis Pub/Sub được coi là sự kết hợp “lỏng lẻo” vì các Publishers và Subscribers không biết gì về nhau.
2. Những điểm cần lưu ý
- Khi message được gửi đi tới tất các các subscriber thì nó sẽ bị xóa khỏi channel
- Nếu một subscriber hủy đăng ký và đăng ký lại vào channel thì:
- Nó sẽ không nhận được bất kỳ tin nhắn nào mà nó đã bỏ lỡ khi hủy đăng ký.
- Nó sẽ không biết đã đã bị lỡ những tin nhắn nào.
- Nếu hiện tại không có subscriber nào subscribe vào kênh, tin nhắn sẽ bị loại bỏ và không được gửi cho bất kỳ subscriber nào.
- Vì message phải đến được tất cả các subscriber hiện hành trước khi bị xóa. Điều này sẽ tốn thời gian nhiều hơn khi có nhiều subscriber.
II. Ứng dụng Redis Pub/Sub trong việc mở rộng Node.js Socket Server
1. Vấn đề
Một trong những chủ đề thú vị khi phát triển back-end là mở rộng và phân tán server. Giả sử chúng ta muốn tăng khả năng đáp ứng của ứng dụng nên đã mở rộng server, triển khai multiple instances của một ứng dụng Node và sử dụng một Nginx server đóng vai trò proxy cho tất cả các request/connections đến một Node server.
Như bạn thấy, chúng ta có một Nginx server nhận tất cả các requests được gửi bởi client và chuyển đến các Node server khác nhau. Nginx mặc định sử dụng thuật toán round robin, đó là lý do tại sao r1 đến server:8000, r2 đến server:8001, r3 đến server:8002,..
Hãy tưởng tượng một tình huống mà bạn được kết nối với Node: 8000, một người bạn của bạn được kết nối với Node: 8001 và bạn muốn gửi cho người ấy một tin nhắn. Bạn gửi nó bằng socket, server nhận được một sự kiện và muốn gửi tin nhắn của bạn cho người dùng khác (bạn của bạn). Tôi nghĩ rằng bạn đã đoán được vấn đề chúng ta có thể gặp phải: server muốn gửi dữ liệu cho người dùng không được kết nối với nó nhưng được kết nối với một server khác trong hệ thống.
2. Hướng giải quyết
Để giải quyết vấn đề này chỉ có một giải pháp, và có thể thực hiện bằng nhiều cách. Đó là, tạo một lớp giao tiếp nội bộ cho các server.
Điều này có nghĩa là mỗi server có thể gửi request đến những server khác.
Bằng cách này, Node:8000 gửi request đến Node:8001 và Node:8002, và chúng sẽ check xem có user2 có được kết nối đến chúng không, nếu có thì server đó sẽ gửi data được cung cấp bởi Node:8000
Một trong những công nghệ phổ biến nhất cung cấp tầng giao tiếp mà chúng ta có thể dùng đó là Redis, và cụ thể là Redis Pub/Sub.
Sử dụng Subscriber ở Redis client, bạn có thể subscribe đến một channel và lắng nghe các messages được gửi tới channel. Với Publisher, bạn có thể gửi message đến một channel cụ thể, nó sẽ được nhận bởi những user đã đăng ký.
Bằng cách này, chúng ta có thể có subscribers và publishers trong một ứng dụng để có thể nhận và gửi data cho nhau.
Sử dụng Redis Pub/Sub, chúng ta thiết lập liên lạc giữa các server Node.js. Mỗi khi bất kỳ server nào muốn gửi dữ liệu cho máy khách không được kết nối với nó, server sẽ publish dữ liệu. Sau đó, mọi server đều nhận được và kiểm tra xem người dùng có được kết nối với nó không. Cuối cùng, server đó gửi dữ liệu được cung cấp cho máy khách. Và đây là mô hình hoàn chỉnh.
III. Tổng kết
Qua bài viết này, ta đã hiểu được:
- Redis Pub/Sub là gì
- Cơ chế hoạt động của Pub/Sub messaging
- Những điểm cần lưu ý đối với Redis Pub/Sub
- Ứng dụng Redis Pub/Sub trong việc mở rộng ứng dụng Node.js Socket Server
IV. Tài liệu tham khảo
- https://blog.jscrambler.com/scaling-node-js-socket-server-with-nginx-and-redis
- https://laptrinh.vn/books/redis/page/redis-publish-subscribe
- https://thenewstack.io/redis-pub-sub-vs-apache-kafka/#:~:text=Redis%20Pub%2FSub%20is%20the,t%20know%20about%20each%20other.
- https://helpex.vn/question/su-dung-redis-lam-pubsub-tren-socket.io-60be6570d24b80926dc00b6d