Files
im_server/docs/IM-Kafka接入方案.md
T

44 KiB
Raw Blame History

IM Kafka 接入方案

日期:2026-08-26
关联文档:IM Kafka 接入范围识别、IM 前后端逐图对接协议
目标:明确 Admin 后台、IM 服务、HotGo 控制库、租户业务库之间的 Kafka 接入边界、查询方式、鉴权方式和首批落地范围。

0. 与范围识别文档的关系

IM Kafka 接入范围识别 是本方案的前置输入,负责按前后端对接文档逐章识别哪些业务适合 Kafka、哪些仍应走 WebSocket/Redis/MySQL/OSS。本方案在该识别结果基础上,进一步确定服务边界、库访问边界、前后台交互模型、内部查询接口、鉴权方式和首批落地步骤。

两份文档分工如下:

文档 作用
IM Kafka 接入范围识别 回答“哪些业务该用 Kafka,哪些不该用”。
本方案 回答“Kafka 怎样接入,Admin 与 IM 怎样交互,服务和库怎样隔离”。

实施时以范围识别文档的逐章清单确定业务覆盖面,以本方案确定技术实现方式。若后续新增需求,先补充范围识别,再同步调整本方案的 Topic、Command、内部接口和鉴权规则。

1. 核心原则

系统按“服务和库一一对应”设计,不允许不同服务直连对方数据库。

服务 只能直接访问 说明
Admin/HotGo 服务 hotgo 控制库 管理后台、租户主数据、后台配置、审核、操作单。
IM 服务 当前租户业务库 用户、好友、群、消息、文件引用、工作台业务数据。
Redis IM 实时状态与缓存 在线状态、短状态、热点消息、缓存分层。
Kafka Admin 与 IM 的命令、事件、结果桥 后台写操作、异步任务、业务事件、审计、缓存失效。
OSS 文件对象存储 上传下载字节流不进入 Kafka。

最终边界:

  1. Admin 不直连租户库。
  2. IM 不直连 hotgo 库。
  3. Admin 写租户业务操作统一通过 Kafka Command。
  4. IM 写后台业务状态不直写 hotgo,通过 Kafka Result/Event 返回 Admin。
  5. Admin 查询租户业务数据通过 IM 内部只读 API。
  6. IM 查询租户配置、字典、路由通过 Admin 内部只读 API,或消费 Kafka 配置事件维护本地副本。
  7. 在线实时投递继续走 Redis + WebSocket,Kafka 不替代 WS 主链路。

2. 总体架构

Admin/HotGo 服务
  -> 写 hotgo 操作单
  -> 生产 Kafka Command
  -> IM 服务消费 Command
  -> 写租户业务库
  -> 生产 Kafka Result/Event
  -> Admin 消费 Result/Event
  -> 更新 hotgo 操作状态

Admin 查询租户业务数据
  -> 调 IM 内部只读 API
  -> IM 查租户业务库
  -> 返回 Admin

IM 查询租户配置/字典/路由
  -> 优先读本地缓存/本地副本
  -> 缓存缺失时调 Admin 内部只读配置 API
  -> Admin 查 hotgo
  -> 返回 IM

3. Kafka 使用范围

场景 是否使用 Kafka 说明
Admin 后台群操作通知 C 端 是 后台写 hotgo 操作单,投 Kafka,IM 执行租户库变更并 WS 下发。
Admin 后台用户封禁、解封、重置密码 是 IM 消费后更新租户库、踢在线、通知客户端。
Admin 后台租户配置、字典、功能开关变更 是 Admin 写 hotgo 后投配置事件,IM 刷新缓存或本地副本。
企业注册、实名、举报、反馈审核结果 是 Admin 审核后投 Kafka,IM 生成通知或更新租户侧状态。
工作台会议、日报、月报、信箱通知 是 状态变更、提醒、红点更新走 Kafka。
私聊/群聊消息异步落库 是 WS 收消息后完成鉴权、幂等和 seq,再投 Kafka 异步持久化。
文件安全检测、恶意文件检测 是 OSS 上传完成后投检测任务,消费者调用第三方并更新状态。
离线 Push 是 消息或业务事件落地后投 Push 任务。
在线消息实时 fanout 不作为主链路 继续 Redis Pub/Sub/Stream + WS。
文件上传下载字节流 否 走 OSS/文件服务;Kafka 只处理上传完成后的事件。
验证码、Action Token、限流、在线状态 否 继续 Redis。
普通查询接口 否 走内部只读 API 或本服务数据库。

4. 前后台交互模型

4.1 后台写租户业务

Admin 后台所有会影响租户业务库或 C 端展示的写操作,统一走 Kafka Command。

Admin
  1. 校验后台管理员权限
  2. 写 hotgo.admin_command,状态 pending
  3. 发送 Kafka command

IM
  4. 消费 command
  5. 校验租户、对象、版本、权限和幂等
  6. 写租户业务库
  7. 必要时通过 WS 通知在线 C 端
  8. 发送 Kafka result

Admin
  9. 消费 result
 10. 更新 hotgo.admin_command 状态

典型操作:

操作 Command IM 执行动作 C 端通知
群资料修改 group.profile.update 更新群表和 Topic 资料 group.profile.updated
设置/删除管理员 group.admin.set / group.admin.remove 更新成员角色 group.role.updated
禁言/解禁 group.member.mute / group.member.unmute 更新禁言表 group.mute.updated
踢人 group.member.remove 更新成员状态和订阅 group.member.removed
解散群 group.delete 解散 Topic、撤销权限 group.deleted
用户封禁 user.disable 更新用户状态、踢在线 user.disabled
重置密码 user.password.reset 更新密码和 auth_version 可选安全通知

