尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
即时通讯源码从消息入口到异步任务的后端分层
即时通讯源码如果只围绕“发送消息接口”组织代码后期会很容易变重。一开始只是文本、图片、文件、表情继续往后已读回执、消息撤回、收藏、朋友圈互动、红包状态、钱包流水、群成员变更、语音视频邀请、多人会议加入离开都会进入同一条实时链路。这些行为不一定都应该写进聊天消息表也不一定都应该被客户端渲染成聊天气泡。更合适的方式是把它们统一抽象成事件再按事件类型进入不同处理链路。从事件如何进入系统、如何分发、如何存储、如何异步处理、如何同步到多端来看 SpringBoot WebSocket Redis Stream 的设计方式。客户端行为 ↓ WebSocket 接入层 ↓ 事件包装 EventEnvelope ↓ 同步主链路 ├─ 权限校验 ├─ 状态校验 ├─ 核心数据落库 └─ ACK 返回 ↓ Redis Stream 异步事件 ├─ 会话刷新 ├─ 通知提醒 ├─ 事件日志 ├─ 搜索索引 └─ 多端状态同步这张链路草图的重点是实时操作和异步任务不要挤在同一个方法里。用户发送一条文件消息核心链路只需要处理文件引用、消息落库、ACK 返回和在线推送。至于搜索索引、操作日志、通知提醒、资源引用统计可以交给异步事件处理。用户撤回一条消息核心链路只需要校验权限、更新消息状态、推送撤回事件。至于多端缓存刷新、审计日志、会话摘要更新可以作为后续事件消费。这样可以避免 WebSocket 入口越来越厚。先统一事件外壳再处理业务差异即时通讯系统里的事件来源很多。用户发文本是事件。用户发文件也是事件。用户收藏消息是事件。用户读完会话是事件。用户发起视频通话是事件。用户进入多人会议也是事件。如果每种行为都独立写一套入参结构后端很快就会堆出大量相似代码。更稳定的方式是先定义统一事件外壳再把业务差异放进 payload。public class ImEventEnvelope { private String eventId; private String traceId; private String eventType; private Long userId; private String device; private String conversationId; private Long createdAt; private MapString, Object payload; public boolean isMessageEvent() { return eventType ! null eventType.startsWith(MESSAGE_); } public boolean isStateEvent() { return eventType ! null eventType.startsWith(STATE_); } public boolean isSignalEvent() { return eventType ! null eventType.startsWith(SIGNAL_); } }这个结构可以覆盖多类场景MESSAGE_SEND表示普通消息发送文本、图片、文件、表情、引用回复、合并转发都可以走这类事件。STATE_READ表示已读回执不需要进入聊天气泡只需要更新读取位置和未读数。STATE_REVOKE表示消息撤回客户端收到后更新本地消息状态。SIGNAL_CALL_INVITE表示语音或视频邀请IM 通道只传信令不传媒体流。SIGNAL_MEETING_JOIN表示加入多人会议可以同步会议成员状态。这种设计可以让聊天消息、状态同步、音视频信令分开处理而不是全部塞进一个“消息发送”方法里。事件类型不要直接等于页面功能页面上看到的入口不一定等于后端事件类型。比如“发送文件”这个动作至少可以拆成两个事件RESOURCE_UPLOADED MESSAGE_SEND文件先通过 HTTP 上传生成资源 ID随后 WebSocket 发送一条文件消息消息里只引用 resourceId。“收藏文件”也不是复制文件内容而是产生一个收藏状态事件STATE_FAVORITE_ADD收藏表保存对象类型和对象 ID。对象可以是 messageId、resourceId、postId 或 forwardId。“朋友圈评论提醒”也不应该直接写进聊天消息表。朋友圈本身属于内容流评论产生后可以转成通知事件CONTENT_COMMENT_CREATED STATE_NOTIFY_PUSH这样聊天系统仍然保持会话结构朋友圈保持内容流结构两者通过事件发生关联。Redis Stream 承接非核心任务SpringBoot 主链路处理完核心数据后可以把后续任务写入 Redis Stream。这样不会让消息发送、撤回、已读这类实时操作被日志、索引、统计任务拖慢。Service public class ImEventPublisher { private final StringRedisTemplate redisTemplate; public ImEventPublisher(StringRedisTemplate redisTemplate) { this.redisTemplate redisTemplate; } public void publish(ImEventEnvelope event) { MapString, String body new HashMap(); body.put(eventId, event.getEventId()); body.put(traceId, event.getTraceId()); body.put(eventType, event.getEventType()); body.put(userId, String.valueOf(event.getUserId())); body.put(device, event.getDevice()); body.put(conversationId, event.getConversationId()); body.put(payload, JsonUtils.toJson(event.getPayload())); redisTemplate.opsForStream().add(im:event:stream, body); } }可以进入 Redis Stream 的任务包括消息发送后的会话摘要刷新。消息撤回后的多端状态同步。文件消息后的资源引用统计。收藏变更后的收藏列表刷新。朋友圈互动后的通知生成。红包状态变化后的事件日志记录。多人会议状态变化后的在线端通知。这里的关键点不是“所有事件都异步”而是区分主链路和扩展链路。主链路要保证实时反馈。异步链路负责后续扩散。事件日志不是消息表的替代品即时通讯源码里常见一个误区已经有消息表了就不需要事件日志。实际上两者职责不同。消息表记录会话中的聊天内容。事件日志记录系统中发生过的关键动作。用户发了一条文本消息消息表需要保存正文事件日志可以记录这次发送操作的 traceId、设备、处理状态。用户撤回消息消息表更新状态事件日志记录是谁撤回、从哪个端撤回、影响了哪条消息。用户加入群聊群成员表写入关系事件日志记录入群来源是扫码、邀请还是后台加入。用户领取红包钱包流水记录金额变化事件日志记录该业务动作和会话事件之间的关联。事件日志可以这样设计CREATE TABLE im_event_log ( id BIGINT PRIMARY KEY AUTO_INCREMENT, event_id VARCHAR(64) NOT NULL, trace_id VARCHAR(64) NOT NULL, event_type VARCHAR(64) NOT NULL, user_id BIGINT NOT NULL, device VARCHAR(32) DEFAULT NULL, conversation_id VARCHAR(64) DEFAULT NULL, target_id VARCHAR(64) DEFAULT NULL, event_status TINYINT DEFAULT 0, payload JSON, created_time DATETIME DEFAULT CURRENT_TIMESTAMP, UNIQUE KEY uk_event_id (event_id), KEY idx_trace_id (trace_id), KEY idx_user_time (user_id, created_time), KEY idx_conversation_time (conversation_id, created_time) );有了事件日志排查问题时可以按 traceId 找到一次操作的完整路径。比如用户反馈“收藏后 PC 端没刷新”可以查看收藏事件是否生成。事件是否写入 Redis Stream。多端推送是否执行。PC 端是否在线。客户端是否消费了状态事件。如果没有事件日志只能分别翻消息表、收藏表、WebSocket 日志和客户端日志定位成本会高很多。聊天消息和状态事件分流即时通讯系统里的 WebSocket 下发数据不应该全部进入聊天列表。可以分成三类第一类聊天类事件进入消息列表例如文本、图片、文件、语音、视频、表情、名片、引用回复、合并转发摘要。第二类状态类事件不进入消息列表只更新状态例如已读回执、消息撤回、会话置顶、免打扰、收藏变更、群资料变更。第三类信令类事件进入实时通话或会议流程例如语音邀请、视频邀请、会议创建、成员加入、成员离开、挂断。客户端收到事件后应该先判断 eventType再决定更新哪个本地模块。MESSAGE_* - 聊天窗口 STATE_* - 会话状态或本地缓存 SIGNAL_* - 通话与会议流程 CONTENT_* - 朋友圈或通知入口这种分流可以避免一个问题所有后端事件都被当成聊天气泡。如果撤回、已读、收藏、群资料更新、会议状态都以普通消息方式渲染聊天列表会越来越混乱客户端逻辑也会越来越难维护。一次文件收藏如何穿过事件系统以“用户收藏一条群聊文件消息”为例后端可以按事件链处理MESSAGE_SEND 文件消息进入会话 消息体引用 resourceId STATE_FAVORITE_ADD 收藏 messageId 或 resourceId RESOURCE_REF_UPDATED 文件资源引用计数变化 STATE_SYNC_PUSH 推送收藏变更到其他在线端 EVENT_LOG_CREATED 记录本次收藏操作这里不需要复制文件内容也不需要把收藏数据写回消息表。消息表负责聊天记录。资源表负责文件元数据。收藏表负责对象引用。事件流负责状态同步。这样后期即使文件消息被删除系统也能根据引用关系判断资源是否仍被收藏使用。一次多人会议邀请如何穿过事件系统多人会议也可以按事件处理而不是当成普通文本消息。SIGNAL_MEETING_CREATE 创建会议房间 SIGNAL_MEETING_INVITE 邀请成员加入会议 STATE_NOTIFY_PUSH 推送到在线端 SIGNAL_MEETING_JOIN 成员加入会议 SIGNAL_MEETING_LEAVE 成员离开会议IM 通道只处理信令媒体流不进入 WebSocket 消息链路。这样语音通话、视频通话、多人会议都可以复用信令事件模型。聊天系统不需要承载音视频流只需要维护呼叫状态、房间状态和成员状态。红包状态不要直接塞进聊天消息红包在聊天窗口中可以展示为一种卡片但红包金额和钱包流水不应该依赖消息表。事件链可以这样拆MESSAGE_SEND 会话中展示红包卡片 WALLET_RED_PACKET_CREATED 创建红包单据 WALLET_RED_PACKET_RECEIVED 用户领取红包 WALLET_LEDGER_CREATED 写入钱包流水 STATE_RED_PACKET_SYNC 同步红包状态到多端聊天消息只保存红包 ID 和展示摘要。红包模块保存金额、数量、剩余状态。钱包模块保存余额变化和流水。事件系统负责把这些动作串起来但不让资金数据污染消息主表。事件驱动架构需要关注这些细节事件驱动不是把所有逻辑都异步化也不是把所有业务都塞进队列。即时通讯源码里使用事件模型时需要注意几个工程细节事件 ID 必须唯一 traceId 必须贯穿同步和异步链路 事件处理器必须幂等 核心链路不能被异步任务阻塞 状态事件不能全部渲染成聊天消息 Redis Stream 消费失败需要重试策略 事件日志要能按 userId 和 conversationId 查询 消息表不要承担文件、钱包、朋友圈的全部状态 客户端要按事件类型分流处理这里最容易忽略的是幂等。Redis Stream 中的事件可能因为重试被消费多次。如果处理器没有幂等控制就可能出现重复刷新、重复通知、重复写日志甚至重复产生业务结果。因此事件处理器需要根据 eventId 或业务唯一键判断是否已经处理过。目录结构也可以按事件边界组织即时通讯源码可以不按页面目录组织而按事件边界组织。im-gateway WebSocket 接入、协议解析、连接管理 im-event-core 事件模型、事件分发、事件日志 im-message 聊天消息、会话状态、已读回执 im-resource 文件、图片、语音、视频资源 im-wallet 红包、钱包、资金流水 im-content 朋友圈、评论、点赞 im-notify 多端推送、系统通知、状态事件 im-signal 语音视频、多人会议信令这样新增能力时代码落点会更清楚。新增一种消息类型进入 im-message。新增文件收藏关联 im-resource 和 im-notify。新增红包领取进入 im-wallet。新增朋友圈评论提醒进入 im-content 和 im-notify。新增多人会议邀请进入 im-signal。不同业务通过事件连接而不是互相直接调用一堆内部方法。事件模型让即时通讯源码从接口堆叠变成链路编排即时通讯系统不是普通 CRUD 系统。它的复杂度来自实时连接、会话状态、多端同步和业务扩展之间的叠加。如果所有能力都写进 WebSocket 消息入口代码会越来越重。如果所有状态都写进消息表数据会越来越混乱。如果所有下发都当成聊天消息客户端渲染会越来越复杂。事件驱动架构的价值是把不同类型的变化分开聊天消息走消息链路。已读撤回走状态链路。文件收藏走资源链路。红包钱包走资金链路。朋友圈互动走内容链路。语音视频和多人会议走信令链路。Redis Stream 承接异步扩散MySQL 记录关键状态和事件日志WebSocket 只负责实时事件下发客户端按事件类型更新对应页面。对于 SpringBoot 即时通讯源码来说这种结构能让单聊、群聊、文件、收藏、朋友圈、红包、语音视频、多人会议这些能力自然接入而不是不断堆到同一个消息发送方法里。相关概念的资料整理笔记宠友(IM即时通讯)app,支持语音、文件、图片、视频等多种类型消息的发送,安全可靠,交流轻松,私有化部署,快速开发极简部署支持群聊管理、语音视频通话...功能https://chongyou.info/1/product/im.html
RELATED

