IM 即时通讯系统消息 有序性与可靠性 的全链路设计与工程实现

在 IM 聊天系统中,消息不丢、不重、不乱序 是最核心、也是最难实现的目标之一。 本文从 架构设计 → 协议机制 → 数据模型 → Java 工程实现 全链路展开,给出一套可直接落地的 企业级 IM 消息有序性与可靠性解决方案


一、问题背景与设计目标

1. IM 系统面临的核心挑战

在真实网络环境中,IM 系统必须面对:

  • 网络抖动 / 丢包 / 重连
  • 多端同时在线(手机 / PC / Web)
  • 分布式服务带来的乱序
  • 客户端与服务端时钟不一致
  • 服务宕机、进程重启、消息重放

2. 设计目标拆解

目标含义
不丢失任何已确认发送的消息最终一定可达
不重复重传、重放不会导致多次投递
不乱序会话内消息对用户展示始终有序
高可用服务重启、节点切换不影响正确性
低延迟不因强一致牺牲用户体验

二、总体设计思想(先给结论)

核心原则:允许乱序到达,但保证最终有序;优先可靠性,其次强顺序

我们采用以下总体策略:

  • 服务端统一分配序列号(Seq)
  • 客户端永远不信任本地时间
  • 消息可乱序到达,展示必须按序
  • 可靠性靠 ACK + 重试 + 持久化
  • 顺序性靠 Seq + 重排窗口

三、消息有序性设计(Ordering)


3.1 全局唯一消息 ID(MessageId)

设计目的
  • 去重
  • 幂等
  • 链路追踪
  • 分布式环境唯一性
方案

使用 Snowflake 变体算法

| 时间戳 | 实例ID | 序列号 |
  • 时间递增
  • 无中心依赖
  • 支持高并发
** 全局唯一ID生成器(Snowflake变体)**
@Component public class MessageIdGenerator { // 起始时间戳(2024-01-01) private static final long START_TIMESTAMP = 1704067200000L; // 各部分占位 private static final long SEQUENCE_BITS = 12; // 序列号12位 private static final long INSTANCE_BITS = 10; // 实例ID10位 private static final long MAX_SEQUENCE = (1 << SEQUENCE_BITS) - 1; private static final long MAX_INSTANCE = (1 << INSTANCE_BITS) - 1; // 移位偏移量 private static final long TIMESTAMP_SHIFT = SEQUENCE_BITS + INSTANCE_BITS; private static final long INSTANCE_SHIFT = SEQUENCE_BITS; private final long instanceId; // 实例ID(0-1023) private long lastTimestamp = -1L; private long sequence = 0L; public MessageIdGenerator(@Value("${server.instance-id:0}") long instanceId) { if (instanceId > MAX_INSTANCE || instanceId < 0) { throw new IllegalArgumentException("实例ID超出范围"); } this.instanceId = instanceId; } public synchronized long nextId() { long currentTimestamp = getCurrentTimestamp(); // 时钟回拨处理 if (currentTimestamp < lastTimestamp) { throw new RuntimeException("时钟回拨异常"); } // 同一毫秒内生成 if (currentTimestamp == lastTimestamp) { sequence = (sequence + 1) & MAX_SEQUENCE; if (sequence == 0) { // 序列号用尽,等待下一毫秒 currentTimestamp = waitNextMillis(lastTimestamp); } } else { sequence = 0L; // 新毫秒重置序列号 } lastTimestamp = currentTimestamp; // 组合ID:时间戳 | 实例ID | 序列号 return ((currentTimestamp - START_TIMESTAMP) << TIMESTAMP_SHIFT) | (instanceId << INSTANCE_SHIFT) | sequence; } // 解析ID的各个部分 public static IdParts parseId(long id) { return new IdParts( (id >> TIMESTAMP_SHIFT) + START_TIMESTAMP, (id >> INSTANCE_SHIFT) & MAX_INSTANCE, id & MAX_SEQUENCE ); } private long waitNextMillis(long lastTimestamp) { long timestamp = getCurrentTimestamp(); while (timestamp <= lastTimestamp) { timestamp = getCurrentTimestamp(); } return timestamp; } private long getCurrentTimestamp() { return System.currentTimeMillis(); } @Data @AllArgsConstructor public static class IdParts { private long timestamp; private long instanceId; private long sequence; } }

3.2 会话级序列号(Session Seq)

为什么还需要 Seq?

MessageId 只能保证“全局唯一”,不能保证会话内顺序

IM 的顺序要求是:

