20 KiB
IM 工作台服务拆分迁移稳定方案
目标:将
im_server中的工作台业务拆到独立仓库/Users/youshunlai/go_workspace/im_workbench,先形成独立服务和独立发布边界;数据库暂不迁移,等接口全部稳定后再单独做工作台库迁移。
1. 结论
建议采用“独立仓库 + 分阶段迁移 + Nginx 分流 + Redis 统一 Token 鉴权”的方式:
im_server保留 IM 核心能力:登录态校验、聊天协议、单聊/群聊、消息存储、长连接、在线状态、Redis 实时 fanout、Kafka 消息消费。im_workbench承接工作台能力:工作台入口、组织架构、考勤、会议、会议笔记、日报、月报、总经理信箱、工作台红点。- 当前阶段不迁移数据库,
im_workbench先连接现有租户库读取和写入工作台相关表。 - 等
im_workbench接口、鉴权、Kafka、监控全部稳定后,再单独启动数据库迁移专项。 - 工作台接口直接切换为
/v1/workbench/*,由 Nginx/API Gateway 按路径分发到im_workbench;im_server不再代理工作台请求。 - 迁移采用“先复制迁出、旧代码保留”的方式;只有
im_workbench全部接口、数据库、Kafka、监控联调通过后,才删除im_server中的工作台旧代码。
一句话:网关分流,Redis 鉴权,先拆服务和接口,数据库后迁,最后清理 im_server 中的工作台旧代码。
2. 拆分范围
2.1 迁出到 im_workbench
以下业务从 im_server 迁移到 im_workbench:
| 模块 | 当前接口示例 | 迁移归属 |
|---|---|---|
| 工作台入口 | GET /v1/workbench |
im_workbench |
| 组织架构 | /v1/workbench/organization/* |
im_workbench |
| 考勤打卡 | /v1/workbench/attendance/* |
im_workbench |
| 会议通知 | /v1/workbench/meetings* |
im_workbench |
| 会议笔记 | /v1/workbench/meeting-notes、/v1/workbench/meetings/{id}/notes* |
im_workbench |
| 日报 | /v1/workbench/reports/daily* |
im_workbench |
| 月报 | /v1/workbench/reports/monthly* |
im_workbench |
| 总经理信箱 | /v1/workbench/mailbox* |
im_workbench |
| 工作台红点 | workbench_total_unread、模块未读 |
im_workbench 计算,im_server 聚合透出 |
2.2 留在 im_server
以下能力继续留在 im_server:
| 模块 | 说明 |
|---|---|
| 登录与 Token 签发 | C 端登录仍由 IM 负责,登录成功后把 Token 会话写入 Redis。 |
| 聊天消息 | 单聊、群聊、消息 seq、消息落库、Redis fanout、WS 下发。 |
| 群治理 | 群资料、群成员、禁言、进群审批、群公告、群文件。 |
| 文件上传入口 | POST /v0/file/u/ 暂留 im_server,工作台只保存业务引用;后续可单独拆文件服务。 |
| 系统通知投递 | 最终给 C 端的在线通知仍由 im_server 通过 WS 下发。 |
| Kafka 消费到 C 端 | Admin 或 Workbench 产生的业务事件,由 im_server 消费后找在线用户下发。 |
3. 目标架构
C 端 App
|
| HTTPS
v
Nginx / API Gateway
|-- /v1/im/*、/v0/channels、/v0/file/u/ -> im_server
|-- /v1/workbench/* -> im_workbench
im_workbench
|
| MySQL
v
现有租户库中的工作台表
im_workbench
|
| Kafka: workbench 业务事件
v
im_server
|
| WebSocket
v
C 端在线用户
稳定边界:
im_workbench不直接操作 IM 消息表、在线连接、WebSocket。im_server不直接写工作台业务表,也不代理工作台 HTTP 请求。im_server登录成功后将 Token 会话写入 Redis,im_workbench每次请求从 Redis 校验 Token。- 两边共享用户 ID 口径:内部管理和工作台接口使用数据库
BIGINT/int64;聊天协议层仍可使用usr...。 - 工作台需要通知 C 端时投 Kafka 事件,由
im_server统一下发。
4. 数据库处理方案
4.0 当前阶段原则
当前阶段数据库先不迁移。im_workbench 独立服务启动后,仍访问现有租户库中的工作台相关表,先保证新服务接口、Redis Token 鉴权、Nginx 路由、Kafka 事件和监控全部跑通。
代码层面禁止服务启动时自动建库建表。im_server 和 im_workbench 都只负责连接已有数据库和执行正常业务 SQL;所有 CREATE DATABASE、CREATE TABLE、ALTER TABLE、索引变更、初始化字典和种子数据,统一整理为 SQL 文件,经审核后由人工或运维发布流程执行。
数据库迁移作为后置专项处理,触发条件是:
/v1/workbench/*全部接口在本地、测试环境、前端联调中稳定。im_server中工作台旧接口确认没有客户端继续访问。- 工作台事件、通知、红点、文件引用链路全部验收通过。
- 运维确认新库命名、备份、监控、账号权限和迁移窗口。
4.1 当前工作台相关表
当前这些表仍保留在租户库 tinode 中,暂不迁移;后续数据库专项时再纳入迁移范围:
| 表 | 用途 | 迁移建议 |
|---|---|---|
im_workbench_apps |
工作台模块配置、排序、入口 | 暂留租户库;后续迁到工作台库或由 Admin 配置后同步。 |
im_org_departments |
组织部门树 | 暂留租户库;后续迁到工作台库。 |
im_org_members |
组织成员、岗位、联系方式 | 暂留租户库;保留 user_id BIGINT 关联 IM 用户。 |
im_org_visibility_overrides |
组织可见范围覆盖 | 暂留租户库。 |
im_attendance_rules |
考勤规则 | 暂留租户库。 |
im_attendance_shifts |
考勤班次 | 暂留租户库。 |
im_attendance_records |
考勤日记录 | 暂留租户库。 |
im_attendance_checkins |
打卡流水 | 暂留租户库。 |
im_attendance_appeals |
补卡/异常申诉 | 暂留租户库。 |
im_meetings |
会议主表 | 暂留租户库。 |
im_meeting_participants |
会议参与人 | 暂留租户库。 |
im_meeting_note_files |
会议笔记文件引用 | 暂留租户库;文件实体仍在文件表/OSS。 |
im_daily_reports |
日报 | 暂留租户库。 |
im_monthly_reports |
月报 | 暂留租户库。 |
im_mailbox_config |
总经理信箱配置 | 暂留租户库;后续可迁到工作台库或 Admin 公共库配置后同步。 |
im_mailbox_submissions |
总经理信箱提交 | 暂留租户库。 |
4.2 不迁出的表
| 表/数据 | 原因 |
|---|---|
users、认证、会话、设备 |
属于 IM 登录和账号基础能力。 |
topics、subscriptions、messages、im_group_messages |
属于聊天主链路。 |
| 好友、黑名单、群成员、群治理表 | 属于 IM 社交关系和群聊能力。 |
| 文件实体表、OSS 元数据 | 暂不迁移,工作台只保存 file_id 引用。 |
im_system_notifications |
建议先留在 im_server,作为统一 C 端通知中心。后续如要拆,可单独设计通知服务。 |
im_business_events_outbox |
已废弃,不纳入迁移;当前代码不再自动建表,工作台拆分后事件统一走 Kafka 或实时投递链路。 |
4.3 后续目标库建议
后续接口稳定后,再给工作台单独库,命名按环境区分:
本地:im_workbench
测试:im_workbench_test 或按运维规范命名
生产:im_workbench
如果继续保持“一个租户一个库”,则工作台也应支持租户库路由:
hotgo.im_tenant
- code
- im_db_name
- workbench_db_name
- im_internal_base_url
- workbench_internal_base_url
正式方向建议在 hotgo.im_tenant 或租户配置表里增加工作台库配置,而不是让 im_server 读取工作台库 DSN。
4.4 后续数据迁移顺序
迁库等接口全部稳定后再做,不要和本轮服务拆分混在一起。后续建议分四步:
- 建新库新表:在
im_workbench库手动执行审核后的 SQL,创建同结构表,先不接线上流量。 - 全量复制:从租户库复制历史工作台表数据到工作台库。
- 增量同步:迁移窗口内对工作台写操作做双写,或由旧库 binlog/脚本同步到新库。
- 切读切写:先灰度读新库,再切写新库,最后关闭旧库工作台写入。
迁移校验至少包括:
| 校验项 | 说明 |
|---|---|
| 行数校验 | 每张表按租户统计行数。 |
| 主键/业务唯一键校验 | meeting_id、report_id、submission_id、department_id 等必须一致。 |
| 更新时间校验 | 对比 updated_at 最大值,确认增量无遗漏。 |
| 抽样内容校验 | 抽样会议、日报、月报、考勤记录详情。 |
| 外键引用校验 | 会议参与人、会议笔记文件、组织成员部门引用不能断。 |
4.5 回滚原则
当前阶段没有数据库迁移,回滚以服务和路由为主。后续真正迁库时,旧库数据至少保留一个发版周期,不删除旧表。
回滚策略:
- 如果服务拆分异常:关闭
/v1/workbench/*路由,前端回退旧路径或旧版本。 - 如果
im_workbench业务异常:保留im_server旧工作台代码作为临时回退能力。 - 如果 Redis 鉴权异常:停止工作台新路由,优先恢复登录态校验。
- 如果 Kafka 通知异常:业务写入不回滚,只降级为客户端主动拉取和后台补偿推送。
- 后续如果新库读写异常:再按迁库专项方案切回旧库。
5. 路由与鉴权迁移方案
5.1 Nginx 分流规则
工作台接口直接使用新路径 /v1/workbench/*,Nginx/API Gateway 按路径分流:
/v1/im/* -> im_server
/v0/channels -> im_server
/v0/file/u/ -> im_server
/v1/workbench/* -> im_workbench
建议工作台目标路由:
| 原 IM 路径 | 新 Workbench 路径 |
|---|---|
GET /v1/im/workbench |
GET /v1/workbench |
/v1/im/organization/* |
/v1/workbench/organization/* |
/v1/im/attendance/* |
/v1/workbench/attendance/* |
/v1/im/meetings* |
/v1/workbench/meetings* |
/v1/im/meeting-notes* |
/v1/workbench/meeting-notes* |
/v1/im/meetings/{id}/notes* |
/v1/workbench/meetings/{id}/notes* |
/v1/im/reports/daily* |
/v1/workbench/reports/daily* |
/v1/im/reports/monthly* |
/v1/workbench/reports/monthly* |
/v1/im/mailbox* |
/v1/workbench/mailbox* |
不建议让 im_server 继续代理工作台请求。路由由 Nginx 分流,服务各自鉴权、各自访问自己的数据库。
5.2 Redis Token 鉴权
登录仍由 im_server 负责。登录成功后,im_server 将 Token 会话写入 Redis,im_workbench 直接从 Redis 校验登录态。
Redis Key 建议:
im:session:token:{token_hash}
Value 建议使用 JSON:
{
"user_id": 42,
"tenant_id": 1,
"tenant_code": "default",
"device_id": "ios-device-1",
"auth_level": "auth",
"state": "active",
"expires_at": "2026-09-13T18:00:00+08:00",
"issued_at": "2026-09-13T10:00:00+08:00"
}
请求 Header 保持 C 端统一:
| Header | 说明 |
|---|---|
Authorization |
Bearer {token},两个服务都从 Redis 校验。 |
X-MeetingIM-APIKey |
应用 API Key。 |
X-Tenant-Code |
租户编码。 |
X-IM-Schema |
协议版本。 |
X-Request-ID |
链路追踪 ID。 |
校验流程:
- 从
Authorization取 Bearer Token,先做格式校验。 - 对 Token 做 hash 后查 Redis,避免 Redis 明文 Key 暴露原始 Token。
- 校验会话存在、未过期、
state=active。 - 校验
X-Tenant-Code与 Redis 会话中的tenant_code一致。 - 校验 API Key 是否可用于当前租户和客户端类型。
- 将
tenant_id、tenant_code、user_id、device_id写入请求上下文。
Token 失效场景:
| 场景 | 处理 |
|---|---|
| 用户主动退出 | 删除当前 Token Key。 |
| 踢设备 | 删除指定 device_id 对应 Token Key。 |
| 冻结/封禁账号 | 删除用户全部 Token Key,并通过 Kafka 通知在线连接断开。 |
| 修改密码 | 删除用户全部 Token Key。 |
| Token 过期 | Redis TTL 自动过期。 |
5.3 共享鉴权代码
建议抽一个轻量公共包,两个服务复用:
meetingim_common/auth/session
公共包只放稳定协议:
- Redis Key 生成。
- Token hash 规则。
- Session JSON 结构。
- Header 解析。
- 错误码定义。
不要把数据库访问、HTTP handler、业务权限放进公共包,避免公共包变成新的耦合点。
6. 事件与通知
工作台拆出后,工作台业务变更不再直接调用 im_server 代码函数,而是投 Kafka。
建议 Topic:
| Topic | 生产者 | 消费者 | 用途 |
|---|---|---|---|
im.workbench.event |
im_workbench | im_server | 工作台事件、红点、系统通知、WS 下发。 |
im.cache.invalidate |
im_workbench/Admin | im_server/im_workbench | 组织、工作台模块、配置变更后的缓存失效。 |
im.audit.event |
im_workbench | Admin/审计消费者 | 工作台敏感操作审计。 |
im.workbench.event 消息建议字段:
{
"event_id": "wb_default_meeting_mtg_1_created_v1",
"tenant_id": 1,
"tenant_code": "default",
"actor_user_id": 42,
"module": "meeting",
"event_type": "meeting.created",
"resource_id": "mtg_1",
"target_user_ids": [42, 43],
"title": "会议通知",
"content": "项目周会",
"badge_delta": 1,
"payload": {
"meeting_id": "mtg_1",
"version": 1
},
"occurred_at": "2026-09-13T13:30:00+08:00"
}
消费原则:
event_id全局幂等,消费端记录处理日志。- 系统通知写入失败可重试,超过次数进入死信。
- WS 下发失败不影响业务写入,客户端重连后通过工作台接口和 bootstrap 补偿。
- 工作台红点以服务端查询为准,Kafka 只做实时增量提醒。
7. 代码迁移步骤
7.1 第一阶段:服务骨架
在 /Users/youshunlai/go_workspace/im_workbench 新建 Go 服务:
im_workbench/
cmd/workbench/
internal/http/
internal/store/
internal/kafka/
internal/config/
docs/
sql/
第一阶段只做:
- 配置文件、日志、MySQL、Redis、Kafka 初始化。
- 健康检查:
GET /healthz、GET /readyz。 - Redis Token 鉴权中间件。
- 租户上下文解析。
- 复制工作台接口 DTO 和响应结构。
7.2 第二阶段:迁移业务代码
从 im_server 迁出以下代码:
| 当前位置 | 迁移内容 |
|---|---|
server/im_http.go |
serveIMWorkbench、Organization、Attendance、Meetings、MeetingNotes、DailyReports、MonthlyReports、Mailbox 相关 handler。 |
server/store/store.go |
工作台相关 Persistence Interface 和 mapper。 |
server/store/types/*.go |
workbench.go、organization.go、attendance.go、meeting.go、reports.go、mailbox.go 等类型。 |
server/db/mysql/tenant_adapter.go |
工作台相关 SQL 实现。 |
server/im_business_events.go |
工作台事件生产逻辑拆到 im_workbench,只保留 IM 消费下发。 |
server/kafka_workbench_audit.go |
工作台事件生产侧迁出,IM 侧保留消费或下发处理。 |
迁移时要保留测试:
- 原 handler 单测迁到
im_workbench。 im_server原有工作台测试暂时保留,作为旧链路回归保护。im_workbench新增同等接口测试,确认新路径行为一致。- Kafka 事件用例拆为 Workbench 生产端测试和 IM 消费端测试。
7.3 第三阶段:Nginx 路由切换
im_server 中原工作台 handler 暂时不删除,不做主链路代理。新请求由 Nginx/API Gateway 直接分流到 im_workbench:
客户端请求 /v1/workbench
-> Nginx/API Gateway
-> im_workbench Redis Token 鉴权
-> return response
路由层必须支持:
/v1/workbench/*全量转发到im_workbench。/v1/im/*、/v0/channels、/v0/file/u/继续转发到im_server。- 透传
Authorization、X-MeetingIM-APIKey、X-Tenant-Code、X-IM-Schema、X-Request-ID。 - 工作台服务超时建议 3 到 5 秒。
- 工作台不可用时返回明确
WORKBENCH_UNAVAILABLE或网关 502/504,不影响聊天主链路。
旧代码保留策略:
im_server工作台旧 handler、store、SQL 先保留。- 前端切新路径后,测试环境持续观察一个发版周期。
im_workbench全部接口、数据库、Kafka、监控确认稳定后,再从im_server删除旧工作台代码。- 删除前要确保没有客户端继续访问
/v1/im/workbench、/v1/im/meetings*等旧路径。
7.4 第四阶段:接口稳定验收
当前阶段只做接口稳定验收,不做数据库切换。建议保留以下服务开关:
| 配置 | 说明 |
|---|---|
workbench.service.enabled |
是否启用工作台独立服务。 |
workbench.route.enabled |
Nginx/API Gateway 是否启用 /v1/workbench/* 路由。 |
workbench.kafka.enabled |
是否启用工作台事件 Kafka。 |
后续迁库专项再增加数据库切换开关:
workbench.db.read_from=old|new|shadow
workbench.db.write_to=old|dual|new
8. 发布与回归
8.1 发布前检查
im_workbench健康检查通过。im_workbench可连接现有租户库,并只访问工作台相关表。- Redis Token 鉴权与
im_server登录态一致。 - Nginx/API Gateway 工作台路由灰度开关默认关闭或仅测试环境开放。
- Kafka Topic、消费组、死信队列已建。
- 监控已覆盖 HTTP 成功率、耗时、Kafka 积压、DB 错误、网关转发失败。
- 本阶段不要求新工作台库建表和数据复制。
8.2 必测用例
| 模块 | 用例 |
|---|---|
| 工作台入口 | 登录后返回模块排序、开关、未读角标。 |
| 组织架构 | 普通用户、手机号注册用户、邀请用户、测试账号可见范围正确。 |
| 考勤 | 配置查询、打卡、重复幂等、记录列表、申诉创建。 |
| 会议 | 创建、列表、详情、修改、取消、提醒、参会响应。 |
| 会议笔记 | 上传文件、绑定文件、详情、替换、删除、权限校验。 |
| 日报 | 创建草稿、保存、提交、列表、统计、提醒。 |
| 月报 | 创建、保存、提交、reopen、详情、统计。 |
| 总经理信箱 | 配置查询、匿名/实名提交、附件引用。 |
| 通知 | 工作台事件生成系统通知,在线用户收到 WS,离线用户重登可补偿。 |
| 回滚 | 关闭 /v1/workbench/* 路由后,前端回退旧版本或网关明确降级;旧代码未删前可切回旧路径。 |
9. 风险点
| 风险 | 处理 |
|---|---|
| 一次性拆代码和迁库导致回归面过大 | 本阶段不迁库,只拆服务和接口;数据库等接口稳定后单独迁移。 |
| 工作台依赖 IM 用户资料 | 通过 IM 内部查询 API 获取用户摘要,禁止直连 IM 库。 |
| IM 需要工作台红点 | 通过工作台内部接口或 Kafka 事件聚合,禁止 im_server 查工作台库。 |
| 文件上传仍在 im_server | 工作台保存 file_id 引用,文件服务后续再独立拆。 |
| Kafka 事件丢失 | 生产端直接投 Kafka,必要时使用业务失败表补偿;消费端使用幂等和死信队列。 |
| 前端路径切换风险 | 前端切到 /v1/workbench/* 前必须完成接口对照、灰度和回归。 |
| 数据不一致 | 当前阶段继续读写同一套租户库,避免双写不一致;后续迁库再做影子读和校验。 |
10. 推荐落地顺序
- 在
im_workbench建服务骨架、配置、健康检查、Redis Token 鉴权。 - 迁移工作台类型、store interface、MySQL 实现和单测。
- 迁移
/v1/workbench、组织架构、考勤接口。 - 迁移会议、会议笔记、日报、月报、总经理信箱接口。
- Nginx/API Gateway 增加
/v1/workbench/*路由,默认关闭或只对测试环境开放。 - 本地环境用新路径跑通全部工作台接口。
- 测试环境启用新路由灰度,只切少量测试账号。
- 全量接口稳定后,确认没有客户端访问旧
/v1/im/*工作台路径。 - 清理
im_server内工作台业务实现,只保留 IM 主链路。 - 单独启动数据库迁移专项,新建工作台库、复制数据、影子读、切读写。
11. 当前建议先做的第一步
第一步不要急着删 im_server 代码,建议先在 im_workbench 完成最小可运行服务:
- 监听端口建议:
7070。 - 支持
GET /healthz、GET /readyz。 - 支持 Redis Token 鉴权和统一 Header 校验。
- 接入本地 MySQL、Redis、Kafka 配置。
- 先迁
GET /v1/workbench一个读接口做样板。 - Nginx/API Gateway 加
/v1/workbench测试路由,只开放样板接口。
这样第一步上线风险最低,也能验证服务拆分、Redis 鉴权、链路追踪、配置和部署是否顺畅。