粘性会话工作原理及Node.js相关代码逐行解析请求
没问题,我来帮你逐行拆解这段代码,顺便把Sticky Session和Redis适配器的核心工作原理给你讲透~
首先先贴出完整代码方便对照:
http = require('http'), express = require('express'), socketIO = require('socket.io'), cluster = require('cluster'), port = process.env.PORT || 3000; socket_redis=require('socket.io-redis') var app = express(), io; server = http.Server(app); app.set('view engine','ejs'); app.get('/', function (req, res) { console.log('send message by worker: ' + cluster.worker.id); res.render('abhi'); }); io = socketIO(server); io.adapter(socket_redis({host:'localhost',port:'6379'})) io.on("connection",s=>{ s.on("new",data=>{ console.log("hey you") }) }) // Add your socket.IO connection logic here if(!sticky.listen(server,port)) { server.once('listening', function() { console.log('Server started on port '+port); }); if (cluster.isMaster) { console.log('Master server started on port '+port); } } else { console.log('- Child server started on port '+port+' case worker id='+cluster.worker.id); }
逐行解析 + 核心机制说明
1. 模块引入与基础配置
http = require('http'), express = require('express'), socketIO = require('socket.io'), cluster = require('cluster'), port = process.env.PORT || 3000; socket_redis=require('socket.io-redis')
http = require('http'):引入Node.js内置的HTTP模块,用来搭建底层的HTTP服务器。express = require('express'):引入Express框架,帮我们快速处理路由、模板渲染这些Web开发的常用需求。socketIO = require('socket.io'):引入Socket.IO库,实现客户端和服务器之间的实时双向通信(比如聊天、实时通知)。cluster = require('cluster'):引入Node.js的Cluster模块,用来创建多进程(主进程+子进程),把你的4核CPU都利用起来,提升服务性能。port = process.env.PORT || 3000:设置服务端口,优先用环境变量里配置的端口,没有的话默认用3000。socket_redis=require('socket.io-redis'):引入Socket.IO的Redis适配器,这是多进程下Socket通信的关键工具,后面会重点讲。
2. 初始化Express与HTTP服务器
var app = express(), io; server = http.Server(app);
var app = express():创建一个Express应用实例,用来处理HTTP请求和页面渲染。io:先声明一个变量,后面用来存Socket.IO的实例。server = http.Server(app):把Express应用挂载到HTTP服务器上,这样服务器既能处理Express的路由请求,又能处理Socket.IO的WebSocket连接。
3. 配置模板引擎与路由
app.set('view engine','ejs'); app.get('/', function (req, res) { console.log('send message by worker: ' + cluster.worker.id); res.render('abhi'); });
app.set('view engine','ejs'):告诉Express用EJS作为模板引擎,这样可以渲染views文件夹下的.ejs页面文件。app.get('/', ...):定义根路径的GET请求处理逻辑:console.log('send message by worker: ' + cluster.worker.id):打印当前处理这个请求的子进程ID,方便你看请求是被哪个Worker接管的。res.render('abhi'):渲染名为abhi的EJS模板,把页面返回给客户端。
4. 初始化Socket.IO与Redis适配器
io = socketIO(server); io.adapter(socket_redis({host:'localhost',port:'6379'}))
io = socketIO(server):把Socket.IO绑定到之前创建的HTTP服务器上,这样服务器就能监听客户端的WebSocket连接请求了。io.adapter(socket_redis({host:'localhost',port:'6379'})):给Socket.IO配置Redis适配器,这是多进程Socket通信的核心:
默认情况下,每个Worker进程的Socket.IO消息是孤立的——比如Worker1上的客户端发消息,只有Worker1上的其他客户端能收到。加了Redis适配器后,所有Worker都会把消息同步到Redis中,其他Worker从Redis拿到消息后,再推送给自己管理的客户端,这样就实现了全局消息广播,不管客户端连到哪个Worker,都能收到所有消息。
5. Socket.IO连接处理逻辑
io.on("connection",s=>{ s.on("new",data=>{ console.log("hey you") }) })
io.on("connection", s => { ... }):当有客户端通过WebSocket成功连接到服务器时,触发这个回调,s就是当前客户端的Socket实例,用来和这个客户端单独通信。s.on("new", data => { ... }):监听当前客户端发送的new事件,一旦收到这个事件,就打印"hey you"到控制台,data是客户端传过来的消息内容(这里没用到)。
6. Sticky Session与Cluster进程管理(重点!)
if(!sticky.listen(server,port)) { server.once('listening', function() { console.log('Server started on port '+port); }); if (cluster.isMaster) { console.log('Master server started on port '+port); } } else { console.log('- Child server started on port '+port+' case worker id='+cluster.worker.id); }
先说明:这里的sticky是你代码里没显式引入的模块,应该是sticky-session包,专门用来解决多进程下Socket.IO的连接问题。
这段代码的逻辑拆解:
sticky.listen(server, port):调用Sticky Session的listen方法启动服务:- 如果当前是主进程:
sticky.listen返回false,进入第一个分支。主进程会自动创建和CPU核心数(你的4核)一致的Worker子进程,并且负责监听端口,把客户端的连接请求转发到对应的Worker。 - 如果当前是子进程(Worker):
sticky.listen返回true,进入else分支,子进程启动自己的服务实例,等待主进程转发过来的连接。
- 如果当前是主进程:
第一个分支(主进程逻辑):
server.once('listening', ...):当服务器开始监听端口时,打印服务启动的提示。if (cluster.isMaster):确认当前是主进程,打印主进程启动的提示。
第二个分支(子进程逻辑):
- 打印当前启动的子进程ID和端口,说明这个Worker已经准备好处理请求了。
为什么需要Sticky Session?
Socket.IO的连接建立需要先经过HTTP握手,握手成功后才会升级为WebSocket连接。如果没有Sticky Session,同一个客户端的握手请求和后续的WebSocket连接可能会被分配到不同的Worker进程——而不同Worker之间没有共享握手信息,会导致连接失败。
Sticky Session的工作原理是:根据客户端的IP地址或Cookie,把同一个客户端的所有请求都分配到同一个Worker进程,这样握手和后续的WebSocket连接都在同一个Worker里处理,保证连接正常建立。
Redis适配器和Sticky Session的配合:
- Sticky Session解决的是连接建立时的进程分配问题,确保同一个客户端的连接始终在同一个Worker上。
- Redis适配器解决的是多进程之间的消息同步问题,实现全局消息广播。
两者配合,既利用了多进程提升服务性能,又保证了Socket.IO的实时通信功能正常工作。
内容的提问来源于stack exchange,提问作者Abhinav Singh
相关产品推荐
相关产品推荐

