服务器崩溃时如何处理依赖WebSocket的关联业务数据?
核心逻辑
通过心跳过期+启动预检+定时兜底三层机制,完全覆盖服务器崩溃、网络中断、用户异常断开等场景下的脏数据问题,无需额外中间件依赖,性能损耗极低。
具体实现步骤
表结构调整
给用户-房间关联表新增
last_heartbeat(最后心跳时间)、bound_server_id(绑定的服务实例ID)两个字段:-- 示例DDL,假设关联表名为room_user_mapping ALTER TABLE room_user_mapping ADD COLUMN last_heartbeat TIMESTAMPTZ NOT NULL DEFAULT NOW(), ADD COLUMN bound_server_id VARCHAR(64) NOT NULL;其中
bound_server_id为每个服务实例启动时生成的唯一随机ID,存在实例内存中。启动预检清理
服务实例重启完成后,首先执行一次清理操作,删除所有
bound_server_id等于当前实例ID的历史记录:DELETE FROM room_user_mapping WHERE bound_server_id = '当前实例的ID';原理:服务崩溃重启后,之前绑定到该实例的所有用户连接已经全部断开,这些记录必然是脏数据,直接清理即可。
心跳更新机制
前端保持每30秒向后端发送一次心跳请求,后端收到请求后更新对应用户记录的
last_heartbeat为当前时间:UPDATE room_user_mapping SET last_heartbeat = NOW() WHERE user_id = $1 AND room_id = $2;定时任务兜底清理
后台启动一个定时任务(每1分钟执行一次),删除所有
last_heartbeat早于当前时间2分钟以上的记录:DELETE FROM room_user_mapping WHERE last_heartbeat < NOW() - INTERVAL '2 minutes';即使出现跨实例异常、网络分区等极端情况,超时的无效记录也会被定期清理,不会长期残留。
客户端兼容逻辑
前端检测到连接断开后自动触发重连,重连成功后重新发送加入房间请求,自动重建关联记录,用户无感知。
可选轻量方案(适用于长连接独享数据库会话场景)
如果你的每个用户长连接对应后端一个独立的数据库会话,可以直接使用Postgres临时表存储用户-房间关联数据:
-- 临时表仅对当前会话可见,会话断开后自动删除所有数据 CREATE TEMP TABLE room_user_session ( room_id INT, user_id INT, PRIMARY KEY(room_id, user_id) ) ON COMMIT PRESERVE ROWS;
该方案完全不需要手动处理脏数据,Postgres会在连接断开时自动清理临时表数据,零额外开发成本。
这套方案的优势在于三层逻辑互相兜底,没有单点失效风险:启动清理解决实例崩溃的脏数据,心跳+定时清理解决所有其他异常断开场景,即使某一层逻辑失效,其他层也能保证数据正确性,适配单实例、多实例等所有部署模式。
内容的提问来源于stack exchange,提问作者Helder Esteves

