WebSocket和Redis Pub/Sub
使用Redis的Pub/Sub功能可以在多个服务器之间同步Websocket通信信息。
当为了扩展性而启动多个Websocket服务器时,如果没有一种机制来同步服务器间的通信信息,例如在聊天应用中,连接到服务器A的客户端将无法与连接到服务器B的客户端正常交换消息。
Redis的Pub/Sub功能可以解决这个问题。
Redis Pub/Sub是一种发布/订阅模式的消息传递系统。
Pus/Sub所涉及的主要概念是:
在广播中,
传送节目是”发布”,
收听节目是”订阅”,
节目本身是”频道”。
广播声音只会传送给那些收听节目的人。
我将使用Redis-cli来尝试pubsub。
redis-server //Redisを起動
redis-cli //CLIを起動
打开两个终端标签,其中一个终端中
SUBSCRIBE MorningShow
在另一个终端中
PUBLISH MorningShow "Good Morning!"
使用Node.js运行示例代码
这是一个使用Node.js和Redis PubSub的简单示例,采用了websocket。源代码在这里。
首先是客户端。当连接按钮被按下时,将访问服务器。一旦从服务器接收到消息,将在屏幕上显示。
wsButton.onclick = function () {
wsSendButton.disabled = false;
ws = new WebSocket(`ws://${location.host}`);
ws.onopen = function () {
showMessage('WebSocket connection established');
};
ws.onmessage = function (message) {
let data = JSON.parse(message.data)
showMessage(JSON.stringify(data.message));
};
-- 省略 --
};
然后是服务器端。
我们将创建WebSocket监听器并连接到Redis。这次我们将连接到使用docker-compose创建的Redis容器,所以将Redis主机设置为容器名称”redis”(参考)。我们创建了两个连接到Redis的连接,一个用于发布消息,一个用于订阅。
const express = require('express');
const http = require('http');
const WebSocket = require('ws');
const Redis = require('ioredis');
const app = express();
app.use(express.static('public'));
const server = http.createServer(app);
const wss = new WebSocket.Server({ noServer: true });
const redis = new Redis('redis'); //redis container
const client = new Redis('redis');
以下是pubsub处理部分的内容。
首先,预先在一个Redis连接中订阅名为’newMessage’的频道。
当从客户端接收到消息时,使用另一个连接将接收到的消息发布到’newMessage’频道。
当有新消息到达’newMessage’频道时,将向所有客户端传递消息。
function subscribeMessage(channel) {
client.subscribe(channel);
client.on('message', function(channel, message) {
broadcast(JSON.parse(message))
});
}
subscribeMessage('newMessage')
// broadcast message to all clients
function broadcast(message){
wss.clients.forEach(function(client){
client.send(JSON.stringify({
message: message
}))
})
}
wss.on('connection', function (ws, request) {
ws.on('message', function (message) {
redis.publish('newMessage', JSON.stringify(message))
});
-- 省略 --
});
只使用一台服务器来运行pubsub没有意义。
因此,接下来我们将部署两个Node.js的docker容器,当消息到达一个容器时,我们将尝试通过pubsub将其同步到另一个容器。
在Node.js容器之间进行同步通信
以下是用于创建Node.js容器的Dockerfile,我直接使用了官方提供的内容。
FROM node:12
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
COPY . .
CMD [ "node", "server.js" ]
使用Dockerfile创建两个Node.js容器和一个Redis容器,通过docker-compose工具进行配置。
其中一个Node容器可以通过localhost:3000进行访问,另一个Node容器可以通过localhost:3030进行访问。
version: '3'
services:
server1:
build: .
ports:
- 3000:3000
server2:
build: .
ports:
- 3030:3000
redis:
image: redis:6
ports:
- 6379:6379
最后启动容器。
docker-compose up --build
实际的应用会更加复杂,但我已经写了概述。
更实用的应用架构和实施方法,我认为可以参考AWS的博客,它们非常易懂。
请参考
- Amazon ElastiCache for Redis を使ったChatアプリの開発