WebSocket和Redis Pub/Sub

使用Redis的Pub/Sub功能可以在多个服务器之间同步Websocket通信信息。
当为了扩展性而启动多个Websocket服务器时,如果没有一种机制来同步服务器间的通信信息,例如在聊天应用中,连接到服务器A的客户端将无法与连接到服务器B的客户端正常交换消息。
Redis的Pub/Sub功能可以解决这个问题。

スクリーンショット 2020-12-28 20.44.39.png

Redis Pub/Sub是一种发布/订阅模式的消息传递系统。

Pus/Sub所涉及的主要概念是:

用語説明Publish発行することSubscribe購読することChannel購読するチャンネル

在广播中,
传送节目是”发布”,
收听节目是”订阅”,
节目本身是”频道”。
广播声音只会传送给那些收听节目的人。

我将使用Redis-cli来尝试pubsub。

redis-server  //Redisを起動
redis-cli     //CLIを起動

打开两个终端标签,其中一个终端中

SUBSCRIBE MorningShow

在另一个终端中

PUBLISH MorningShow "Good Morning!"
スクリーンショット_2020-12-27_17_42_18.png

使用Node.js运行示例代码

这是一个使用Node.js和Redis PubSub的简单示例,采用了websocket。源代码在这里。

ezgif.com-crop.gif

首先是客户端。当连接按钮被按下时,将访问服务器。一旦从服务器接收到消息,将在屏幕上显示。

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
ezgif.com-crop.gif

实际的应用会更加复杂,但我已经写了概述。
更实用的应用架构和实施方法,我认为可以参考AWS的博客,它们非常易懂。

请参考

    Amazon ElastiCache for Redis を使ったChatアプリの開発
广告
将在 10 秒后关闭
bannerAds