源码:shuai.68api.cn
摘要:消息的"零丢失、低延迟"之道
在企业IM环境中,消息的可靠性 和实时性是至高要求。云脉IM如何在高并发、多设备、复杂网络状态下,实现消息的快速、精准路由,并保证离线消息的零丢失投递?
一、高性能消息路由:从连接到投递的毫秒级旅程
消息路由是IM系统的核心功能。云脉IM采用分离式路由架构,将用户状态管理、连接管理与消息路由解耦,以实现极致性能。
1. 内存级用户状态与连接管理
为了实现毫秒级查找和路由,云脉IM的信令服务器在内存中维护了一个高效的路由表。
-
数据结构优化: 使用高性能的 ConcurrentHashMap 或 Guava Cache 来存储
<UserID, Connection/SessionID>的映射关系。这种结构保证了在多线程环境下的查找、插入和删除操作的高并发性。 -
状态同步: 当用户多端登录或状态发生变化时,信令服务器通过 Redis Pub/Sub 或 Kafka 等消息中间件,将最新的用户在线状态广播到所有消息处理节点(如果系统是分布式部署),确保路由表的全局一致性。
2. 消息的快速路由决策
当信令服务器接收到一条WSS消息后,路由决策流程如下:
-
解析协议: 快速解析消息协议包(例如,JSON或Protobuf),提取发送者ID、目标ID(或群组ID)。
-
目标查找: 根据目标ID,在内存路由表中查找其对应的所有在线会话(Session)。
-
单聊: 查找到一个或多个Session(多端在线)。
-
群聊: 查找到群组内所有在线用户的Session列表。
-
-
并发投递: 使用线程池并发地将消息推送给查找到的每一个Session。
💡 Java代码片段:基于内存表的路由实现
Java
public class MessageRouter {
// 内存中的活跃连接映射 (UserID -> List<WebSocketSession>)
private final ConcurrentHashMap<String, List<WebSocketSession>> userSessionsMap = new ConcurrentHashMap<>();
// 异步投递线程池,防止阻塞主信令线程
private final ExecutorService deliveryPool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 2);
/**
* 将消息异步路由给目标用户(支持多端在线)
*/
public void routeMessage(String targetUserId, String payload) {
List<WebSocketSession> sessions = userSessionsMap.get(targetUserId);
if (sessions != null && !sessions.isEmpty()) {
sessions.forEach(session -> {
deliveryPool.submit(() -> {
try {
// 1. 检查连接状态 (Session.isOpen())
if (session.isOpen()) {
// 2. 异步发送消息
session.sendMessage(new TextMessage(payload));
} else {
// 3. 处理死连接清理
// sessionManager.remove(session);
}
} catch (IOException e) {
logger.error("Error sending message to user: {}", targetUserId, e);
}
});
});
}
// 如果 sessions 为 null 或 empty,则进入离线消息处理流程
else {
offlineQueueManager.enqueue(targetUserId, payload);
}
}
// ... 其他方法:处理用户上线、下线、多端登录逻辑
}
二、 离线消息推送:零丢失的保障机制
高性能路由解决了在线 消息的实时性,而离线消息推送 则解决了可靠性 和可达性。
1. "存储-队列"双保险机制
云脉IM采用消息持久化 与离线队列相结合的双保险机制。
-
持久化(MySQL): 所有消息(无论是实时还是离线)都会被首先写入 MySQL 数据库。这保证了消息的消息漫游 和回溯能力 ,是消息零丢失的根本保证。
-
离线队列(Redis/Kafka): 当路由决策判断目标用户当前不在线 时,该消息的元数据或引用ID会被写入到目标用户的离线消息队列 中(通常使用 Redis List 或 Kafka Topic)。
2. 上线后的自动补发与ACK确认
当离线用户重新上线时,系统会触发补发流程:
-
用户上线: 客户端建立WSS连接,信令服务器更新路由表。
-
队列检查: 信令服务器立即检查该用户在离线队列中的积压消息。
-
消息补发: 从队列中取出消息ID,从MySQL数据库中加载完整消息体,并通过WSS通道补发给用户。
-
客户端ACK: 客户端接收到消息后,发送一个确认包 (ACK) 给服务器。只有收到ACK后,服务器才会从持久化存储和离线队列中将该消息标记为已读或删除。
3. 多通道融合:保障移动端可达性
对于移动端(Android/iOS)用户,当应用被系统挂起(进程被杀)时,WSS连接会被断开,此时需要使用系统级的离线通知。
云脉IM的解决方案是多通道融合推送:
-
iOS: 通过 APNs (Apple Push Notification service) 通道。
-
Android: 优先使用国内厂商的官方通道(华为PushKit、小米Push等),如果无法使用,则回退到 FCM (Firebase Cloud Messaging)。
这种策略确保了即使应用处于后台或被杀死,用户也能通过系统通知栏接收到消息提醒,显著提升了消息的可达性。
总结:自主可控是性能的基石
云脉IM通过深度定制的Java高性能路由层 和精细化的离线推送逻辑,实现了对消息生命周期的完全掌控。
这套技术体系,不仅保障了消息的实时性(毫秒级路由)和可靠性(存储-队列双保险),更重要的是,它完全部署在企业自有基础设施上,结合源代码交付 ,为企业提供了无与伦比的性能优势、安全保障和技术自主权 。