相关推荐

JDK 16 ZGC 并发线程栈处理:实测GC暂停时间降低至1毫秒以下

JDK 16 ZGC 并发线程栈处理:实测GC暂停时间降低至1毫秒以下

JDK 16 ZGC并发线程栈处理:如何实现亚毫秒级GC暂停的实战解析当你的Java应用需要处理每秒数十万次请求时,垃圾回收(GC)暂停带来的延迟可能成为系统瓶颈。JDK 16中的ZGC通过JEP 376引入的并发线程栈处理技术,将GC暂停时…

📅 2026/8/22 20:32:46
数据集成+智能化应用,人力资源系统革新新方向!

数据集成+智能化应用,人力资源系统革新新方向!

一、引言在当今竞争激烈的商业环境中,企业的人才管理效能对于其发展至关重要。而人力资源系统作为企业管理人才的重要工具,其革新对于提升人才管理效能具有重要意义。二、传统人力资源系统的痛点1. 功能有限:传统人力资源系统往往只具备基本的…

📅 2026/8/22 20:32:47
单臂机器人如何学会双臂协同操作

单臂机器人如何学会双臂协同操作

1. 项目概述:当单臂机器人开始“学着用两只手”做事“MonoDuo”这个名字乍一听有点拗口,但拆开看就特别直白——Mono是“单”的意思,Duo是“双”,合起来就是“单臂变双臂”。它不是给机器人硬装上第二条机械臂,而是让一…

