1.聊天系统架构设计总览
1.1 知识点
需求分析
聊天系统在实际游戏中,会遇到各种功能和性能需求,包括但不限于:
- 地图聊天
向同一个场景/地图中的所有玩家广播消息,需优化广播性能与服务器负载。 - 世界广播
向全服玩家发送重要公告或活动信息,优先级管理与实时推送至关重要。 - 私聊
一对一安全私密通信,需对接收方在线状态进行校验并支持双向回显。 - 群组聊天
支持队伍、公会、临时群组等多种群聊,涉及权限控制、成员管理与离线消息补发。 - 系统消息
道具变更、战斗记录等系统通知,结合事件驱动与消息队列实现可靠下发。 - 广播系统
跑马灯、滚动公告、大喇叭、置顶消息等多样化播报形式,需设计优先级排序和频道管理。 - 自定义消息
表情、装备信息、动图、超链接、语音、游戏功能链接等富媒体内容支持,要求灵活拓展与兼容。 - 聊天节点事件
点击链接打开界面、跳转到地图、使用物品等互动事件,需事件驱动模型与易维护的解析机制。 - 高并发与限速
多人同时发言、刷屏控制、聊天 CD、敏感词过滤、黑白名单等防护与限流策略。 - 可扩展性
多 Chat 服集群、动态路由、热更新、离线消息存储与拉取能力。 - 离线聊天
使用数据库存储离线聊天消息,用户上线时拉取。
设计思路
聊天系统需要在高并发、低延迟和可扩展的前提下,支持地图聊天、世界广播、私聊、群组、系统消息等多种场景。总体上,我们采用了分层设计:
- 客户端负责 UI、协议封包与解包、心跳维护等基础能力。
- Gate 服务器负责路由、会话管理以及向后端服务器(Chat/Map)中转聊天协议。(Gate部分详看注册登录,这里只讨论专注于聊天的实现)
- Chat 服务器作为聊天中枢,管理在线聊天单元(ChatUnit)、频道(ChatChannel)、聊天消息包解析与分发;并对外提供路由接口供 Gate 和其他服调用。
- Map/Game 服务器在收到游戏逻辑触发的系统或世界广播时,通过内网路由将消息推送至 Chat,再由 Chat 分发;或直接将 Chat 消息下发给指定客户端。
这种分层将业务逻辑(聊天分发、频道管理)和网络路由(Gate 中转、RouteComponent 自动转发)解耦,使系统具备灵活扩展多 Chat 节点、支持动态热更、并能在单 Chat 服承载数万在线玩家的场景下依然保持稳定。
注意:所有客户端 ↔ 后端通信均通过 Gate,Chat 与 Map 发回客户端也借助 Gate 转发,保证通道一致、监控可控。
架构图概览
graph LR subgraph 客户端 direction TB ChatClientScene["ChatClientScene"] Serializer["SerializerComponent"] ClientSession["ClientSession"] ChatClientScene -->|"挂载"| Serializer ChatClientScene -->|"创建"| ClientSession end subgraph Gate服 direction TB GateScene["GateScene"] GateUnitManage["GateUnitManageComponent"] GateSession["GateSession"] GateFlag["GateUnitFlagComponent"] GateUnit["GateUnit"] RouteComp["RouteComponent"] GateScene -->|"挂载"| GateUnitManage GateScene -->|"创建"| GateSession GateSession -->|"挂载"| GateFlag GateSession -->|"绑定路由"| RouteComp GateSession -->|"关联"| GateUnit GateUnitManage -->|"管理"| GateUnit end subgraph Chat服 direction TB ChatScene["ChatScene"] Serializer2["SerializerComponent"] ChatUnitManage["ChatUnitManageComponent"] ChatSession["ChatSession"] ChatUnit["ChatUnit"] ChatChannelCenter["ChatChannelCenterComponent"] ChatChannel["ChatChannel"] ChatRouteId["ChatRouteId"] ChatScene -->|"挂载"| Serializer2 ChatScene -->|"挂载"| ChatUnitManage ChatScene -->|"挂载"| ChatChannelCenter ChatScene -->|"创建"| ChatSession ChatSession -->|"注册路由 ChatUnitRuntimeId 返回给 Gate"| ChatRouteId ChatChannelCenter -->|"申请/解散"| ChatChannel ChatChannel -->|"Unit 字典"| ChatUnit ChatUnitManage -->|"管理"| ChatUnit ChatUnit -->|"Channel 字典"| ChatChannel end subgraph Map服 direction TB MapScene["MapScene"] MapSession["MapSession"] MapRouteId["MapRouteId"] MapScene -->|"创建"| MapSession MapSession -->|"注册路由 MapUnitRuntimeId 返回给 Gate"| MapRouteId MapSession -->|"Other2Chat_ChatMessage"| ChatSession end %% 消息流 ClientSession -->|"C2Chat_SendMessageRequest"| GateSession GateSession -->|"Route → Chat (via RouteComponent)"| ChatSession GateSession -->|"Route → Map (via RouteComponent) (上线时 Map 记录 ChatUnitRouteId)"| MapSession ChatChannel -->|"innerRoute(Chat2C_Message)"| GateSession GateSession -->|"Route back to Client"| ClientSession
核心模块职责
客户端
- 构造
ChatInfoTree
(一个聊天消息包),逐步添加ChatInfoNode
(聊天信息节点)后发生聊天消息包。 - 一个
ChatInfoTree
包括多个ChatInfoNode
。ChatInfoNode
有不同类型,包括文本、位置、链接,图片,标签等。 - 聊天相关的信息,如枚举,
ChatInfoTree
,ChatInfoNode
应该是和双端一致的。另一端主要是聊天服使用。 - 客户端和服务端都添加
SerializerComponent
对聊天消息进行序列化和反序列化。 - 通过 KCP/TCP 将
C2Chat_SendMessageRequest
发给 Gate。Gate会进行路由。 - 解析
Chat2C_Message
,收到消息后解析ChatInfoTree
,再在客户端进行处理。
Gate 服务器
- GateUnitManageComponent:内存缓存所有在线用户的 GateUnit。
- GateUnit:一个Gate用户,包括用户名,关联的Session,路由字典等。路由字典的key是服务器类型,值是对应服务器Unit。方便下线时发消息通知其他服务器Unit下线。
- GateUnitFlagComponent:会话绑定,让Session直接可以知道对应的GateUnitId,断开Session触发下线逻辑时直接可以基于GateUnitId通知GateUnitManageComponent。
- RouteComponent:自动将客户端请求路由到 Chat 或 Map,并把后端响应转回客户端。会维护一个路由字典,类型是SceneType->其他服的Unit的RunTimeID。这样方便直接找到对应的Unit进行通信。注意Id是最好各个服的Unit保持一致,RunTimeId是用于通信的。
Chat 服务器
- ChatUnitManageComponent:管理 ChatUnit(用户在 Chat 服的身份与路由 ID)。
- ChatUnit:管理 ChatUnit(用户在 Chat 服的身份与路由 ID)。存储GateRouteId(Gate的session.RunTimeId)方便发消息时路由。还包括ChannelDict存储假如的Channel。还可以拓展存储发送消息的时间避免频繁发送消息。
- ChatChannelCenterComponent:申请/销毁频道(世界、队伍、公会、地图等)。使用字典管理ChatChannel。
- ChatChannel:频道内成员列表、广播消息实现。
- ChatSceneHelper:核心分发
Distribution(chatUnit, tree)
,按频道类型调用Broadcast
,Channel
,Private
等。核心思路就是找对应的ChatUnit的GateRouteId发给Gate,Gate再转给客户端。
Map/Game 服务器
- 上线时,Gate的会发送chatUnitRouteId(chatUnit.RunTimeId)给Map记住,这样战斗服想聊天时也可以聊天。
- 处理游戏触发的系统广播或世界聊天,使用
ChatHelper.SendChatMessage(scene, chatUnitRouteId, tree)
推送至 Chat,Chat转给Gate,Gate再转客户端。
总结
- 分层解耦:客户端、Gate、Chat、Map 各司其职,逻辑清晰、易维护。
- 路由中转:Gate 通过 RouteComponent 做透明转发,Chat 侧只关注业务分发。
- 内存管理:GateUnit/ChatUnit 缓存结合超时组件,实现延迟下线与热重载友好。
- 消息树协议:双端共享的 ChatInfoTree、ChatNodeFactory、ChatNodeEventHelper,保证一致性与灵活扩展。
- 拓展和展望:暂时没有做离线聊天,离线聊天需要数据库支持,才能让好友上线时收到消息,并且成本会加
后续将深入拆解 Gate 服设计、消息包(消息树)设计、Chat 服核心逻辑与其他服触发场景。
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com