4.2 KiB
4.2 KiB
IM 系统消息存储与推送策略文档
1. 概述
本策略文档定义了 消息在系统中的存储、读取和推送流程,目标是:
- 保证 消息实时性
- 支持 离线消息存储与同步
- 支持 多端登录同步
- 支持 单聊、群聊及系统消息
2. 消息存储策略
2.1 消息表设计
表结构参考前期设计:
| 表名 | 作用 |
|---|---|
| Messages | 存储所有聊天消息(单聊/群聊) |
| Conversation | 缓存用户最近会话信息(last_message_id, target_id, unread_count) |
| Files | 附件 / 图片 / 语音存储URL |
2.2 消息存储规则
- 单聊消息
- 写入
Messages表 - 更新发送者和接收者
Conversation表 - 更新
UnreadCount
- 写入
- 群聊消息
- 写入
Messages表 - 更新群成员对应的
Conversation表(except 发送者) - 更新每个成员的
UnreadCount
- 写入
- 文件消息
- 文件存储到对象存储(OSS/S3/MinIO)
Messages.Content存文件 URL + metadata
- 消息撤回
- 消息允许撤回时,修改 `message.status = 1
- 更新
Conversation.LastMessageId(如撤回的是最后一条消息)
3. 消息推送策略
3.1 推送原则
- 实时性:在线用户立即通过 WebSocket 推送
- 可靠性:离线用户存储消息,登录时同步
- 顺序保证:消息按
timestamp或messageId顺序发送 - 幂等性:客户端可根据
messageId去重
3.2 单聊推送流程
- 发送者通过 WebSocket 或 HTTP API 发送消息
- 服务端写入
Messages表 - 查询接收者是否在线
- 在线:通过 WebSocket 推送
- 离线:存储到 Redis 或
Conversation.UnreadCount
- 接收者收到消息后发送
MESSAGE_ACK - //暂不要求:更新消息状态(已送达 / 已读)
3.3 群聊推送流程
- 发送者发送群消息
- 服务端写入
Messages 表 - 查询群成员列表(
GroupMember表) - 遍历成员:
- 在线成员:WebSocket 推送
- 离线成员:增加
UnreadCount,保存在 Redis/数据库
- //暂不要求:接收者回 ACK 后更新
message_receipt(已读)
3.4 离线消息处理
- 离线消息存储位置:
- 数据库
Messages表(长期保存) - Redis 缓存(短期加速推送)
- 数据库
- 客户端上线时:
- 请求
/syncMessages接口 - 返回未读消息 + 未读计数
- 请求
- 消息同步完成后清除缓存或更新状态
3.5 多端同步策略
- 每个设备维护独立的
deviceId - WebSocket 推送时:
- 排除发送设备
- 推送给同账号其他设备
- //暂不要求:消息回执:
- 每端发送 ACK
- 服务端更新
Voncers和message_receipt
4. 消息可靠性保障
| 场景 | 解决方案 |
|---|---|
| 消息丢失 | 发送端生成 requestId,服务端去重 |
| 消息顺序错乱 | 按 messageId 或 timestamp 排序 |
| WebSocket 异常断开 | 客户端重连后同步离线消息 |
| 群聊大消息量 | 异步推送 + 批量 ACK |
5. //暂不要求:高性能优化策略
- 消息表索引:
(chat_type, to_id, created_at) - 会话表缓存:
conversation表避免全表查询 - Redis 缓存:用户在线状态、未读消息数
- 分表/分库:按月或按用户分表
- 异步推送队列:消息通过 MQ(Kafka/RabbitMQ)推送,保证高并发
6. 消息撤回与删除策略
- 撤回条件:超时限制( 2 分钟内可撤回)
- 撤回操作:
- 更新
message.status = 1 - 更新
Conversation.LastMessageId - 推送撤回事件到在线用户
- 更新
7. 系统消息与通知策略
- 系统消息(好友申请、群邀请、公告)走 同样的消息推送流程
- 保留在
Notification表 - 支持离线同步