📅 2026/8/22 20:32:47
MORE NEWS

更多资讯

📰

问卷收回来了然后呢?书匠策AI把数据分析变成了“翻译题”

官网:www.shujiangce.com | 微信 公众号 :书匠策AI 别让数据在Excel里躺着过年,你需要一个能把数字“翻译”成论文的人。 你好,我是你们的老朋友,专注论文写作科普的教育博主。 今天聊一个让无数论文党血压飙升的…

📰

问卷设计的“降维打击”:当书匠策AI把“猜题”变成“搭积木”

官网:www.shujiangce.com | 微信 公众号 :书匠策AI 各位科研路上的同行者,大家好。 我是你们熟悉的教育测评博主,专注论文写作科普。 今天想跟你聊一个几乎所有社科、教育、经管研究者都绕不开的话题——问卷设计。顺便安…

📰

课程论文还在“硬写”?书匠策AI把这件事拆成了四步,每一步都在替你省时间

官网:www.shujiangce.com | 微信 公众号 :书匠策AI 你不是写不好论文,你只是用错了顺序——先搞定内容,再搞定形式,别边写边改 先问一个很现实的问题:你写一篇课程论文,从打开Word到提交&a…

📰

Agentic Edge AI落地实战:边缘智能体与模型量化部署全解析

最近圈子里聊“Agentic Edge AI”的人越来越多,但大部分讨论还是概念层面的,真正能把“智能体”和“边缘端”揉到一起落地的团队并不多。我前阵子刚好在一个工业视觉检测项目里把整套链路跑通了,从模型选型、量化部署到Agent行为逻辑的裁剪都…

📰

Cursor太贵?实测五大平替方案,免费与低价AI编程工具怎么选

去年这个时候,我还在跟朋友安利 Cursor,说它是"用了就回不去"的 AI 编程工具。结果今年轮到我自己被现实锤了一顿:订阅费涨了、免费额度15分钟见底、出个差换个电脑还弹个账号设备限制。更要命的是,团队里几个小伙伴也跑…

📰

智慧景区边缘计算落地实践:架构设计、算力选型与多业态数据融合

去年年中,我接手了一个智慧景区项目,主题就是“边缘计算与多业态融合”。一开始我觉得这名字有点大——景区嘛,无非就是闸机、广播、监控、停车,拢共也就那么几个系统。可真等方案评审和现场部署跑下来,我才意识到&…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