4.2 后台查询租户业务

Kafka 不适合做普通查询。Admin 需要实时查看租户业务数据时,调用 IM 提供的内部只读 API。

只读 API 只允许 GET,不提供通用 SQL 或万能查询接口。

接口 用途
GET /internal/admin-query/tenants/{tenant_code}/users/{user_id} 查询租户用户详情。
GET /internal/admin-query/tenants/{tenant_code}/groups/{topic} 查询群详情。
GET /internal/admin-query/tenants/{tenant_code}/groups/{topic}/members 查询群成员。
GET /internal/admin-query/tenants/{tenant_code}/messages/{topic}/{seq} 查询消息受控快照。
GET /internal/admin-query/tenants/{tenant_code}/files/{file_id} 查询文件引用和审核状态。
GET /internal/admin-query/tenants/{tenant_code}/reports/abuse/{report_id}/target 查询举报目标快照。
GET /internal/admin-query/tenants/{tenant_code}/kafka/dead-letters 查询 IM 租户库 Kafka 死信列表。
GET /internal/admin-query/tenants/{tenant_code}/kafka/dead-letters/{dead_id} 查询单条死信详情和原始 envelope。

后台列表、统计、高频页面优先使用 hotgo 摘要表。摘要由 IM 通过 Kafka 事件同步给 Admin,Admin 查询自己的库。

推荐摘要表:

摘要表 来源
admin_im_user_snapshot IM 用户资料变更事件。
admin_im_group_snapshot IM 群资料、成员数、状态变更事件。
admin_im_group_member_stat 群成员统计事件。
admin_im_file_audit_snapshot 文件审核和引用状态事件。
admin_im_workbench_snapshot 工作台红点、会议、日报/月报状态事件。

4.3 IM 查询后台配置

IM 不直连 hotgo。IM 需要租户路由、租户状态、字典、第三方配置时,使用两种方式:

  1. 常态:Admin 修改配置后发送 Kafka 配置事件,IM 消费后更新进程内缓存或本地副本。
  2. 兜底:IM 缓存缺失或启动预热时,调用 Admin 内部只读配置 API。
接口 用途
GET /internal/im-config/tenants/{tenant_code} 查询租户状态、名称、路由标识。
GET /internal/im-config/tenants/{tenant_code}/limits 查询人数、群数、上传大小等限制。
GET /internal/im-config/tenants/{tenant_code}/features 查询功能开关。
GET /internal/im-config/dictionaries?types=oss,file_security,sms,jpush,agora 查询字典配置。
GET /internal/im-config/app/releases/latest 查询 App 版本配置。

Admin 内部配置 API 只返回 IM 运行需要的字段,不返回后台管理员账号、菜单权限、审核私有字段。

5. Topic 规划

Topic 用途
im.admin.command Admin 发给 IM 的租户业务写命令。
im.admin.command.result IM 回传命令执行结果。
im.config.event Admin 发给 IM 的配置、字典、租户状态变更。
im.business.event IM 内部或 Admin 触发的 C 端业务事件。
im.message.persist 私聊消息异步落库。
im.group.message.persist 群聊消息异步落库。
im.message.push 离线 Push 任务。
im.file.security 文件内容安全、恶意文件检测任务。
im.cache.invalidate 跨节点缓存失效。
im.audit.event IM 与 Admin/HotGo 的跨系统审计事件。
im.dead.letter 消费失败死信。

首版可合并部分 Topic,但事件体必须保留 biz_type 和 event_type,方便后续拆分。

6. 消息结构

统一 Kafka Envelope:

{
  "event_id": "evt_01K...",
  "trace_id": "req_01K...",
  "tenant_code": "default",
  "source_service": "hotgo-admin",
  "target_service": "im",
  "event_type": "group.member.mute",
  "biz_type": "group",
  "biz_id": "grp...",
  "idempotency_key": "idem_01K...",
  "version": 3,
  "occurred_at": "2026-08-26T10:00:00.000Z",
  "actor": {
    "type": "admin",
    "id": "admin_1",
    "display_name": "管理员"
  },
  "payload": {}
}

Command Result:

{
  "event_id": "evt_result_01K...",
  "trace_id": "req_01K...",
  "tenant_code": "default",
  "command_id": "cmd_01K...",
  "command_event_id": "evt_01K...",
  "status": "succeeded",
  "reason": "",
  "message": "",
  "result": {},
  "occurred_at": "2026-08-26T10:00:01.000Z"
}

失败时 status=failed,reason 使用稳定错误码,例如 GROUP_VERSION_CONFLICT、FORBIDDEN、RESOURCE_NOT_FOUND、COMMAND_DUPLICATED。

7. 幂等、事务与重试

7.1 生产端

Admin 写操作必须先落 hotgo.admin_command,再发送 Kafka。推荐使用 outbox 模式:

  1. 同一事务写 admin_command 和 admin_outbox。
  2. outbox poller 发送 Kafka。
  3. Kafka 发送成功后标记 outbox 已发送。
  4. 发送失败按退避重试。

IM 内部业务事件也按同样方式写租户库 outbox,避免“数据库成功、事件丢失”。

7.2 消费端

每个消费者维护消费幂等记录:

