系统设计:基于API Gateway/SQS的AWS聊天应用服务端消息推送实现
AWS架构下类WhatsApp即时通讯系统的消息推送与群聊实现
核心疑问直接答复
- 关于EC2能否直接调用API Gateway完成推送:可以,但不需要调用自定义业务路由。AWS WebSocket API Gateway原生提供了
@connections专用控制接口,EC2只要拿到接收方的有效连接ID,直接向该接口发HTTP POST请求即可触发推送,API Gateway会自动完成连接路由,不需要你额外在网关层写转发逻辑。 - 关于是否需要缓存层存储连接详情:必须要,这是推送链路能跑通的核心依赖。API Gateway本身不会持久化维护「用户ID-连接ID」的映射关系,没有这层存储你根本无法定位消息要推给哪个在线连接。
单聊场景端到端推送实现流程
整个流程完全适配现有参考架构,不需要推翻原有SQS+EC2+DB的设计,只需要补全连接管理和推送逻辑:
- 连接生命周期管理
- 用户端携带鉴权Token发起WebSocket连接到API Gateway,网关触发
$connect系统路由,将连接事件投递到SQS队列。EC2轮询拿到事件后,先校验Token合法性拿到对应用户ID,再将用户ID: 连接ID集合的键值对写入ElastiCache(Redis,AWS托管缓存服务),给键设置和WebSocket空闲超时一致的TTL,自动清理过期死连接。如果用户多端登录,同一个用户ID下会存多个连接ID,后续推送时遍历下发即可。 - 用户主动断开连接或者网络超时断连时,API Gateway会触发
$disconnect系统路由,同样投递事件到SQS,EC2拿到后从Redis中删除对应的连接ID,避免向无效连接发请求。
- 用户端携带鉴权Token发起WebSocket连接到API Gateway,网关触发
- 消息上行处理
- 发送方通过已建立的WebSocket连接发送消息,API Gateway将包含发送方连接ID、消息体、接收方ID的请求投递到SQS。EC2轮询拿到消息后,先做权限校验(比如判断双方是不是好友、有没有被拉黑),再将消息持久化到数据库(RDS/DynamoDB都可以,存消息记录、会话列表、未读计数),这一步就是原有方案里提到的「存入DB」环节。
- 消息下行推送
- EC2完成消息持久化后,直接从Redis查询接收方ID对应的在线连接ID集合:
- 如果查到有效连接ID,EC2通过AWS SDK直接调用
@connections接口,向https://<你的API网关ID>.execute-api.<区域>.amazonaws.com/<阶段名>/@connections/<目标连接ID>地址POST消息内容,API Gateway收到请求后会自动将消息推送给对应在线客户端。注意给EC2绑定的IAM角色加上execute-api:ManageConnections权限,SDK会自动处理请求签名,不用自己写签名逻辑。 - 如果没查到有效连接ID,说明接收方当前离线,EC2更新数据库里的接收方未读计数,同时对接APNS/FCM等系统推送通道,给接收方发离线通知栏推送,等用户下次上线建立连接时,再主动拉取所有未读消息即可。
- 如果查到有效连接ID,EC2通过AWS SDK直接调用
- EC2完成消息持久化后,直接从Redis查询接收方ID对应的在线连接ID集合:
群聊功能适配方案
完全可以复用现有单聊链路,只需要补全群维度的逻辑,不需要做架构重构:
- 先存储群基础元数据:数据库里单独存群ID、群成员列表、群设置、群公告这类信息,成员规模小的群可以把成员列表缓存到Redis,减少推送时的DB查询压力。
- 群消息上行处理:发送方发消息时携带群ID,EC2拿到消息后先校验发送方是否为群成员,再将群消息持久化到数据库,之后拉取该群的全量成员ID列表,批量去Redis查询每个成员的在线连接ID。
- 分场景做推送优化:
- 百人以内的普通群:EC2直接批量调用
@connections接口,给所有在线成员推送消息,离线成员更新未读计数+发系统推送即可,逻辑和单聊差异不大。 - 千人/万人级别的大群:不要让处理通用消息的EC2直接做全量推送,避免阻塞单聊消息处理。可以新增专门的群聊推送SQS队列,EC2存完大群消息后,只需要把「群ID+消息ID」扔到这个队列,由一组独立的推送消费者EC2分片拉取群成员列表,并行完成推送,大幅提升推送效率。
- 百人以内的普通群:EC2直接批量调用
- 常规优化点:可以给群消息做预扇出,用户上线时提前同步已加入群的最新消息位点,避免每次拉取群消息都扫描全量消息表,降低数据库压力。

内容的提问来源于stack exchange,提问作者Ryan
相关产品推荐
相关产品推荐

