怎么使用redis缓存websocket实例?

如果直接存在内存的话,感觉有点不靠谱,如果连接数大的时候,会引发内存泄漏?那该怎么缓存ws实例呢?

import {WebSocketServer} from 'ws';

const wss = new WebSocketServer({
    port: 8080,
});

wss.on('connection', function (ws) {
    // 为了防止内存泄漏,怎么把ws实例用redis缓存起来?然后,需要使用的时候,从redis获取并send
    // 使用redis set的话,只能存储字符串,ws无法JSON.stringify?报错了
})

这方面的优化怎么做呢?求各位大佬指点指点

阅读 1.5k
2 个回答

将WebSocket实例存储在Redis中是一个不错的解决方案,以防止内存泄漏并支持水平扩展。但是,WebSocket实例不能直接存储在Redis中,因为Redis只支持存储字符串、数字和二进制数据,而WebSocket实例是一个复杂的JavaScript对象。为了在Redis中缓存WebSocket实例,你可以考虑以下方法:

使用WebSocket连接标识符:将WebSocket连接的唯一标识符(例如连接ID或用户名)作为键,将WebSocket实例的序列化版本作为值存储在Redis中。你可以使用JSON.stringify将WebSocket实例序列化为字符串,然后在需要使用它时,从Redis中获取并反序列化为WebSocket实例。

示例代码:

javascript
Copy code
const redis = require('redis');
const client = redis.createClient();

wss.on('connection', function (ws) {
    // 假设每个WebSocket连接有一个唯一的连接ID
    const connectionId = generateConnectionId();
    
    // 存储WebSocket实例到Redis
    client.set(connectionId, JSON.stringify(ws));

    ws.on('close', function () {
        // 在连接关闭时,从Redis中删除WebSocket实例
        client.del(connectionId);
    });
});

// 在需要使用WebSocket实例时,从Redis中获取并反序列化
function getWebSocketInstance(connectionId) {
    return new Promise((resolve, reject) => {
        client.get(connectionId, (err, serializedWs) => {
            if (err) {
                reject(err);
            } else if (!serializedWs) {
                resolve(null); // 没有找到WebSocket实例
            } else {
                const ws = JSON.parse(serializedWs);
                resolve(ws);
            }
        });
    });
}

请注意,这里使用了一个唯一的连接ID作为键来存储WebSocket实例。你需要确保在连接关闭时从Redis中删除WebSocket实例,以避免不再使用的实例占用Redis空间。

使用WebSocket连接池:你可以创建一个WebSocket连接池,将WebSocket实例存储在池中,并使用连接标识符来检索和重用WebSocket实例。这种方法可以更精细地控制WebSocket实例的生命周期,以减少内存泄漏的风险。
你可以使用现有的连接池库来管理WebSocket实例。

不管你选择哪种方法,都需要确保在WebSocket连接关闭时从缓存中删除实例,以防止资源泄漏。此外,你还需要考虑定期清理不再使用的WebSocket实例,以释放Redis中的资源。

这些处理来优化:给每个WebSocket实例分配一个唯一ID,存一定要的数据在Redis里,然后在内存里维护一个WebSocket实例的映射,发送消息时从Redis获取数据。这只是一个大概框架,可以帮你更好管理WebSocket连接和相关数据,而不是直接缓存WebSocket实例,这个方法可以减少内存泄露的风险,就如楼上所说,你可以用Nginx或这其他负载均衡器来分散连接到多个服务器。还可以加更多的服务器来分担负载

import { WebSocketServer } from 'ws';
import redis from 'redis';

const wss = new WebSocketServer({ port: 8080 });
const client = redis.createClient();
const wsMap = new Map();

wss.on('connection', function (ws) {
    const uniqueID = generateUniqueID(); // 生成一个唯一ID的函数
    wsMap.set(uniqueID, ws);

    ws.on('message', function (message) {
        // 处理接收到的消息
        // ...
        
        // 把需要的数据存储在Redis里
        client.set(uniqueID, JSON.stringify({ /* your data here */ }));
    });

    ws.on('close', function () {
        // 从映射和Redis了删除WebSocket实例
        wsMap.delete(uniqueID);
        client.del(uniqueID);
    });
});

function sendMessage(uniqueID, message) {
    // 从Redis里获取数据
    client.get(uniqueID, function (err, data) {
        if (err) {
            console.error(err);
            return;
        }

        // 从映射里获取WebSocket实例然后发送消息
        const ws = wsMap.get(uniqueID);
        if (ws) {
            ws.send(message);
        }
    });
}

function generateUniqueID() {
    // 实现函数来生成一个唯一ID
    // ...
}

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题