字段 说明
event_id Kafka 事件唯一 ID。
consumer_group 消费组。
status processing/succeeded/failed/dead。
retry_count 重试次数。
last_error 最近失败原因。
created_at/updated_at 时间。

消费前先插入或锁定 event_id + consumer_group。已成功的事件直接跳过;处理中超时可重新抢占。业务表必须再用唯一键兜底,例如 tenant + command_id、tenant + client_mid、tenant + topic + seq。

7.3 重试与死信

类型 策略
临时失败 指数退避重试。
版本冲突 不自动重试,回传 failed,由 Admin 刷新后重新发命令。
权限失败 不重试。
对象不存在 不重试,除非明确是延迟同步。
第三方失败 可重试,超过次数写死信和失败表。

7.4 消费失败处理流程

消费者收到消息后按固定流程处理:

收到 Kafka 消息
  -> 校验 Envelope 格式、签名字段、租户和事件类型
  -> 抢占 event_id + consumer_group 幂等记录
  -> 已 succeeded:提交 offset,跳过
  -> processing 超时:允许重新抢占
  -> 执行业务逻辑
  -> 成功:标记 succeeded,提交 offset
  -> 可重试失败:retry_count + 1,按退避策略延迟重试
  -> 超过最大重试:写入死信,标记 dead,提交 offset
  -> 不可重试失败:标记 failed 或 dead,必要时回传 command result,提交 offset

重试建议参数:

参数 建议值 说明
max_retry_count 5~10 第三方接口可取高值,权限/参数错误不重试。
retry_backoff 10s、30s、1m、5m、15m 指数退避,可加随机抖动。
processing_timeout 5m~30m 超过后允许其他消费者重新抢占。
dead_letter_retention 30~90 天 便于排障和人工补偿。

7.5 死信队列处理

进入死信表示该事件已超过自动恢复能力,系统不能再无限重试。死信必须形成“可查看、可诊断、可重放、可关闭”的闭环。

死信写入两处:

  1. Kafka im.dead.letter Topic:保留原始事件,便于流式订阅、告警和后续自动补偿。
  2. 数据库失败表:便于 Admin 后台查询、人工处理和审计。

推荐失败表字段:

字段 说明
dead_id 死信记录 ID。
event_id 原 Kafka 事件 ID。
source_topic 原 Topic。
consumer_group 失败消费组。
tenant_code 租户编码。
event_type 事件类型。
biz_type / biz_id 业务对象。
payload 原始 Envelope。
retry_count 已重试次数。
last_reason 稳定失败原因。
last_error 最近错误摘要,敏感字段脱敏。
status dead/pending_replay/replayed/ignored/resolved。
replay_count 人工重放次数。
created_at/updated_at 时间。
resolved_by/resolved_at 人工处理人和处理时间。
resolve_note 处理备注。

死信来源分类:

分类 示例 默认处理
临时资源失败超过上限 DB 短暂不可用、第三方超时 修复环境后允许重放。
业务状态冲突 群版本冲突、对象已被删除 不自动重放,Admin 刷新状态后重新发命令。
权限失败 管理员无权限、租户停用 不重放,标记 ignored 或 failed result。
参数错误 Envelope 缺字段、payload 非法 不重放,修复生产方后关闭。
第三方永久失败 文件违规、Push token 无效 按业务结果落状态,不重放或仅重放特定步骤。

Admin 后台需要提供死信处理页:

操作 说明
查看详情 展示事件、租户、业务对象、错误原因、重试次数和 trace_id。
重放 将原事件或修正后的事件重新投递到原 Topic,生成新的 event_id,保留 parent_event_id。
忽略 确认该事件无需继续处理,状态改为 ignored。
标记已处理 线下补偿完成后改为 resolved。
重新生成命令 对版本冲突类命令,不直接重放旧事件,而是基于最新状态创建新 Command。

重放规则:

  1. 重放必须生成新的 event_id,原 event_id 保留在 parent_event_id。
  2. 重放前重新校验租户状态、对象是否存在、操作者权限和业务版本。
  3. 参数错误、权限失败、版本冲突默认禁止直接重放。
  4. 文件安全检测、Push、审计写入等可重试任务允许重放。
  5. 每次重放都写审计,记录处理人、原因、原事件和新事件。

死信告警:

指标 建议
单 Topic 死信数 5 分钟内超过阈值告警。
同一 event_type 连续失败 可能是代码或配置问题,立即告警。
同一租户大量失败 检查租户库、配置或权限状态。
死信积压时间 超过 24 小时未处理提醒。

对 Admin Command 类事件,进入死信后必须回传 im.admin.command.result,状态为 failed 或 dead,让后台操作单结束等待状态。否则后台会长期显示处理中。

8. 内部接口鉴权

内部 API 鉴权非常关键,必须同时做网络层、服务层和业务层控制。

