Socket 服务梳理与问题排查:从架构到实战

本文最后更新于 2026-08-04 15:16

Socket 服务梳理与问题排查:从架构到实战

本文系统梳理了基于 Socket.IO 的消息推送服务架构,包括服务启动流程、认证机制、消息订阅/推送模型,以及批量导入进度通知和批量导出方案的完整设计。

一、服务启动过程

1.1 启动入口

  1. 服务启动方法:SocketServiceApplication#main
  2. Socket 启动方法:SocketIOServiceImpl#autoStartup

1.2 启动流程

1
2
3
4
5
6
7
8
9
autoStartup
├── 初始化消息缓存数量,设置默认命名空间
└── 绑定监听方法 bind()
├── 监听客户端连接
├── 监听客户端断开连接
└── 监听客户端请求
├── 认证(auth
├── 订阅(sub
└── 取消订阅(cancel

二、认证过程

2.1 请求参数格式

1
2
3
4
{
"type": "auth",
"data": "jwt_token_value"
}
  • type:认证时值为 auth,订阅为 sub,取消订阅为 cancel
  • data:前端登录成功后返回的 JWT Token

2.2 认证流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
客户端发起 type=auth 请求


服务端监听到请求,初始化 Client 对象


将 Token 转为 TokenDto → 再转为 JwtDto(提取 id 等属性)


调用 login 方法
├── 设置 client.token = jwtDto.id
├── 加入私聊房间(id 不为空时)
│ 房间号规则:getUserRoom()
└── 加入群聊房间(grp 不为空时)
房间号规则:getGroupRoom()

2.3 Token 解析异常场景

异常场景 原因 参考位置
登录超时 JWT 已过期 JwtUtil#parseJwt
签名验证失败 JWT 签名与秘钥不匹配 JwtUtil#parse

Token 值是根据秘钥生成的,秘钥需要妥善管理,避免硬编码在代码中。


三、批量导入进度通知流程

这是批量导入功能中,前端提交 Excel 文件后的 WebSocket 交互流程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
┌─────────┐      ┌─────────┐      ┌─────────┐      ┌──────────┐
│ 前端 │ │ API │ │ MQ │ │ Socket │
└────┬────┘ └────┬────┘ └────┬────┘ └────┬─────┘
1.上传Excel │ │ │
│───────────────>│ │ │
│ │ 2.解析验证 │ │
│ │ 3.创建批量任务 │ │
4.返回批次号 │ │ │
│<───────────────│ │ │
5.发起订阅请求 type=sub │ │
│─────────────────────────────────────────────────>│
│ │ │ │
│ │ │ 6.创建房间 │
│ │ │ /sub/task/{id} │
│ │ │ 加入房间 │
7.订阅成功通知│ │ │
│<─────────────────────────────────────────────────│
│ │ │ │
│ │ 8.批量子任务执行完成 │
│ │ 保存结果 + 推送进度消息 │
│ │───────────────>│ │
│ │ │ 9.监听MQ消息 │
│ │ │────────────────>│
│ │ │ │
10.推送进度消息│ │ │
│<─────────────────────────────────────────────────│
│ │ │ │
11.进度100%时 │ │ │
│ 从房间移出 │ │ │

3.1 详细步骤说明

步骤 1-4:前端上传 → API 解析 → 创建批量任务 → 返回批次号

步骤 5:客户端向 WebSocket 发起订阅请求:

1
2
3
4
5
6
7
{
"type": "sub",
"data": {
"to": "41940",
"type": "task"
}
}

步骤 6-7:后端根据批次号和任务类型创建房间,以参数 {"type":"sub","data":{"to":"41826","type":"task"}} 为例,创建名为 /sub/task/41826 的房间,把当前客户端加入房间,通知客户端订阅成功。

步骤 8:批量子任务执行完成后,保存结果并推送进度消息。推送内容包括:

字段 说明
批次号 标识当前批量任务
错误数量 执行出错的子任务数
当前状态 任务执行状态
已执行数量 已完成的子任务数
任务总数 子任务总数
已成功数量 成功的子任务数
进度百分比 已执行进度
是否最后一条 进度 100% 时为 true

如果有回调,回调占 20% 的进度。

步骤 9-10:Socket 服务监听 MQ 消息,推送到对应房间。

步骤 11:如果发送的消息是该房间内最后一条消息(进度 100%),推送完成后把该客户端从房间移出。

3.2 消息缓冲机制

Socket 服务内部实现了消息缓冲机制,避免高频推送导致前端卡顿:

  • 第一条消息:不缓冲,立即发送
  • 最后一条消息:不缓冲,立即发送
  • 中间消息:根据 interval 字段(默认 1000ms)判断是否到了发送时间
    • 未到时间 → 缓存消息,放入线程池中定时执行
    • 到了时间 → 直接发送

四、批量导出方案

4.1 数据库设计

新增两张表:

表名 用途
导出数据临时表 存放需要导出的完整数据(JSON 格式)
导出记录表 记录导出批次号和导出文件 ID

每个需要导出功能的服务及对应的库都要加这两张表和一个查询接口。

4.2 导出流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
1. 前端发送导出请求(带查询条件)


2. 查询导出数据总条数


3. 发起批量异步任务(带回调),子任务中存放主表 ID


4. 返回批次号


5. 前端根据批次号发起订阅,订阅批次号的房间


6. 批量子任务执行:根据 ID 组装导出数据 → 存入"导出数据临时表"


7. Socket 服务监听 MQ → 推送进度到房间


8. 前端收到进度消息 → 更新进度条


9. 所有子任务完成 → 发起回调


10. 回调函数:分页查询"导出数据临时表" → 生成 Excel → 保存文件 ID 到"导出记录表"


11. 推送进度 100%


12. 前端收到 100% → 调用接口查询是否有文件 ID

├── 有文件 ID → 直接下载
└── 无文件 ID → 按批量导入逻辑处理

4.3 关键设计点

  • 分页查询:回调中分页查询导出数据临时表,避免内存溢出
  • 进度回调:回调执行占 20% 进度,子任务执行占 80%
  • 文件下载:前端收到 100% 进度后,先查询是否有文件 ID,有则直接下载

五、常见问题与解决方案

5.1 生产环境进度条偶现为 0

现象:生产环境偶现进度条显示为 0。

可能原因

  1. 消息缓冲时间间隔配置不当
  2. 客户端订阅时序问题(订阅还未完成,消息已经推送)
  3. Socket 服务多实例部署时,消息推送到了错误的实例

排查方向

  • 确认订阅成功后再触发批量任务
  • 检查 Socket 服务的分布式部署逻辑
  • 验证消息缓冲的 interval 配置是否合理

5.2 JWT 认证失败

现象:客户端连接后认证失败。

排查步骤

  1. 检查 Token 是否过期
  2. 检查 Token 签名秘钥是否一致
  3. 确认 Token 格式是否正确

5.3 消息推送延迟

现象:进度条更新不及时。

排查步骤

  1. 检查消息缓冲的 interval 配置
  2. 确认 MQ 消息是否及时消费
  3. 检查 Socket 服务线程池是否正常

Socket 服务梳理与问题排查:从架构到实战
https://your-project-name.pages.dev/2026/07/25/socket-service-troubleshooting/
作者
阿川
发布于
2026年7月25日
许可协议