一条消息从按下发送到对方看到,中间经过的环节比大多数人想的多。用户感知到的是「点一下就到了」,系统里走的却是六段以上:发送端把消息交出去、通过长连接上行、服务端校验与路由、在线实时推送或离线暂存、接收端回执、落库并同步到该账号的其他终端。
这几段里任何一段变慢或中断,表现出来往往都是同一句话——「消息怎么没收着」。把这条链路拆开,很多困扰团队的现象就能对号入座。下面描述的是这类系统的常见实现,不同产品的具体做法会有差异。
先确定一条消息要经过哪些环节
企业内部的沟通软件不管界面怎么做,结构上通常分三层。
| 层 | 负责什么 | 直接影响 |
|---|---|---|
| 客户端 | 输入与呈现消息、本地缓存、通知提醒 | 打开速度、消息是否即时弹出、历史记录能否查到 |
| 消息中转与接入服务端 | 维持连接、记录在线状态、把消息路由到正确的收件端 | 消息能否及时送到、断网后能否自动恢复 |
| 存储与同步层 | 消息落库、离线消息暂存、历史检索、多端一致 | 消息会不会丢、换设备能否看到、事后能否追溯 |
三层各管一段体验,哪一层做得薄,问题就会从那一层冒出来。以喧喧IM为例,它采用的就是这种三层结构:服务端基于 PHP 与 MySQL,承担数据存储与管理接口;消息中转服务器用 Go 实现,负责高并发通信与文件管理;客户端基于 Electron 构建,提供跨平台界面。
把三层串起来,一条消息的完整路径可以写成一行:
发送端 → 长连接上行 → 服务端校验与路由 → 在线实时推送 / 离线暂存 → 接收端回执 → 落库并同步到其他终端
和邮件这类异步通讯相比,最核心的差别是多了一张在线状态表。邮件是存储转发,发出去就算完成,不关心收件人在不在线;内部沟通软件在用户登录时就记下这个账号当前在哪个终端、连在哪个节点上,发消息时先查这张表,在线走实时通道,不在线进离线队列。
| 环节 | 谁在负责 | 出问题时最直观的表现 |
|---|---|---|
| 消息提交 | 客户端 | 消息卡在「发送中」,重试后对方收到两条 |
| 上行传输 | 长连接通道 | 网络切换后一段时间收不到新消息 |
| 校验与路由 | 消息中转服务端 | 提示发送失败,或投递到错误的会话 |
| 投递与回执 | 接收端与中转服务端 | 显示已发出,对方却说没看到 |
| 落库与同步 | 存储与同步层 | 换设备后历史缺失、多端已读状态不一致 |
第一段:客户端先把消息交出去
点下发送,客户端通常不会直接把内容丢进网络,而是先在本地留一条记录,状态标为「发送中」,同时给这条消息生成一个编号,打上时间戳。这个编号由发送端自己生成,是后面所有确认与去重的基础。
为什么不让服务端统一分配编号? 因为消息可能在传输中丢失或超时,客户端需要重试。重试时编号保持不变,服务端据此判断「这条我已经处理过了」,避免同一段内容被存两遍。
消息类型不同,这一步的工作量差别很大。纯文本只有几 KB,一帧就发完了;图片和文件一般先上传到文件服务,拿到一个文件引用,再发一条指向该引用的消息,避免大文件挤占长连接,把后面所有人的消息一起堵住。喧喧IM 的 即时聊天能力覆盖单聊、群聊与文件传输,这些能力最终都要落到这一段能交给链路多少种内容上。
这一段做得顺不顺,用户平时感觉不到;一旦出问题,表现就是消息重复,或者点了发送没有任何反馈。
第二段:长连接为什么必须一直连着
如果客户端靠「每隔几秒问一次服务器有没有新消息」,延迟和服务器压力都不可接受:几万人在线就是每秒成千上万次空请求,而收件人还得等到下一次询问才能拿到消息。
所以内部沟通软件几乎都用长连接:客户端登录后与服务器建立一条持续通道,之后谁有数据谁就发,不需要每次都重新握手。代价是这条通道本身需要维护——客户端定时发送心跳,服务端凭心跳判断连接是否还活着。心跳间隔太长,断线了系统还不知道;太短,又白增负担,所以多数实现会按网络类型动态调整。
网络抖动,或者从 WiFi 切到移动网络时,连接会断,客户端按递增的间隔重连,比如 1 秒、2 秒、4 秒逐步拉长,避免一断网就密集重试。
用户感受到的「消息慢了半拍」,很多时候是这条连接正在重建,而不是消息本身在路上走得慢。
第三段:服务端怎么找到收件人
消息到达服务端后,第一件事是校验:发送方身份是否有效、有没有权限往这个会话发内容。校验通过,才进入路由。
路由的依据就是那张在线状态表:账号、终端类型、当前所在节点、设备标识。收件人在线,消息直接推到他所在节点的那条长连接上;不在线,转入离线队列。
群消息比单聊复杂一层。一条消息要送到几百个人手里,如果对每个成员各写一份,成员越多写入量越大,服务端很快会被放大后的写入压住。常见做法是按群规模分开处理:小群直接把消息投递到每个成员的收件箱,大群只保留一份消息,由接收方按需聚合读取。
同一套系统里,单聊和大群走不同的投递策略,这是群规模上台阶之后才需要关心的问题。
第四段:回执、去重与顺序
「发出去了」和「对方收到了」是两件事。数据传到服务器,只说明网络这一段走通了,还需要应用层补两道确认:服务端收到消息后给发送端回执,接收端收到后给服务端回执。
回执会丢,所以要有重推:接收端没有回执,服务端隔一段时间再推一次。重推又带来重复,于是又回到上一段提到的消息编号——接收端按编号去重,同一条内容只渲染一次。
顺序问题同样在这一层解决。客户端的本地时间不可信,多台设备同时发消息时更加不可信,所以消息顺序通常由服务端分配的递增序号决定。
还有一个容易误解的地方是消息状态。气泡上的「发送中」「已送达」「已读」是三个不同层级的确认:前两个由客户端和服务端完成,第三个依赖用户真的打开了会话。 已读回执的技术含义是「这条消息进入了用户的可见区域」,不等于对方认真读过内容。
第五段:收件人不在线时,消息去哪了
接收方离线时,消息暂存在服务端,等他上线后补发。这里有两个常被忽略的细节。
一是保留策略。离线消息不可能无限期堆着,多数系统会设一个保留窗口,超期的会话只提示未读数量,不再全量下发,否则长时间离线的人一上线,加载会非常慢。
二是多端同步。同一个账号可能同时挂在办公电脑、手机和网页端,服务端要把消息推给所有在线终端,还要把已读状态回传对齐,让几端看到的状态一致。新设备首次登录能不能拉到完整历史,同样取决于这一层。多端消息漫游和离线消息推送需要客户端与服务端两侧配合,喧喧IM 的 移动办公能力覆盖的正是这一类场景。
移动端还有一个额外的兜底。系统在后台清理进程时会顺带掐断长连接,这时推送通道承担的角色通常是「把客户端叫醒、重建连接」,业务消息仍然走自己那条长连接,格式与加密策略才能保持一致。
第六段:链路上的加密与控制点
看完整条链路,加密发生在哪一层就清楚了。链路里至少要区分三处:客户端到服务端的传输、服务端上的文件、落进数据库的消息。三处各自的处理方式不一定相同,问供应商时最好分开问,避免只换回一句笼统的「我们有加密」。
喧喧IM 的公开口径是: 传输与服务端文件采用 AES 256 位加密,消息在数据库中加密存储。 除了传输与存储本身,访问侧还有一组控制点,例如界面水印、IP 登录限制、LDAP 认证、组织隔离,这些 通讯安全能力在不同版本中的开放程度不一样,评估时要按实际版本核对,别默认所有版本一致。
部署形态决定了这条链路归谁。 私有化部署把服务端、消息中转和存储都放进企业自己的服务器,链路不再经过外部服务商的设备。官网给出两种常见网络环境:一种是有公网 IP 的服务器,客户端通过公网访问;另一种是企业只允许内网访问、服务器不连外网,所有客户端只在企业内网通信。后一种在研发、生产和政务环境里更常见。
链路归属改变的不是功能清单,而是数据经过谁、存在哪、谁能看。
代价也要算清。服务端搬回内部,服务器和运维由企业自己承担。官方给出的参考标准是:服务端与消息中转服务器各按 16G 内存、8 核以上 CPU 准备,音视频服务器 8 核以上、建议带宽 8Mbps 以上,这套配置的参考范围是 5000 人以下。如果企业用的是国产软硬件环境,还要看系统适配,喧喧IM 适配的操作系统包括银河麒麟、统信 UOS、Deepin,CPU 侧覆盖申威、麒麟、兆芯、鲲鹏、海光、飞腾、海思盘古、龙芯。
常见异常对应到哪一环
把现象按链路对号入座,排查方向会清楚很多。
| 现象 | 大概率卡在哪一环 | 可以先查什么 |
|---|---|---|
| 消息延迟几十秒才到 | 上行传输,连接重建中 | 网络是否刚切换、客户端是否处于后台被限制 |
| 发送方显示成功,对方说没看到 | 投递与回执 | 接收端在线状态是否判断滞后、是否多端登录 |
| 同一条消息出现两次 | 去重 | 消息编号是否由发送端生成、接收端去重窗口是否过短 |
| 手机和电脑上的消息不一致 | 多端同步 | 已读状态是否回传、历史拉取是否完整 |
| 群消息明显比单聊慢 | 路由与扇出 | 群规模、投递策略、成员在线比例 |
| 换新设备后找不到历史 | 存储与同步 | 历史拉取范围、本地缓存与保留策略 |
评估团队内部沟通软件时可以问的问题
把上面几节换成问法,可以直接用在内部评审或供应商沟通里。
- 断网或切换网络后,连接多久能恢复? 关注是否有心跳与递增重连策略,弱网下表现如何。
- 离线消息保留多久,补发是否完整? 问清保留窗口、超期处理方式,以及多端能否补齐。
- 多端同步同步的是什么? 只同步消息,还是已读状态和历史也同步;新设备首次登录能不能拉到完整历史。
- 数据存在哪,加密分几层? 把传输、服务端文件、数据库消息分开问。
- 能不能对接现有系统,消息能否检索留痕? 这决定消息能否驱动业务流程,以及事后能否追溯。喧喧IM 提供 API、WebHook 与机器人机制,具体接口和扩展方式可以从 二次开发手册入手核对。
这五个问题对方答得清楚,说明他对自己系统的链路有把握;答得含糊,功能演示再漂亮也要谨慎。

2286
联系我们
社群交流