Nodejs socket.io mongo---cluster 求助

Nodejs socket.io mongo—cluster 求助

使用nodejs + socket.io +mongo 做一个即时聊天系统(实际项目)

1:如何共享 scoket 开启多进程实现负载,如何通过 cluster 模块实现(这里不讨论 cluster 负载不均衡) 2: 官方提供socket 可以存储到redis,我现在是使用的mongo 做为db,不太想单独为一个socket存储启用一个redis (npm 上有一个模块 mong.socket.io/socket.io-mongo使用时经常出错),存入mongo 有没有好的方法,方案可行不? 3:客户端(用户usernam如何和node 服务器端的sockets 关联) 目前单进程直接 写了个:var usersWS = {}; usersWS[username]=socket… 【其实sokcet 存那无所谓 就是为了实现多进程 socket 互通,通过username可以找到socket 不受线程限制】

      欢迎. 多谢各位指点..谢谢

4 回复

当然,我可以帮助你解答这个问题。以下是针对你的问题的详细回答,包括一些示例代码。

1. 如何共享 Socket 开启多进程实现负载

cluster 模块可以帮助你在 Node.js 中开启多个工作进程,每个进程可以处理不同的连接请求。为了共享 socket.io 实例,我们需要将 socket.io 的实例暴露给所有工作进程。我们可以利用 Redis 或者其他共享存储机制来实现这一点。

示例代码:

const cluster = require('cluster');
const http = require('http');
const Redis = require('ioredis');
const io = require('socket.io');

if (cluster.isMaster) {
    const numWorkers = require('os').cpus().length;
    console.log(`Master ${process.pid} is running`);

    // Fork workers.
    for (let i = 0; i < numWorkers; i++) {
        cluster.fork();
    }

    cluster.on('exit', (worker, code, signal) => {
        console.log(`Worker ${worker.process.pid} died`);
    });
} else {
    const redisClient = new Redis();
    const server = http.createServer();
    const ioServer = io.listen(server, { transports: ['polling'] });

    ioServer.adapter(require('socket.io-redis')(redisClient));

    ioServer.on('connection', (socket) => {
        console.log(`Worker ${process.pid} got a connection`);
        socket.on('disconnect', () => {
            console.log('Client disconnected');
        });
    });

    server.listen(3000, () => {
        console.log(`Worker ${process.pid} started`);
    });
}

2. 使用 MongoDB 存储 Socket 信息

虽然官方文档推荐使用 Redis 作为共享存储,但如果你坚持使用 MongoDB,你可以创建一个中间件来处理这些操作。

示例代码:

const MongoClient = require('mongodb').MongoClient;

async function connectToMongo() {
    const client = await MongoClient.connect('mongodb://localhost:27017/', { useNewUrlParser: true, useUnifiedTopology: true });
    return client.db('chat_db');
}

async function storeSocket(socketId, username) {
    const db = await connectToMongo();
    const collection = db.collection('sockets');
    await collection.updateOne({ socketId }, { $set: { username } }, { upsert: true });
}

async function findSocket(username) {
    const db = await connectToMongo();
    const collection = db.collection('sockets');
    const result = await collection.findOne({ username });
    return result ? result.socketId : null;
}

3. 客户端与服务器端的关联

客户端可以通过发送用户名信息到服务器,服务器再将其存储到 MongoDB 中。

示例代码:

io.on('connection', (socket) => {
    socket.on('login', async (username) => {
        await storeSocket(socket.id, username);
        console.log(`${username} logged in`);
    });

    socket.on('disconnect', async () => {
        await removeSocket(socket.id);
        console.log(`${username} disconnected`);
    });
});

客户端可以这样发送登录信息:

socket.emit('login', 'your_username');

希望这些示例代码能帮助你更好地理解如何在 Node.js + Socket.io + MongoDB 环境下实现负载均衡和数据共享。


针对你的问题,我将逐个解答:

1. 使用 cluster 模块实现负载均衡

在 Node.js 中使用 cluster 模块来启动多个子进程可以实现负载均衡。每个子进程都会有自己的 Socket 服务,需要确保这些 Socket 之间的通信。

示例代码

const cluster = require('cluster');
const http = require('http');
const numCPUs = require('os').cpus().length;

if (cluster.isMaster) {
    for (let i = 0; i < numCPUs; i++) {
        cluster.fork();
    }

    cluster.on('exit', (worker, code, signal) => {
        console.log(`Worker ${worker.process.pid} died`);
    });
} else {
    const io = require('socket.io')(3000);
    
    let sockets = {};

    io.on('connection', function(socket) {
        let username;
        
        socket.on('login', function(data) {
            username = data.username;
            sockets[username] = socket;
        });

        socket.on('disconnect', function() {
            delete sockets[username];
        });
    });
}

2. 使用 MongoDB 存储 Socket 信息

虽然官方推荐使用 Redis,但如果你希望使用 MongoDB 来存储 Socket 信息,可以通过自定义存储方式实现。可以创建一个中间件来管理 MongoDB 的连接,并将 Socket 信息保存到 MongoDB 中。

示例代码

const MongoClient = require('mongodb').MongoClient;
const url = 'mongodb://localhost:27017/';

async function saveSocket(username, socket) {
    let db = await MongoClient.connect(url);
    let collection = db.db("chat").collection("sockets");
    await collection.insertOne({ username, socketId: socket.id });
}

io.on('connection', function(socket) {
    let username;

    socket.on('login', async function(data) {
        username = data.username;
        sockets[username] = socket;
        await saveSocket(username, socket);
    });

    socket.on('disconnect', async function() {
        delete sockets[username];
        await collection.deleteOne({ socketId: socket.id });
    });
});

3. 客户端与服务器端的关联

为了实现客户端与服务器端的关联,你需要在客户端发送登录信息给服务器,服务器则将其保存在一个映射中。

示例代码

// 客户端
socket.emit('login', { username: 'Alice' });

// 服务器端
io.on('connection', function(socket) {
    socket.on('login', function(data) {
        let username = data.username;
        sockets[username] = socket;
    });
});

以上就是你的问题的一些解决方案和示例代码。希望对你有所帮助!

回到顶部