8.1 网络层

  1. /internal/* 只允许内网网关或内网地址访问。
  2. 禁止公网直接暴露内部接口。
  3. 有条件时启用 mTLS。

8.2 服务签名

内部请求统一携带:

Header 说明
X-Service-Name 调用方服务名,例如 hotgo-admin 或 im-server。
X-Timestamp Unix 秒或毫秒时间戳。
X-Nonce 随机串,短期内不可重复。
X-Request-ID 请求追踪 ID。
X-Signature HMAC 签名。

签名内容:

METHOD + "\n" +
PATH_WITH_QUERY + "\n" +
BODY_SHA256 + "\n" +
X-Timestamp + "\n" +
X-Nonce

校验规则:

  1. 时间窗建议 5 分钟。
  2. nonce 写 Redis,TTL 5 分钟,防重放。
  3. 每个服务独立 service_id/service_secret。
  4. 每个服务配置允许访问的内部接口白名单。

8.3 业务授权

Admin 调 IM 查询时,签名 payload 或 Header 中必须包含后台操作者信息:

字段 说明
admin_user_id 后台用户 ID。
admin_role 后台角色。
admin_permissions 本次已校验过的权限列表。
tenant_code 被查询租户。
reason 查询原因或工单号。

IM 仍需根据 tenant_code + permission + resource 做二次校验,并写内部查询审计。

IM 调 Admin 配置接口时,Admin 只校验服务身份和接口白名单,不返回超出 IM 运行需要的字段。

9. 文件与工作台

9.1 文件

文件上传下载不走 Kafka,OSS 是文件字节流主链路。当前只有消息落库使用 Kafka;文件生命周期改为同步处理:

  1. im.file.security:仍可用于内容安全、恶意文件检测。
  2. 消息附件引用绑定在消息落库 consumer 内同步执行。
  3. 群文件登记/删除由对应 HTTP 业务接口同步落库。

9.2 工作台

工作台查询不走 Kafka,状态变化和提醒当前也改为同步处理:

  1. 会议创建、更新、取消、提醒、响应:业务接口同步生成通知/红点事件。
  2. 日报/月报提交、撤回、重开、催办:业务接口同步生成通知/红点事件。
  3. 总经理信箱提交、处理结果:业务接口同步处理。
  4. 工作台模块配置变更:im.config.event 或 im.cache.invalidate。

10. 首批落地建议

阶段 内容
第一步 增加 Kafka 配置、生产者、消费者、健康检查、统一 Envelope。
第二步 增加消费幂等表、outbox 表、死信表或死信 Topic。
第三步 接入 im.admin.command 和 im.admin.command.result,先覆盖后台群治理操作。
第四步 增加 IM 内部只读查询 API,供 Admin 查用户、群、消息、文件快照。
第五步 增加 Admin 内部配置 API,供 IM 查询租户配置、字典、第三方参数。
第六步 接入文件安全检测、离线 Push、工作台事件。
第七步 消息异步落库接入 im.message.persist,完善幂等和重试。

11. 分端任务拆分

11.1 Admin/HotGo 侧任务

Admin 侧只访问 hotgo 库,负责后台操作入口、配置主数据、命令生产、结果消费和死信处理。

模块 任务 产出
Kafka 基础 增加 Kafka producer/consumer 配置、健康检查、统一 Envelope 组装。 可发送 im.admin.command、消费 im.admin.command.result。
操作单 新增 admin_command、admin_outbox 表和状态机。 pending/running/succeeded/failed/dead 操作状态。
Outbox 后台写操作单与 outbox 同事务落库,poller 发送 Kafka。 防止 hotgo 写成功但 Kafka 丢事件。
Command 生产 群治理、用户封禁/解封、重置密码、审核结果、工作台配置等后台操作生成 Command。 im.admin.command 事件。
Result 消费 消费 IM 回传结果并更新操作单。 后台页面可展示最终成功/失败原因。
配置事件 租户配置、字典、功能开关、第三方配置变更后发送 im.config.event。 IM 刷新缓存或本地副本。
配置查询 API 提供 /internal/im-config/* 只读接口。 IM 启动预热和缓存缺失兜底查询。
摘要表 建立用户、群、文件、工作台等后台摘要表。 后台列表统计优先查 hotgo。
死信后台 提供死信查看、重放、忽略、标记已处理、重新生成命令。 运维闭环。
内部鉴权 实现服务签名校验、nonce 防重放、接口白名单、审计。 保护 Admin 内部配置 API。
审计 记录后台操作者、租户、资源、Command、Result、死信处理。 可追踪后台操作链路。

Admin 首批优先级:

  1. Kafka 基础配置、Envelope、producer。
  2. admin_command + admin_outbox。
  3. 群治理 Command 生产。
  4. im.admin.command.result 消费。
  5. /internal/im-config/* 配置查询 API。
  6. 死信管理页。

11.2 IM Server 侧任务

IM Server 侧只访问租户业务库,负责执行 Admin Command、维护租户业务状态、通过 WS 通知 C 端,并向 Admin 回传结果。

模块 任务 产出
Kafka 基础 增加 Kafka producer/consumer 配置、健康检查、统一 Envelope 解析。 可消费 Command、生产 Result/Event。
消费幂等 新增租户库消费幂等表或统一消费日志。 event_id + consumer_group 幂等。
Command 消费 消费 im.admin.command。 后台命令进入 IM 执行链路。
群治理执行器 执行群资料、管理员、禁言、踢人、解散、群主转让等命令。 更新租户库和 Topic 状态。
用户治理执行器 执行封禁、解封、重置密码、踢在线等命令。 更新用户状态和 auth_version。
Result 生产 执行成功/失败后发送 im.admin.command.result。 Admin 操作单闭环。
WS 通知 Command 成功后生产 C 端业务事件并投递在线客户端。 `info.what="im
配置消费 消费 im.config.event,刷新进程内缓存或本地副本。 租户配置、字典、第三方配置生效。
配置兜底查询 调 Admin /internal/im-config/*。 IM 启动预热和缓存缺失恢复。
内部只读 API 提供 /internal/admin-query/*。 Admin 实时查询租户业务数据。
文件任务 上传完成、附件绑定、群文件登记/删除同步处理。 文件审核、引用绑定、回收。
消息异步落库 接入 im.message.persist、im.group.message.persist。 私聊/群聊消息削峰落库。
Push 任务 生产 im.message.push。 离线 Push 异步投递。
死信处理 写失败表、投 im.dead.letter、Command 死信回传 Result。 失败可诊断、可补偿。
内部鉴权 校验 Admin 调用 /internal/admin-query/* 的签名、权限和审计。 保护租户业务查询。

IM Server 首批优先级:

  1. Kafka 基础配置、Envelope、consumer/producer。
  2. 消费幂等表和死信写入。
  3. im.admin.command 群治理消费执行。
  4. im.admin.command.result 回传。
  5. WS 业务事件下发。
  6. /internal/admin-query/* 只读查询 API。

11.3 双方联调契约

契约 Admin 负责 IM Server 负责
Envelope 字段 生产完整字段,保证 event_id/trace_id/tenant_code/event_type/idempotency_key。 校验字段完整性和事件类型白名单。
Command 状态 创建操作单,展示状态。 回传成功、失败、死信结果。
幂等 同一后台操作复用 command_id/idempotency_key。 同一 Command 重复消费只执行一次。
错误码 展示 IM 返回的稳定 reason。 返回稳定 reason,不让 Admin 解析错误文本。
查询接口 带管理员身份、权限、原因和签名。 校验签名、权限和租户资源,写审计。
配置接口 提供最小必要配置字段。 不直连 hotgo,使用缓存、事件或内部 API。
死信 提供处理入口和人工操作审计。 写死信、回传 Command dead/failed 状态。
Trace 生成并传递 trace_id。 日志、Kafka、WS 下发沿用同一 trace_id。

11.4 首批联调用例

用例 预期
Admin 禁言群成员 Admin 操作单 pending,IM 消费后更新租户库,C 端收到 group.mute.updated,Admin 状态 succeeded。
Admin 重复提交同一禁言操作 IM 只执行一次,Result 返回同一最终状态。
Admin 删除管理员但群版本冲突 IM 返回 GROUP_VERSION_CONFLICT,Admin 操作单 failed,不自动重试。
IM 消费时临时 DB 失败 自动退避重试,未超限不进入死信。
IM 消费超过重试上限 写 im.dead.letter,Admin 操作单进入 dead/failed。
Admin 查询群成员 Admin 调 /internal/admin-query/*,IM 校验签名和权限后返回只读数据。
IM 启动加载租户配置 IM 优先读缓存,缺失时调 /internal/im-config/*,Admin 只返回必要配置。

11.5 IM Server 已接入的首批 Admin Command

IM Server 首批消费 im.admin.command,执行后回传 im.admin.command.result。所有命令必须带 tenant_code,payload.actor_user_id 必须是租户内 IM 用户 ID,用于落群事件和 C 端通知。

Command event_type 说明 必填 payload
group.profile.update 修改群名称、头像、简介。 command_id,actor_user_id,topic,profile,version
group.governance.update 修改进群审批、全员禁言、成员邀请等治理开关。 command_id,actor_user_id,topic,governance,version
group.admin.set 设置一个或多个管理员。 command_id,actor_user_id,topic,user_ids
group.admin.remove 删除管理员,降为普通成员。 command_id,actor_user_id,topic,user_id
group.member.mute 禁言成员。 command_id,actor_user_id,topic,user_id,reason,expires_at
group.member.unmute 解除禁言。 command_id,actor_user_id,topic,user_id
group.member.remove 移出群成员。 command_id,actor_user_id,topic,user_id
group.owner.transfer 转让群主。 command_id,actor_user_id,topic,target_user_id,version

当前 IM Server 消费 im.admin.command 时已经接入 im_kafka_consume_log:

  1. 按 event_id + consumer_group 抢占消费。
  2. 已成功事件直接跳过,不重复执行业务。
  3. 处理中且未超时的事件跳过,避免并发重复执行。
  4. 失败或处理超时的事件允许重新抢占。
  5. 不可重试错误或超过重试次数后写入 im_kafka_dead_letters,并投递 im.dead.letter。
  6. Admin Command 进入死信时回传 im.admin.command.result,status=dead。

11.6 IM Server 已接入的配置事件

IM Server 首批消费 im.config.event,用于 Admin 修改 HotGo 配置后通知 IM 刷新进程内缓存。当前实现以“缓存失效”为主,收到事件后清除对应缓存,下次业务读取时重新加载。

Config event_type 说明 IM 行为
tenant.updated 租户基础信息变更。 清理租户 code/id 缓存。
tenant.status.changed 租户启停、状态变化。 清理租户 code/id 缓存。
tenant.limits.updated 租户人数、群数、上传限制等变化。 清理租户 code/id 缓存。
tenant.features.updated 租户功能开关变化。 清理租户 code/id 缓存。
dictionary.updated 字典配置变化。 清理第三方/字典配置缓存。
third_party.updated OSS、文件安全、短信、极光、声网等第三方配置变化。 按 group 清理第三方配置缓存。
registration.config.updated 注册、短信开关变化。 清理注册配置缓存。

事件示例:

{
  "event_id": "evt_01K_config",
  "trace_id": "req_01K",
  "tenant_code": "default",
  "source_service": "hotgo-admin",
  "target_service": "im-server",
  "event_type": "third_party.updated",
  "biz_type": "config",
  "biz_id": "im_third_party",
  "occurred_at": "2026-08-26T10:05:00.000Z",
  "payload": {
    "tenant_code": "default",
    "group": "im_third_party",
    "keys": ["oss.endpoint", "file_security.enabled"]
  }
}

禁言命令示例:

{
  "event_id": "evt_01K_mute",
  "trace_id": "req_01K",
  "tenant_code": "default",
  "source_service": "hotgo-admin",
  "target_service": "im-server",
  "event_type": "group.member.mute",
  "biz_type": "group",
  "biz_id": "grp...",
  "idempotency_key": "cmd_01K_mute",
  "occurred_at": "2026-08-26T10:00:00.000Z",
  "payload": {
    "command_id": "cmd_01K_mute",
    "actor_user_id": "usr_admin",
    "topic": "grp...",
    "user_id": "usr_target",
    "reason": "刷屏",
    "expires_at": null
  }
}

11.7 IM Server 已接入的内部只读查询 API

为满足“Admin 不直连租户库”的边界,IM Server 提供内部只读查询接口给 HotGo/Admin 调用。接口默认关闭,通过 internal_api.enabled=true 开启。

请求统一鉴权头:

Header 说明
X-Service-Name 调用方服务名,如 hotgo-admin。
X-Timestamp Unix 秒级时间戳,默认 300 秒时间窗。
X-Nonce 一次性随机串,用于防重放。
X-Request-ID 调用链路 ID。
X-Signature HMAC-SHA256 签名,支持 hex 或 base64,可带 sha256= 前缀。

nonce 防重放优先使用 Redis 短状态 SETNX + TTL,Redis 未配置时退化为单节点进程内防重放;生产多节点必须配置 Redis。

签名明文:

METHOD + "\n" +
PATH_WITH_QUERY + "\n" +
SHA256_HEX(BODY) + "\n" +
X-Timestamp + "\n" +
X-Nonce

当前首批接口:

接口 说明
GET /internal/admin-query/tenants/{tenant_code}/users/{user_id} 查询租户内用户基础资料。
GET /internal/admin-query/tenants/{tenant_code}/groups/{topic} 查询群资料和治理配置。
GET /internal/admin-query/tenants/{tenant_code}/groups/{topic}/members 查询群成员分页快照,支持 limit/cursor/role/eligible_role/q。
GET /internal/admin-query/tenants/{tenant_code}/messages/{topic}/{seq_id} 查询单条私聊或群聊消息,seq_id 为 BIGINT。
GET /internal/admin-query/tenants/{tenant_code}/files/{file_id} 查询文件元信息和存储位置。

配置示例:

{
  "internal_api": {
    "enabled": true,
    "time_window_seconds": 300,
    "services": {
      "hotgo-admin": {
        "secret": "replace-with-random-secret",
        "allow": ["admin_query"]
      }
    }
  }
}

Docker 环境变量:

环境变量 说明
INTERNAL_API_ENABLED 是否开启内部接口,默认 false。
INTERNAL_API_TIME_WINDOW_SECONDS 签名时间窗。
INTERNAL_API_HOTGO_SERVICE_NAME Admin 服务名,默认 hotgo-admin。
INTERNAL_API_HOTGO_SECRET Admin 与 IM 共享签名密钥。

11.8 IM 访问 Admin 配置查询接口

为满足“IM 服务不直连 hotgo 库”的目标,IM Server 增加 Admin 内部配置查询客户端。该客户端默认关闭,开启后 store.Tenants、注册短信开关、第三方配置读取会优先请求 Admin 内部接口,失败时仍可回落旧数据库适配器,便于灰度迁移。

配置示例:

{
  "admin_internal_api": {
    "enabled": true,
    "base_url": "http://hotgo-admin:8080",
    "service_name": "im-server",
    "secret": "replace-with-random-secret",
    "timeout_ms": 3000
  }
}

接口约定:

接口 用途
GET /internal/im-config/tenants/by-code/{tenant_code} 按企业码获取租户路由信息,需返回 id/code/name/state/db_name/db_dsn。
GET /internal/im-config/tenants/by-id/{tenant_id} 按租户 ID 获取租户路由信息。
GET /internal/im-config/tenants?state=active&limit=1000 获取活跃租户列表,用于 Kafka Outbox 扫描。
GET /internal/im-config/registration/sms 获取注册短信开关,返回 {"enabled": true}。
GET /internal/im-config/third-party/{group}?keys=a,b 获取第三方配置,返回 {"values": {"a": "..."}}。

鉴权沿用内部接口 HMAC 方案,请求头为 X-Service-Name、X-Timestamp、X-Nonce、X-Signature;签名文本为 METHOD + "\n" + RequestURI + "\n" + BodySHA256 + "\n" + Timestamp + "\n" + Nonce。

Docker 环境变量:

环境变量 说明
ADMIN_INTERNAL_API_ENABLED 是否启用 IM 到 Admin 的配置查询客户端,默认 false。
ADMIN_INTERNAL_API_BASE_URL Admin 内部接口根地址。
ADMIN_INTERNAL_API_SERVICE_NAME IM 服务名,默认 im-server。
ADMIN_INTERNAL_API_SECRET Admin 与 IM 共享签名密钥。
ADMIN_INTERNAL_API_TIMEOUT_MS 请求超时时间。

11.9 IM Server 已接入的消息异步落库

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。
  5. 消费侧复用 im_kafka_consume_log 做 event_id + consumer_group 幂等。
  6. 失败按统一退避重试 3 次,超过上限先投递 im.dead.letter,再由 dead letter consumer 写入 im_kafka_dead_letters。

11.10 IM Server 已接入的缓存失效消费

IM Server 已订阅 im.cache.invalidate,用于接收 Admin 或其他节点发出的通用缓存失效事件。消费侧复用 im_kafka_consume_log 做幂等,失败按统一退避重试,超过上限进入死信。

事件体示例:

{
  "event_id": "cache:tenant:default:1720000000",
  "event_type": "cache.tenant.invalidate",
  "tenant_code": "default",
  "payload": {
    "tenant_code": "default",
    "tenant_id": 1,
    "namespace": "tenant"
  }
}

支持的失效范围:

event_type / namespace 处理方式
cache.tenant.invalidate / tenant 清理租户注册表与租户配置进程内缓存。
cache.registration.invalidate / registration 清理注册短信开关缓存。
cache.third_party.invalidate / third_party 按 group 清理第三方配置缓存。
cache.dictionary.invalidate / dictionary 按 group 清理字典/配置类缓存。
cache.redis_object.invalidate / 任意 Redis namespace 按 keys 删除用户、群、关系、权限、未读等 Redis 对象缓存。
cache.group_hot_messages.invalidate / group_hot_messages 按 topic 和可选 ranges 清理群热消息缓存。

11.11 IM Server 已接入的死信处理闭环

IM Server 已将死信从“只写表”补齐为“可查询、可忽略、可解决、可重放”的处理闭环。Admin 不直连租户库,列表和详情通过 IM 内部只读 API 查询;写操作仍通过 im.admin.command 投递给 IM。

Admin 查询接口:

接口 说明
GET /internal/admin-query/tenants/{tenant_code}/kafka/dead-letters?status=dead&limit=50&cursor= 死信分页列表,支持 status/biz_type/biz_id/event_type 过滤。
GET /internal/admin-query/tenants/{tenant_code}/kafka/dead-letters/{dead_id} 单条死信详情,包含原始 Kafka envelope。

Admin 处理命令:

event_type 说明 Payload 关键字段
kafka.dead_letter.replay 删除原消费日志并按原 source_topic 重投 envelope,成功后标记 replayed。 dead_id、actor_user_id、note
kafka.dead_letter.ignore 人工确认无需处理,标记 ignored。 dead_id、actor_user_id、note
kafka.dead_letter.resolve 线下修复后标记 resolved。 dead_id、actor_user_id、note

重放规则:

  1. IM 先把 im_kafka_dead_letters.status 改为 pending_replay,并删除对应 im_kafka_consume_log。
  2. IM 按死信记录中的 source_topic 重新投递原 envelope。
  3. 投递成功后把死信标记为 replayed,并累计 replay_count。
  4. 如果重放后仍失败,普通消费者会再次写入新的 dead 记录,保留完整处理痕迹。

11.12 IM Server 已接入的用户治理命令

IM Server 已在 im.admin.command 中接入用户治理类后台动作。Admin 侧写 hotgo 操作单并发送 Kafka Command,IM 消费后修改租户库用户状态、踢在线连接、清理缓存并回传 im.admin.command.result。

支持命令:

event_type 行为 Payload 关键字段
user.ban 封禁用户,设置 StateSuspended 并踢所有在线会话。 actor_user_id、user_id 或 target_user_id、reason
user.unban 解封用户,设置 StateOK。 actor_user_id、user_id 或 target_user_id、reason
user.freeze 冻结账号,设置 StateSuspended 并踢所有在线会话。 actor_user_id、user_id 或 target_user_id、reason
user.unfreeze 恢复账号,设置 StateOK。 actor_user_id、user_id 或 target_user_id、reason
user.device.kick 踢指定设备在线连接,并删除设备推送记录。 actor_user_id、user_id 或 target_user_id、device_id、reason
user.logout_all 踢用户所有在线连接,不修改账号状态。 actor_user_id、user_id 或 target_user_id、reason
user.account.cancel 注销账号,默认软删除;hard=true 时硬删除。 actor_user_id、user_id 或 target_user_id、hard、reason
user.account.delete 删除账号,按硬删除处理。 actor_user_id、user_id 或 target_user_id、reason

命令示例:

{
  "event_id": "admin:user:ban:default:usrabc:001",
  "tenant_code": "default",
  "source_service": "hotgo-admin",
  "target_service": "im-server",
  "event_type": "user.ban",
  "biz_type": "user_governance",
  "biz_id": "usrabc",
  "idempotency_key": "admin-operation-id",
  "occurred_at": "2026-08-26T10:10:00.000Z",
  "payload": {
    "command_id": "admin-operation-id",
    "actor_user_id": "usrAdmin",
    "user_id": "usrabc",
    "reason": "违规处理"
  }
}

处理说明:

  1. 封禁/冻结共用 Tinode 用户状态 StateSuspended;解封/恢复共用 StateOK。

  2. 状态变更后 IM 会清理用户缓存,并向本节点 Hub 投递用户状态变更。

  3. 踢设备只影响匹配 device_id 的在线连接,同时删除该设备 Push token 记录。

  4. 全端登出只踢在线连接,不修改用户状态。

  5. 注销/删除会停止用户相关 Topic、清理缓存并调用 store.Users.Delete。

  6. 命令执行成功后统一回传 im.admin.command.result;跨系统审计通过 im.audit.event 投递给 Admin/HotGo 同步落表。

  7. 群消息消费成功后继续写入 Redis 热消息缓存,便于 24 小时内热点拉取。

事件示例:

{
  "event_id": "msg.persist.1.grpabc.10086",
  "tenant_code": "default",
  "source_service": "im-server",
  "target_service": "im-server",
  "event_type": "message.persist.group",
  "biz_type": "message",
  "biz_id": "grpabc:10086",
  "idempotency_key": "client-mid-001",
  "version": 10086,
  "occurred_at": "2026-08-26T10:10:00.000Z",
  "actor": {
    "type": "user",
    "id": "usr..."
  },
  "payload": {
    "message_kind": "group",
    "read_by_sender": true,
    "attachment_urls": [],
    "message": {
      "SeqId": 10086,
      "Topic": "grpabc",
      "From": "abcdef",
      "Head": {
        "x-im-client-mid": "client-mid-001"
      },
      "Content": {
        "txt": "hello"
      }
    }
  }
}

11.9 IM Server 已移除 Kafka DB Outbox

IM Server 不再维护租户库 im_kafka_outbox,Kafka 事件统一由发送入口直接生产。生产侧使用 Kafka writer 的 max_retry_count 控制发送重试;消费侧使用 im_kafka_consume_log 做处理幂等和失败重试,超过上限后进入 im.dead.letter。

本轮暂不实现 im.message.push 离线 Push Kafka 化,已记录到 IM 第一至十一章后续增强项。

11.10 IM Server 文件生命周期同步处理

IM Server 不再生产或消费 im.file.lifecycle。文件相关的小流量动作改为同步执行。

当前事件:

event_type 生产时机 消费行为
file.upload.completed HTTP/gRPC 上传成功并完成文件记录后。 当前无需 Kafka 消费。
file.attachments.bind 消息落库 consumer 成功后,如果消息携带附件。 同步写 im_filemsglinks 或 im_group_files。
group.file.created 群文件 API 登记成功后。 HTTP 业务接口同步完成。
group.file.deleted 群文件 API 删除成功后。 HTTP 业务接口同步完成。

说明:

  1. 消息附件绑定在消息落库 consumer 内同步完成。
  2. Kafka 关闭时,仍沿用原同步消息落库与附件绑定路径,兼容本地环境。
  3. 文件对象字节流仍走 OSS/文件服务,Kafka 不承载上传/下载内容。
  4. 合规删除、临时文件 TTL 回收、OSS 删除动作仍保留为后续深化项。

11.11 IM Server 工作台事件消费处理

工作台拆分为独立 im_workbench 服务后,工作台业务变更由 im_workbench 生产 im.workbench.event,IM Server 新增独立 Kafka consumer 消费该 Topic,并转为系统通知和 C 端业务实时事件。

说明:IM Server 当前保留旧工作台 HTTP 代码和同步处理函数,仅作为迁移过渡兼容。待 im_workbench 全部接口稳定后,再统一删除 IM Server 内的旧工作台业务代码。

当前生产范围:

模块 事件
会议 meeting.created、meeting.updated、meeting.canceled、meeting.reminded、meeting.response.updated
日报 daily_report.draft.created、daily_report.draft.saved、daily_report.submitted、daily_report.reminded
月报 monthly_report.draft.created、monthly_report.draft.saved、monthly_report.submitted、monthly_report.reopened
总经理信箱 mailbox.submitted

当前消费行为:

  1. im_workbench 直接发送 JSON 事件到 im.workbench.event,Topic 配置键为 workbench_external。
  2. IM Server 按 event_id + consumer_group 做消费幂等。
  3. 按 target_user_ids 为非发布人生成系统通知。
  4. 写入 im_business_events_outbox,由现有 WS 业务事件投递器下发在线客户端。
  5. 消费失败按统一 Kafka 重试逻辑处理,超过最大重试次数后进入 im.dead.letter。

11.12 IM Server 已接入的审计事件

IM Server 对跨系统审计仍生产 im.audit.event。该 topic 由 Admin/HotGo 消费并同步写审计表;IM Server 本地不消费该 topic,也不通过它做内部异步落库。

当前审计范围:

类型 事件
工作台 会议、日报、月报、总经理信箱的状态变更。
Admin Command 后台群治理命令执行成功。
Kafka 死信 kafka.dead_letter.created。
文件生命周期 上传完成、附件绑定、群文件新增/删除。

审计事件当前不在 IM 内部通过 Kafka 落审计表,只作为 IM -> Admin/HotGo 的跨系统写事件。

12. 风险与约束

  1. Kafka 是异步链路,Admin 后台命令不能默认立即成功,只能显示 pending/running/succeeded/failed。
  2. 查询不能通过 Kafka 常规化实现,高频实时查询必须走内部只读 API 或 hotgo 摘要表。
  3. 内部 API 不能暴露公网,签名、nonce、防重放和审计必须首批完成。
  4. 配置事件可能丢失或延迟,IM 必须保留启动预热和缓存缺失时的 Admin 配置查询兜底。
  5. Kafka 消费可能重复,所有消费者和业务写入都必须幂等。
  6. Admin 和 IM 不跨库直连后,排障要依赖 trace_id 串联 hotgo 操作单、Kafka 事件、IM 执行日志和 WS 下发日志。