  • 单聊 / 群聊内部严格有序
  • 不同会话之间无序无关
方案
  • 每个 sessionId 维护独立递增序列
  • 使用 Redis INCR 原子操作
  • 服务端统一分配
** 会话序列号生成器**
@Service public class SessionSequenceService { @Autowired private RedisTemplate<String, String> redisTemplate; private static final String SEQ_KEY_PREFIX = "im:session:seq:"; private static final long MAX_SEQ = 0x7FFFFFFFFFFFFFFFL; // Long.MAX_VALUE /** * 为会话生成递增序列号(原子操作) */ public long nextSequence(String sessionId) { String key = SEQ_KEY_PREFIX + sessionId; // 使用Redis原子递增 Long seq = redisTemplate.opsForValue().increment(key); if (seq == null) { throw new RuntimeException("获取序列号失败"); } // 序列号溢出处理(实际场景很少发生) if (seq >= MAX_SEQ) { // 重置序列号,记录到数据库用于历史消息同步 resetSe

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1131604.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深度学习毕设项目推荐-基于python-CNN卷积神经网络的水果识别基于机器学习卷积神经网络的水果识别

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

【课程设计/毕业设计】通过python_CNN卷积神经网络对鸡蛋是否破损识别

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

深度学习毕设项目推荐-基于python-CNN卷积神经网络对土豆疾病识别

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

NFS服务端操作系统常用操作手册:体系化指南

一、NFS基础概述 1.1 什么是NFS&#xff1f; 网络文件系统&#xff08;Network File System&#xff09;是一种分布式文件系统协议&#xff0c;允许客户端计算机通过网络访问服务器上的文件&#xff0c;就像访问本地存储一样。 1.2 核心组件 nfs-utils: NFS服务套件rpcbind: RP…

通信协议仿真:通信协议基础_(6).网络层协议仿真

网络层协议仿真 在网络层协议仿真中&#xff0c;我们将探讨如何通过仿真工具和编程语言来模拟网络层协议的行为。网络层协议负责将数据从源节点传输到目的节点&#xff0c;涉及到路由选择、分组转发、地址管理等关键功能。通过仿真&#xff0c;我们可以更好地理解这些协议的工作…

【强烈收藏】我Python都不会,能直接学AI大模型吗?——小白避坑指南

文章探讨学习AI大模型的前提条件&#xff0c;指出普通人无需从零开始造模型&#xff0c;而是学习使用现有模型。分析常见学习障碍&#xff1a;数学恐惧、代码过敏、耐心缺失和硬件不足&#xff0c;并提供差异化学习路径&#xff1a;大学生应打好数学编程基础&#xff0c;积累实…

深度学习毕设项目推荐-通过python_CNN卷积神经网络对鸡蛋是否破损识别

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

LeetCode热题100--5. 最长回文子串--中等

题目 给你一个字符串 s&#xff0c;找到 s 中最长的 回文 子串。 示例 1&#xff1a; 输入&#xff1a;s “babad” 输出&#xff1a;“bab” 解释&#xff1a;“aba” 同样是符合题意的答案。 示例 2&#xff1a; 输入&#xff1a;s “cbbd” 输出&#xff1a;“bb” 题…

【值得收藏】大模型RAG技术突破:12种创新架构全解析,助你掌握前沿检索增强生成技术

本文介绍了12种最新的RAG高级架构与方法&#xff0c;包括Mindscape-Aware RAG、基于超图记忆的多步RAG、高保真分层RAG等创新技术。这些方法针对长文档理解、多步推理、减少幻觉、多模态处理等场景进行了优化&#xff0c;每个方法均附有论文链接&#xff0c;为开发者提供了丰富…

深度学习毕设项目推荐-通过python_CNN卷积神经网络对辣椒类别识别

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

ADVANCE Day45

浙大疏锦行 &#x1f4d8; Day 45 实战作业&#xff1a;给模型装上仪表盘 —— TensorBoard 实战 1. 作业综述 核心目标&#xff1a; 环境搭建&#xff1a;安装并启动 TensorBoard。指标监控 (Scalar)&#xff1a;不再盯着控制台刷屏&#xff0c;而是画出漂亮的 Loss 和 Ac…

2026年转行AI大模型必备:两个高薪岗位,让你年后求职弯道超车

文章指出当前就业市场低迷&#xff0c;但春节后很快进入春招旺季&#xff0c;建议现在就开始准备。重点推荐两个普通人也能入行的AI方向&#xff1a;AI大模型应用开发师&#xff08;年薪最高72万&#xff09;和AI大模型训练师&#xff08;年薪最高45万&#xff09;。AI行业正处…

一文搞清微调技术的发展与演进

现在的大语言模型发展得非常快&#xff0c;从几亿参数到千亿参数&#xff0c;不仅模型越来越大&#xff0c;能力也越来越强。但是在实际工作中&#xff0c;我们很少会从零开始训练一个这样的巨无霸模型&#xff0c;因为那样的成本和资源需求实在太高了。更多的时候&#xff0c;…

linux的root目录缓存清理

1. 找出隐藏的大文件 / 文件夹&#xff08;关键步骤&#xff09;先执行以下命令&#xff0c;查看 /root 下所有文件&#xff08;包括隐藏文件&#xff09; 的空间占用&#xff0c;定位具体占用空间的文件&#xff1a;# 查看/root下所有文件&#xff08;含隐藏&#xff09;的空间…

【收藏】LLM大模型全景解析:从零开始理解AI智能的诞生

LLM大模型是基于Transformer架构的海量参数模型&#xff0c;通过规模效应、自注意力机制和训练范式调整实现通用智能。工作流程包括分词、嵌入表示、多层Transformer堆叠和概率预测&#xff0c;实现数据压缩→规律学习→智能涌现。LLM有Decoder-Only、Encoder-Only和Encoder-De…

深度学习计算机毕设之通过python_CNN卷积神经网络对鸡蛋是否破损识别

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

mysql之联合索引

文章目录 一&#xff1a;联合索引二&#xff1a;创建联合索引三&#xff1a;删除索引四&#xff1a;总结&#xff1a; 一&#xff1a;联合索引 联合索引又称组合索引或者复合索引&#xff0c;是建立在俩列或者多列以上的索引。 二&#xff1a;创建联合索引 语法&#xff1a…

mysql之字符串函数

假设我们有一个字符串 Hello, World! 作为示例&#xff0c;我们会展示对这个字符串应用每个函数后的结果。 CONCAT(str1, str2, …) 将多个字符串值连接成一个字符串。 SELECT CONCAT(Hello, , World!); -- 结果: Hello, World!LENGTH(str) 返回字符串的长度&#xff08;字节数…

大模型入门必看:一篇读懂AI大模型核心知识,建议收藏!

本文全面介绍了AI大模型家族的基础知识&#xff0c;包括AIGC的两种类型和三个发展阶段&#xff0c;详细解释了AI、机器学习、深度学习、生成式AI和大语言模型之间的关系与区别。重点阐述了Transformer架构及其自注意力机制在大语言模型中的核心作用&#xff0c;以及大语言模型的…