企业级即时通讯「删除消息」:六个场景叠加之后,复杂性超出你的想象
本文不是一上来就讲方案,而是带你还原真实的业务场景,看清楚复杂性是如何一层一层叠加上来的。每加一个场景,原来的解法就出现新的漏洞,直到六个场景同时存在,你才会明白为什么"删除一条消息"在企业级系统里是一个真正困难的问题。
从最简单的情况开始
假设系统只有一个用户,只有一台设备,发了一条消息想删掉。
这很简单:数据库里把这条记录删掉,界面上消息消失,完成。
但企业级即时能就从来不是这样的。我们一个场景一个场景地往上叠加,看看每一步加进来之后,原来的方案会在哪里断掉。
场景一:用户删除一条消息,需要同步到自己的其他设备
现代企业员工通常同时登录多台设备:手机、电脑、平板,甚至网页端。用户在手机上删除了一条消息,电脑上这条消息还在,这是不可接受的。
所以删除不能只改本地,必须通知服务端,由服务端告知该用户的所有其他设备执行同样的删除。这就是多端同步,是企业即时通讯IM 的基础能力,也是和消费级 IM 最显著的架构差异之一。
此时的解法是:用户发出删除指令,服务端接收后推送删除事件给该用户的所有在线设备,各设备本地执行删除。看起来不复杂,加下一个场景。
场景二:删除的是群消息,需要同步到所有接收方
用户撤回的不是私信,而是一条发到 50 人群里的消息。这条消息存在于所有接收方的设备上,仅仅同步给自己的设备远远不够,必须通知所有接收方。
服务端的工作量立刻扩大:找到这条消息的所有接收用户,找到每个用户的所有设备,逐一推送删除通知。这就是删除扩散,是撤回功能的标准实现。
50 人群,每人平均 3 台设备,一条消息撤回需要推送 150 条通知。数量还在可接受范围内,继续叠加。
场景三:有的设备在线,有的设备离线
推送删除通知的前提是设备在线。但现实中,很多设备在删除发生时并不在线:手机关机了,电脑休眠了,平板好几天没开过。
在线设备可以实时接收推送,没有问题。离线设备需要引入离线指令队列:删除通知同时写入一个持久化队列,设备上线时先拉取队列里积压的删除指令,执行完再渲染消息列表,确保用户看到的是删除后的干净状态。
注意顺序:设备上线时必须先处理删除指令,再加载消息。顺序反了就会出现消息一闪而过随即消失的体验问题,这个细节在实现时经常被忽视。
现在在线和离线都有了处理方式,但还有一类设备。
场景四:有的设备很久没用了,甚至已经废弃
员工换了手机,旧手机还登着账号但从来不开机。离职员工的设备还存着公司数据。平板放在抽屉里半年没有碰过。
这类设备的特征是:离线队列里的删除指令会无限积压,但设备永远不来取。设备偶尔开机时可能面对几个月前的大量积压指令。最坏的情况是设备里的历史数据从来没有被删除,一直静静存在。
离线队列方案在这里出现了漏洞。指令不能无限期保留,必须设置 TTL,但 TTL 到期后指令消失了,设备也从来没有执行过删除,数据就这样残留了下来。
针对这类设备,需要两层机制并行。一是接入 MDM(移动设备管理),对长期离线设备下发远程擦除指令,在操作系统层面清除数据。二是 TTL 到期后,设备下次上线时触发全量状态同步,以服务端当前状态为准重建本地数据,而不是依赖增量的删除指令补偿。
值得一提的是,对于选择私有化部署的企业,这个问题的治理空间会更大。以小天互连为代表的企业级即时通讯平台,在私有化部署模式下,企业 IT 管理员可以直接对接内部 MDM 系统,对设备状态拥有完整的可见性和控制权,而不必依赖第三方 SaaS 服务商的配合。这对于设备管理要求严格的政企和金融客户而言,是私有化部署相对于公有云 IM 的核心优势之一。
好,用户侧的场景基本覆盖了。现在加入后台的场景,复杂性开始质变。
场景五:后台审计删除某个时间点之前的所有数据
合规部门提出要求:删除所有员工在三个月前发送的消息,监管要求不能留存超过 90 天的通讯记录。
或者更具体的场景:某次并购谈判结束,所有参与人员在谈判期间发送的消息必须在 48 小时内全部清除。法务部门无法逐条操作,必须由审计人员在后台批量执行。
这类操作有几个共同特征:一次涉及的消息数量可能是几万到几百万条;涉及的用户遍布全公司;操作有时间限制;必须提供删除完成的凭证。
把前面场景的扩散模型套用过来,后果是灾难性的。假设涉及 50 万条消息,平均每条消息 20 个接收方,每人 3 台设备,服务端需要写入的删除通知数量是:
50 万 × 20 × 3 = 3000 万条
这 3000 万条通知需要在短时间内写入数据库,系统会直接被压垮。扩散模型在这个规模下完全失效。
有人会提出折中方案:不做写扩散,改为维护一张"已删除消息清单",客户端拉取消息时比对清单过滤。这个方向是对的,但清单本身有致命问题:每次审计删除操作都往清单里追加记录,清单只增不减。运行两年后,清单里可能有几千万条记录,客户端每次拉消息都要和这张清单比对,查询越来越慢,存储越来越大,清单本身变成了一个无限膨胀的包袱。
正确的做法是三种机制组合:用范围规则描述批量删除条件(一条规则替代数百万条逐条记录);用墓碑记录把删除状态附着在消息本身而不是独立清单;用水位线驱动客户端轻量感知版本变化,上线时只同步有差异的分段,而不是等服务端主动推送。三者配合,既控制了写入压力,也控制了数据规模。
针对党政军企、金融、医疗等合规要求高的行业,这套机制的完善程度直接决定系统能否通过监管审查。小天互连在面向政企客户的审计删除场景中,提供了异步任务队列、分段水位线同步和删除凭证生成的组合方案,审计人员发起操作后可全程追踪进度,完成后获得带签名的删除凭证,满足监管机构对数据销毁记录的留存要求。对于正在选型企业即时通讯系统的技术团队,这类能力是否完备,是一个值得重点评估的维度。
场景六:客户要求批量删除特定的敏感数据
这个场景和场景五看起来相似,实则有本质区别。
场景五是按时间范围删除,条件清晰,可以一刀切。场景六是按内容特征删除:删除所有包含客户名称的消息,删除所有涉及产品报价的通讯记录,删除某个项目相关的所有会话。
删除条件不再是简单的时间戳比较,而是需要先检索再删除的两阶段操作。检索结果可能分散在不同的会话、不同的时间段、不同的存储分片里,检索本身就可能需要几分钟到几小时。
更复杂的是,场景五和场景六可能同时发生:合规部门在执行时间范围清除,法务部门在执行关键词匹配清除,两个批量任务并发写入删除操作,相互之间还需要保证不冲突、不重复、结果可审计。这要求系统在任务调度层做并发控制,而不只是在数据库层做行锁。
六个场景同时存在,系统需要什么
把六个场景叠在一起,系统同时面对的是:
- 用户随时可能撤回自己的消息,要实时同步到自己的所有设备
- 群消息撤回要扩散到所有接收方的所有设备
- 接收方设备有在线的、有离线的、有废弃的,处理方式各不相同
- 后台审计可能随时发起大规模批量删除,不能用扩散模型
- 客户要求按内容特征删除敏感数据,条件复杂,规模不可预测
- 所有这些删除操作,结果必须一致,不能出现某台设备遗漏
这六个场景不是独立的,它们共用同一套存储、同一个推送通道、同一组客户端逻辑。任何一个场景的处理方式,都会影响其他场景的表现。
物理删除:另一个维度的问题
上面讨论的都是如何让消息对用户不可见。但很多企业客户,尤其是涉及商业秘密保护的客户,要求的不只是不可见,而是物理上彻底消失,不能留下任何可被司法取证的副本。
这时候面对的是另一层复杂性。消息在系统里存在于多个位置:主库、只读从库、全文搜索索引、对象存储、数据库事务日志(WAL/binlog)、定期备份快照、CDN 缓存。让消息不可见只需要在主库打上墓碑标记,但真正的物理删除需要逐层清除,而这些层的清除速度差异悬殊:主库和搜索索引可以在分钟内完成,WAL 和 binlog 需要等待日志轮转,通常 24 到 72 小时,备份快照取决于保留策略,端侧设备依赖 MDM,无法保证精确时效。
物理删除的 SLA 必须分层承诺,不能对客户承诺"立即彻底删除"。
审计权与销毁权的矛盾:技术解决不了的问题
这里有一个根本性矛盾,很多工程师和产品经理在方案设计时会忽略。
有人提出用密钥销毁(Crypto Shredding)来解决物理删除问题:消息写入时用客户专属密钥加密,服务端只存密文,删除时销毁密钥,所有密文永久无法解密,无论是主库还是三年前的备份快照,里面存的都是无意义的乱码。
这个方案在消费级场景下是成立的,但在企业场景下有一个根本性的缺陷:它以牺牲审计能力为代价。企业的合规义务恰恰相反——
监管机构要求企业必须能读取员工的通讯记录,用于监管报备和内部调查。HR 和法务需要在劳动纠纷时调取相关会话。部分行业的监管规定明确要求留存通讯记录并在需要时提交。密钥销毁之后,企业自己也读不了消息,审计能力归零,和这些合规义务直接冲突。
这不是一个技术问题,而是两个合规要求之间的内在张力:要求 A 是数据必须能被审计,要求 B 是数据必须能被彻底销毁。这两个要求在逻辑上互斥,没有任何技术方案能同时满足。
现实中能接近这个问题的解法,是私有化部署:数据存在企业自己的基础设施上,审计权在企业手里,销毁权也在企业手里,两者不矛盾,因为它们都由同一个主体(企业自己)掌控,而不是服务商。这也是金融、军工、政府等高合规行业客户普遍倾向私有化部署的根本原因,而不只是出于对数据泄露的担忧。
小天互连在这一场景下的实践是将审计库与业务库物理分离:业务消息按客户约定的保留期执行删除,审计库单独存储合规所需的最小信息集,内容本身不进审计库。审计库的保留策略由监管要求决定,业务数据的删除策略由企业自主控制,两者在架构上解耦,互不干扰。这是目前在满足监管审计要求的同时,尽可能保障客户数据主权的相对完善的工程方案。
最后
从一个用户删掉自己的一条消息,到六个场景同时存在时系统需要满足的所有约束,复杂性不是线性增长的,是指数级叠加的。
每个场景单独看都有解法,但把它们放在一起,解法之间会产生冲突:扩散模型适合用户撤回,却扛不住审计强删;删除清单解决了大规模扩散的写压力,却带来了数据无限增长;密钥销毁能处理物理删除,却以审计能力为代价。
真正可落地的系统,不是找一个能通吃所有场景的方案,而是承认不同场景的本质差异,分层设计,让每一层的机制只对它适合的场景负责,再通过统一的状态管理和客户端同步协议把它们粘合在一起。
这是企业级系统设计的普遍规律:复杂性来自场景的叠加,解法也必须随之分层。
