feat: batch kafka message persistence

This commit is contained in:
richjohnrambo
2026-09-24 22:45:07 +08:00
parent 7f2df1dd4f
commit f898a7171c
18 changed files with 682 additions and 98 deletions
+12 -4
View File
@@ -724,11 +724,19 @@ IM Server 已接入 `im.message.persist`,用于把在线发送链路和最终
1. WS/HTTP 发送入口先完成权限校验,并由 topic 内存态分配 `seq_id`。
2. Kafka 开启时,私聊发送入口直接生产 `im.message.persist`,群聊发送入口直接生产 `im.group.message.persist`,不查库、不落库、不写 DB outbox;客户端在 Kafka 写入成功后拿到已分配的 `seq_id`。
3. Kafka 关闭时,继续走原同步落库路径,兼容本地和未接 Kafka 环境。
4. 消费者按 `message_kind` 区分私聊与群聊:
- `p2p` 写入 `im_messages`。
- `group` 写入 `im_group_messages`。
4. 私聊和群聊使用独立 Topic、独立消费组和独立物理表:私聊批量写入租户分表 `im_%03d_messages`,群聊按租户和月份批量写入 `im_%03d_group_messages_YYYYMM`。
5. 消费侧复用 `im_kafka_consume_log` 做 `event_id + consumer_group` 幂等。
6. 失败按统一退避重试 3 次,超过上限先投递 `im.dead.letter`,再由 dead letter consumer 写入 `im_kafka_dead_letters`。
6. 消费者最多聚合 `message_batch_size` 条消息,在 `message_batch_wait_ms` 时间窗内形成批次并执行一条多值 `INSERT`。
7. 批量写入失败后逐条降级;每条执行首次写入和 `message_single_retry_count` 次重试,默认共尝试 4 次。
8. 单条仍失败时,完成 `im.dead.letter` 投递和 `im_kafka_dead_letters` 终态写入后才提交该批 offset;提交失败会持续重试,避免跳过失败消息。
消息批量落库参数:
| 配置项 | 默认值 | 说明 |
| --- | ---: | --- |
| `message_batch_size` | `100` | 单批最大消息数,上限 500。 |
| `message_batch_wait_ms` | `10` | 从取得第一条消息开始的批次聚合等待时间。 |
| `message_single_retry_count` | `3` | 批量失败后单条额外重试次数,不含首次执行。 |
### 11.10 IM Server 已接入的缓存失效消费
+15 -12
View File
@@ -545,27 +545,27 @@ Payload:
1. 用户 A 与用户 B 建立私聊。
2. A 发送带 `x-im-client-mid` 的私聊消息。
3. 查询 Kafka `im.message.persist`。
4. 查询租户库 `im_messages`。
4. 查询租户私聊分表 `im_%03d_messages`。
5. A 使用同一 `x-im-client-mid` 重复发送。
预期:
1. A 立即收到服务端 ack 和 `seq_id`。
2. `seq_id` 为 BIGINT/int64。
3. 消费成功后 `im_messages` 有一条记录。
3. 消费成功后对应租户私聊分表有一条记录。
4. 重复发送不重复落库。
5. 消费日志 succeeded。
### TC-KAFKA-014 群聊消息异步落库
目标:验证群消息写入 `im_group_messages`,不混入私聊表。
目标:验证群消息写入租户月度群消息分表,不混入私聊表。
步骤:
1. 创建群并加入至少两个成员。
2. 成员发送群消息。
3. 查询 `im_group_messages`。
4. 查询 `im_messages`。
3. 查询 `im_%03d_group_messages_YYYYMM`。
4. 查询 `im_%03d_messages`。
5. 重连客户端按 Topic seq 拉取消息。
预期:
@@ -574,24 +574,27 @@ Payload:
2. `seq_id` 单调增长,类型为 BIGINT/int64。
3. 客户端补偿拉取成功。
4. 24 小时热消息可进入 Redis 热缓存。
5. 私聊与群聊分别由 `im.message.persist`、`im.group.message.persist` 消费。
### TC-KAFKA-015 消息消费失败重试
目标:验证 `im.message.persist` 消费失败可重试并最终成功。
目标:验证私聊和群聊批量落库失败后均按“逐条降级、重试 3 次、死信后提交 offset”处理。
步骤:
1. 临时制造租户库写入失败,如锁表或停止库连接。
2. 发送消息。
3. 恢复数据库。
4. 等待重试。
2. 在批次窗口内连续发送多条私聊和群聊消息。
3. 恢复数据库,验证逐条重试可成功落库。
4. 再次持续制造单条失败直至超过重试次数。
5. 查询 `im_kafka_consume_log`、`im_kafka_dead_letters` 和 `im.dead.letter`。
预期:
1. `im_kafka_consume_log.retry_count` 增加。
2. 未超过重试上限时不进入死信。
3. 数据库恢复后消息最终落库。
4. 状态变为 succeeded。
2. 批量失败后降级为单条写入,每条最多执行 4 次(首次加 3 次重试)。
3. 未超过重试上限时不进入死信,数据库恢复后消息最终落库并标记 succeeded。
4. 持续失败的单条消息写入死信表并投递死信 Topic。
5. 只有批内全部消息达到 succeeded/dead 终态后才提交 offset,不能跳过失败消息。
### TC-KAFKA-016 文件上传完成事件