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 不受线程限制】
欢迎. 多谢各位指点..谢谢
当然,我可以帮助你解答这个问题。以下是针对你的问题的详细回答,包括一些示例代码。
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 环境下实现负载均衡和数据共享。
可以看看如下项目:
谢谢啊 你说的最新版本是这个mong.socket.io ,测试bug 太多
针对你的问题,我将逐个解答:
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;
});
});
以上就是你的问题的一些解决方案和示例代码。希望对你有所帮助!