飞享IM完整架构设计文档——架构师视角的系统设计全解析

comsince
FshareIM Team架构设计不只是画几张图——它是对整个系统的系统性思考:从业务需求到质量约束,从模块拆分到接口契约,从数据分表到故障容灾,再到 AI 融合与技术演进路线。本文以飞享IM(FshareIM)为参考,完整呈现一位架构师在一个生产级 IM 系统上应当完成的全部设计工作,涵盖六大职责分解、五阶段设计步骤,以及覆盖接入层、业务层、数据层、AI 架构、安全架构和部署架构的完整设计文档,附带技术决策记录(ADR)和架构评审检查单。
一、架构师的工作是什么?
在回答"如何设计这个系统"之前,先明确架构师的职责边界。
六大职责与对应工作分解
架构设计五阶段
二、需求分析与约束条件
功能性需求
| 功能域 | 子功能 | 优先级 |
|---|---|---|
| 即时消息 | 私聊、群聊消息收发 | P0 |
| 即时消息 | 消息已读/投递回执 | P0 |
| 即时消息 | 消息撤回、@功能 | P1 |
| 用户管理 | 手机号/邮箱注册登录 | P0 |
| 群组管理 | 创建群、加人、踢人 | P0 |
| 多媒体 | 图片、文件发送 | P1 |
| 音视频 | 一对一通话(WebRTC) | P1 |
| AI 助手 | AI 对话(流式输出) | P1 |
| 多端同步 | Android + Web 消息同步 | P0 |
非功能性需求(质量属性目标)
| 质量属性 | 指标 | 当前状态 | 目标 |
|---|---|---|---|
| 并发连接数 | 单节点最大连接 | 34 万(8GB 机器) | 110 万(16GB 机器) |
| 消息吞吐量 | 私聊消息 TPS | 3,000–5,000/s | 10,000/s |
| 消息延迟 | P99 端到端延迟 | ~20ms | <50ms |
| 系统可用性 | SLA | 未明确 | 99.95%(月停机 < 22 分钟) |
| 消息可靠性 | 消息不丢失率 | 存在幽灵 Session 丢失风险 | 99.99% |
| 横向扩展 | connector 最大节点数 | 64 | 64(消息 ID 6bit 限制) |
技术约束
三、系统整体架构设计
逻辑架构(4 层分层)
核心消息流转时序
四、模块设计与接口规范
push-connector 职责边界
push-group 服务层次
Dubbo 接口契约(push-stub)
REST API 规范
通用响应结构:
错误码体系:
| 错误码范围 | 含义 |
|---|---|
| 0 | 成功 |
| 1xxx | 参数错误 |
| 2xxx | 认证/鉴权错误 |
| 3xxx | 业务逻辑错误 |
| 5xxx | 服务内部错误 |
核心 API 列表:
| Method | Path | 描述 |
|---|---|---|
| POST | /api/v1/user/login | 手机号+验证码登录 |
| POST | /api/v1/user/register | 注册 |
| POST | /api/v1/group/create | 创建群组 |
| POST | /api/v1/group/{id}/members | 添加群成员 |
| DELETE | /api/v1/group/{id}/members/{uid} | 踢出群成员 |
| POST | /api/v1/media/upload | 上传图片/文件到 MinIO |
五、通信协议设计
TCP 二进制协议头(10 字节)
SubSignal 枚举表
| SubSignal | 值 | 用途 |
|---|---|---|
| MN | 30 | 消息通知(携带最新 seq,触发客户端拉取) |
| MP | 31 | 消息透传推送(不入离线库) |
| MRN | 49 | 已读/投递回执通知 |
| RMN | 50 | 消息撤回通知 |
| SAI | 53 | AI 流式 token 增量推送(新增) |
| FRN | 60 | 好友请求通知 |
| GC/GAM/GKM | 70/71/72 | 群创建/加人/踢人通知 |
协议兼容性原则: SubSignal 不能修改已有枚举值;protobuf 字段只能追加,不能修改已有字段编号。
六、数据架构设计
消息分表策略
⚠️ 运维注意事项:
- 时钟回拨可能导致路由到错误分表,需处理(见 ADR-002)
- 跨月查询最多跨 3 张表
- 3 年后同月复用:须在运维计划中安排历史数据归档,否则数据混淆
Hazelcast 内存数据结构
| Map 名 | Key | Value | 说明 |
|---|---|---|---|
| SESSIONS | clientID | Session | 连接状态 |
| USER_SESSIONS | userId | Set\<clientId> | 多设备映射 |
| MESSAGES_MAP | messageId | MessageBundle | 热消息缓存(7 天 TTL) |
| USER_MESSAGES | userId | TreeMap\<seq,msgId> | 个人收件箱 |
| GROUP_MEMBERS | groupId | Collection\<GroupMember> | 群成员 |
⚠️ 架构风险(已发现): SESSIONS 和 USER_SESSIONS 当前无 max-size 和 TTL 配置,在线用户增至万级时会无界膨胀,导致 OOM。改进方案:
七、AI 融合架构设计
对应岗位要求第 7 条「(特别重要)懂 AI,具备新型 AI 架构工程师能力」
当前 AI 接入方案(SAI 协议)
SAI 数据包格式(当前 JSON)
AI 架构特别关注点
| 关注点 | 当前实现 | 改进建议 |
|---|---|---|
| 流式输出 | SAI SubSignal,每 token 一个包 | 改紧凑二进制帧,减少 JSON 解析开销 |
| 会话记忆隔离 | userId 传给 Agent,按用户维护上下文 | 支持多会话(sessionId)隔离 |
| 并发 AI 请求 | 4 线程固定池,并发 > 4 时排队 | 改有界动态线程池(core=4, max=16) |
| 断线续传 | SAI 不入库,断线丢失 token | 流结束后完整答案通过普通 MN 恢复 |
| 可观测性 | 无 | AI 请求耗时、token 数、错误率监控 |
AI 架构演进路线
八、高可用与容灾设计
各层可用性分析
| 服务层 | 当前风险 | 改进方案 |
|---|---|---|
| 接入层(connector) | 单节点崩溃 → 该节点用户须重连(30~120s) | K8s liveness probe 自动重启 |
| 业务层(push-group) | 单实例 SPOF | 部署 2 实例 + Dubbo failover |
| 数据层(MySQL) | 单主无从库 | MySQL 主从复制 + MHA 自动故障转移 |
| 缓存层(Hazelcast) | 单节点重启丢 Session | 多节点 Hazelcast 集群 |
幽灵 Session 解决方案
问题: connector 进程 kill -9 时,断线回调不触发,online=true 的 Session 残留,其他节点向死连接投递消息后静默丢失。
解决方案:Hazelcast Entry TTL + 心跳续期
九、安全架构设计
认证流程
传输安全状态
| 通道 | 当前状态 | 生产建议 |
|---|---|---|
| TCP 长连接 | 明文 | 启用 SSL(connector 支持配置) |
| WebSocket | ws://(未加密) | 改 wss://(Nginx TLS 终止) |
| REST API | HTTP | HTTPS(Nginx TLS 终止) |
| Dubbo RPC | 明文 + auth token | 内网隔离(已有 token 鉴权) |
分布式限流(改进方案)
当前问题:限流计数存在 JVM 内存中,多节点时实际限额 = 配置值 × 节点数。
改进:Redis Lua 滑动窗口分布式限流:
十、性能容量规划
单节点容量(16GB 机器)
| 指标 | 当前实现 | 优化后目标 |
|---|---|---|
| 最大并发连接数 | 110 万(Kernel TCP buffer 瓶颈) | 110 万(需调 tcp_rmem) |
| 消息写入 TPS | 3,000–5,000/s | 10,000/s(Redis INCR 替代分布式锁) |
| MySQL TPS | ~10,000/s(理论) | ~30,000/s(连接池扩容 + 异步写) |
| AI 并发请求 | 4 | 16(线程池扩容) |
集群扩容规划
OS 调优清单(运维)
十一、技术决策记录(ADR)
ADR-001:选择 t-io 作为 NIO 框架
背景: 需要支持 TCP + WebSocket 双协议,同时支撑 100 万级长连接。
| 方案 | 优点 | 缺点 |
|---|---|---|
| t-io(已选) | 轻量、对 IM 场景优化、中文文档 | 社区相对较小 |
| Netty | 成熟、社区大、性能极致 | 需编写更多底层代码 |
| WebFlux | Spring 生态整合好 | 不支持自定义 TCP 协议 |
决策理由: t-io 内置 IM 场景封装(心跳、群组、广播),开发效率高;110 万连接/节点满足业务需求。后续评估: 若需超过 200 万连接/节点,迁移至 Netty。
ADR-002:消息 ID 使用类 Snowflake 算法
决策: 43bit 时间戳 + 6bit nodeId + 15bit 序号
已知风险:
- 时钟回拨未处理(改进:回拨 > 5ms 拒绝服务,等时钟追上)
- nodeId 手动配置(改进:Redis 自动分配)
- nodeId 上限 63(最多 64 节点)
ADR-003:Hazelcast 作为 Session 存储(部分场景建议改 Redis)
背景: 需要分布式 Session 存储,支持多节点查询。
决策: Hazelcast IMap 存 Session + MySQL 冷备份
后续改进方向:
userMessages.lock(user)的 Hazelcast 分布式锁 → 迁移至 RedisINCR原子操作- Session TTL 管理 → 推荐 Redis(原生 TTL 支持更稳定)
ADR-004:AI 流式输出使用新增 SAI SubSignal
背景: AI Agent 流式 token 需实时推送,MN → Pull 模式延迟过高(多一个 RTT)。
决策: 新增 SubSignal.SAI,旁路推送不入离线库;流结束后完整答案通过 saveAndPublish 正常落库。
权衡: 流中途断线 → token 丢失,仅通过 MN 拉取完整答案恢复(可接受,AI 回复不是核心消息路径)。
十二、技术演进路线图
十三、架构评审检查单
架构师在每次重大版本发布前须对照评审:
功能完整性
- 所有 P0 功能用例已覆盖(私聊/群聊/登录)
- 离线消息在断线重连后可完整恢复
- 多端消息同步(Android + Web)一致
- AI 流式输出与普通消息互不干扰
非功能性验证
- 压测:单 connector 节点 10 万并发连接稳定 1 小时
- 压测:消息 TPS 达到目标(5,000+/s)
- 故障演练:kill -9 connector,客户端 60s 内重连成功
- 内存泄漏:48 小时运行 Hazelcast 内存无无界增长
安全检查
- AUTH token 验证已开启(不可绕过)
- Dubbo 服务间鉴权 token 已配置(非空)
- 生产环境 WebSocket 使用 wss://(TLS)
- SQL 注入防护(MyBatis 参数绑定,无拼接 SQL)
- 敏感信息不出现在日志中
可运维性
- 每个服务有健康检查端点(Actuator /health)
- 关键日志有 traceId(消息 ID 可追踪全链路)
- JVM 参数已设置 HeapDump(OOM 时自动 dump)
- 数据库迁移脚本在 Flyway 中管理(有版本号)
AI 架构专项
- AI 请求超时已配置(防 Agent 服务慢响应阻塞线程)
- AI 线程池有界(防 OOM)
- Agent 服务不可用时有降级(友好提示而非异常)
- AI 上下文记忆按 userId 隔离(不同用户不串话)
总结
一个合格的架构师交付物不只是代码,更是:
- 可演进的分层架构 — 接入层无状态可水平扩展,业务层可从单实例演进到集群
- 清晰的接口契约 — Dubbo 接口、REST 规范、protobuf IDL,让各团队并行开发
- 量化的质量目标 — 110 万连接/节点、5,000 TPS,不是模糊描述
- 透明的技术决策 — 每个关键选型都有 ADR 记录背景、候选方案、决策理由
- 可操作的改进路径 — 从当前版本到近期、中期的演进步骤清晰
- AI 原生思维 — SAI 协议旁路推送、多 Agent 路由、本地 LLM 集成路线
完整源码参见 chat-server-pro,完整架构设计文档见项目 docs/ARCHITECTURE_DESIGN.md。