You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

粘性会话工作原理及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的连接问题。

这段代码的逻辑拆解:

  1. sticky.listen(server, port):调用Sticky Session的listen方法启动服务:

    • 如果当前是主进程:sticky.listen返回false,进入第一个分支。主进程会自动创建和CPU核心数(你的4核)一致的Worker子进程,并且负责监听端口,把客户端的连接请求转发到对应的Worker。
    • 如果当前是子进程(Worker):sticky.listen返回true,进入else分支,子进程启动自己的服务实例,等待主进程转发过来的连接。
  2. 第一个分支(主进程逻辑):

    • server.once('listening', ...):当服务器开始监听端口时,打印服务启动的提示。
    • if (cluster.isMaster):确认当前是主进程,打印主进程启动的提示。
  3. 第二个分支(子进程逻辑):

    • 打印当前启动的子进程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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 07:38:29