WebSocket长连接优化:宠友IM源码中的心跳与断线重连机制

IM系统上线之后,最容易被忽略的一类问题不是发送失败,而是“看起来在线,实际上已经断了”。这种情况用户感知很直接:消息发不出去、收不到、需要反复重启应用。

宠友信息在「宠友IM」源码里,对WebSocket连接这一层做了不少细节处理,没有复杂协议,但在心跳检测、断线重连、连接状态维护这几个点上比较扎实。

这篇只拆一个主题:WebSocket连接稳定性优化

一、长连接为什么会“假在线”

很多开发阶段的WebSocket实现是这样的:

  • 建立连接
  • 收发消息
  • 断开再连

问题在于:TCP连接不等于真实在线状态

常见导致“假在线”的情况:

  • 手机切后台,系统暂停网络
  • 网络切换(WiFi → 4G)
  • 路由器NAT回收连接
  • 服务端连接未及时释放

这类问题不会触发onClose,服务端依然认为用户在线。

二、心跳机制设计(核心)

宠友IM没有使用复杂协议,而是采用最常见的一种:

👉 客户端主动心跳 + 服务端检测超时

基本策略:

  • 客户端每30秒发送一次ping
  • 服务端记录最后活跃时间
  • 超过一定时间未收到心跳 → 判定离线

服务端核心逻辑:

// 简化示例:记录用户最后心跳时间
private static final ConcurrentHashMap<Long, Long> HEARTBEAT_MAP = new ConcurrentHashMap<>();

public void onHeartbeat(Long userId) {
HEARTBEAT_MAP.put(userId, System.currentTimeMillis());
}

配合定时任务扫描:


// 超时检测(60秒未心跳判定离线)
public void checkTimeout() {
long now = System.currentTimeMillis();
HEARTBEAT_MAP.forEach((userId, lastTime) -> {
if (now - lastTime > 60000) {
// 关闭连接 + 清理资源
disconnect(userId);
}
});
}

这种方式简单,但足够稳定。

三、为什么不能只依赖WebSocket事件

很多实现只依赖:

  • onOpen
  • onClose
  • onError

问题在于:

👉 这些事件并不可靠

比如:

  • 用户断网 → 服务端可能长时间收不到onClose
  • 网络抖动 → 连接处于半开状态

宠友IM的处理方式是:

  • WebSocket事件只是“参考”
  • 心跳机制才是“最终判定”

四、断线重连策略(客户端关键逻辑)

断线不可避免,关键是重连策略。

常见错误做法:

  • 立即重连
  • 无限重试

结果:

  • 短时间内大量请求
  • 服务端压力暴涨

宠友IM采用:

👉 指数退避重连

逻辑:

  • 第1次失败:1秒后重连
  • 第2次失败:2秒
  • 第3次失败:4秒
  • 上限:30秒

避免雪崩。

客户端伪代码:

let retry = 0;

function reconnect() {
const delay = Math.min(30000, Math.pow(2, retry) * 1000);
setTimeout(() => {
connect();
retry++;
}, delay);
}

这个策略在网络波动场景下非常关键。

五、多端登录下的连接管理

宠友IM支持:

  • APP
  • 小程序
  • H5
  • PC

多端意味着:

👉 一个用户会有多个连接

服务端结构设计不是:

userId -> session

而是:

userId -> {设备类型 -> session}

这样可以做到:

  • 不同端独立在线
  • 消息可以同步推送多个端

同时避免:

  • 新设备登录踢掉旧连接

六、连接状态同步问题

在单机下维护连接没问题,但一旦多节点部署:

  • A服务器有连接
  • B服务器不知道

宠友IM没有做复杂网关,而是用简单方案:

👉 Redis记录在线状态 + 广播机制

处理方式:

  • 用户上线 → 写Redis
  • 用户下线 → 删除Redis
  • 发送消息时判断目标是否在线

这样可以做到:

  • 跨节点识别在线状态
  • 简单扩展

七、连接资源清理

连接不及时释放,会带来两个问题:

  • 内存泄漏
  • 连接数爆满

宠友IM的处理策略:

  • onClose清理
  • 心跳超时强制清理
  • 异常捕获统一关闭

重点在于:不要依赖单一入口释放资源

八、消息发送失败处理

WebSocket发送不是100%成功:

  • 连接存在但不可写
  • 网络瞬断

宠友IM没有假设“发送一定成功”,而是:

👉 失败后走降级路径

策略:

  • 发送失败 → 写入离线消息
  • 用户下次上线拉取

这样可以保证:

  • 消息不丢
  • 用户体验一致

九、线上遇到的几个典型问题

1)频繁断开重连

原因:

  • 心跳间隔过短
  • 服务端超时过严

调整:

  • 心跳30秒
  • 超时60~90秒

2)连接暴涨

原因:

  • 客户端异常重连
  • 没有限流

处理:

  • 增加连接频率限制
  • 同IP限流

3)消息延迟

原因:

  • 连接处于半开状态
  • 数据未及时发送

解决:

  • 心跳检测及时断开
  • 强制重连

4)多端状态错乱

原因:

  • 一个端断开,误删全部状态

解决:

  • 按设备维度维护连接
  • 独立管理生命周期

十、这类WebSocket优化的核心思路

宠友信息这套实现没有复杂协议,也没有引入额外网关层,但有几个关键点:

  • 用心跳替代连接状态判断
  • 用重连策略避免流量冲击
  • 用简单结构支持多端在线

IM系统稳定性问题,本质不在“用不用WebSocket”,而在于:

👉 是否正确处理“连接不可靠”这件事

市面上已有成熟的源码⭐宠友IM⭐https://www.chongyou.info/1/product/im.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值