建立一个Nodejs websocket+redis推送服务器,遇到阻塞问题

建立一个Nodejs websocket+redis推送服务器,遇到阻塞问题

sever端,使用nodejs+redis建立一个推送服务器,运作机制是 nodejs不停地读取redis中的数据,然后使用websocket发送给client。 当client通过websocket连接服务器,然后服务器就开始向client不停的发送数据。 server端,我尝试使用while循环不停地访问redis数据库,发现代码在while这边卡住了。 求思路~~~~~~简易代码就好

3 回复

当然可以。在Node.js中,直接使用while循环来不停地读取Redis数据会导致阻塞问题,因为这会占用整个事件循环,使得其他异步操作无法执行。为了实现非阻塞的WebSocket + Redis推送服务器,我们可以利用事件驱动的方式,结合setIntervalsetTimeout来定期检查Redis中的数据,并通过WebSocket将这些数据推送给客户端。

以下是一个简单的示例代码,展示了如何实现这一功能:

1. 安装必要的依赖

首先,你需要安装ws(WebSocket库)和redis(Redis客户端)库:

npm install ws redis

2. 编写服务器代码

接下来是服务器端的代码:

const WebSocket = require('ws');
const redis = require('redis');

// 创建WebSocket服务器
const wss = new WebSocket.Server({ port: 8080 });

// 创建Redis客户端
const client = redis.createClient();

// 处理连接
wss.on('connection', function connection(ws) {
    console.log('A client connected.');

    // 定期从Redis获取数据并推送给客户端
    setInterval(() => {
        client.get('message', (err, reply) => {
            if (reply) {
                ws.send(reply);
            }
        });
    }, 1000); // 每秒检查一次Redis
});

console.log('WebSocket server is running on ws://localhost:8080');

3. 客户端代码

客户端代码非常简单,这里仅作示例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>WebSocket Client</title>
</head>
<body>
    <script>
        const ws = new WebSocket('ws://localhost:8080');

        ws.onmessage = function(event) {
            console.log('Message from server:', event.data);
        };

        ws.onopen = function() {
            console.log('Connected to the server.');
        };

        ws.onclose = function() {
            console.log('Disconnected from the server.');
        };
    </script>
</body>
</html>

解释

  • WebSocket服务器:我们创建了一个WebSocket服务器,监听8080端口。
  • Redis客户端:我们创建了一个Redis客户端实例来与Redis进行通信。
  • 定时任务:我们使用setInterval函数每秒检查一次Redis中的数据。如果Redis中有数据,我们将这些数据通过WebSocket发送给客户端。
  • 客户端:客户端连接到WebSocket服务器,并接收来自服务器的数据。

这种方法避免了阻塞问题,因为setInterval和Redis的回调都是异步的,不会阻塞事件循环。


   我做过类似的事情,你while里面不停地去访问redis,由于是异步的,会不断去和redis建立链接,这样会占满cpu,占满网络资源,甚至占满内存。
   我之前在redis里面存储的是list结构的数据,思路是这样的:每次要读redis里面的数据时先用llen查一下有多少数据,如果有超过200条(自己设置阀值),就读200条出来并且在处理完这二百条之后再立即去redis里面继续读数据,如果少于200条时就全部读出来并在处理完之后500ms(自己设置)再去读redis里面的数据。或者傻瓜式的:每500毫秒去拿一次数据。(瞬间压力就下来了)
  其实你应该是想弄一个队列服务器的,建议还是用专门的库或者用rabbitMq这样的大杀器。如果自己写,容错做的不好的话很容易出bug.

在Node.js中使用Websocket和Redis来构建一个推送服务器时,如果使用while循环不断地查询Redis,会导致程序阻塞,因为while循环会占用主线程,使得其他操作无法执行。

为了解决这个问题,可以采用事件驱动的方式。我们可以利用setInterval来定期检查Redis中的数据变化,或者使用redis模块提供的订阅功能来监听数据变化。下面是一个简单的实现方式:

  1. 使用ws库来创建WebSocket服务器。
  2. 使用ioredis库来连接到Redis并监听变化。

示例代码

const WebSocket = require('ws');
const Redis = require('ioredis');

// 创建WebSocket服务器
const wss = new WebSocket.Server({ port: 8080 });

// 创建Redis客户端
const redis = new Redis();

// 存储已连接的WebSocket客户端
const clients = new Set();

// 监听新的WebSocket连接
wss.on('connection', (ws) => {
    console.log('Client connected');
    clients.add(ws);

    ws.on('close', () => {
        console.log('Client disconnected');
        clients.delete(ws);
    });
});

// 使用Redis订阅频道
redis.subscribe('news', (err, count) => {
    if (err) throw err;
});

// 监听消息事件
redis.on('message', (channel, message) => {
    console.log(`Received message on channel ${channel}: ${message}`);
    
    // 将消息广播给所有客户端
    clients.forEach((client) => {
        client.send(message);
    });
});

解释

  • ws 是一个用于创建WebSocket服务器的库。
  • ioredis 是一个高性能的Redis客户端。
  • clients 集合用于存储所有连接的WebSocket客户端。
  • 当有新的WebSocket连接时,将其添加到clients集合,并监听关闭事件以删除断开连接的客户端。
  • 使用Redis的subscribe方法订阅特定频道(例如'news'),并监听message事件来处理新消息。
  • 当接收到消息时,将消息广播给所有已连接的客户端。

这种方法避免了使用while循环带来的阻塞问题,使得服务器能够高效地处理WebSocket连接和Redis消息。

回到顶部