跳转至

Websocket

为什么需要 websocket

在直播间聊天的场景下,一个用户的发言其他用户需要立刻看到:

  • 如果用 HTTP 轮询:观众每隔 1 秒发一个请求,请求最新的消息 → 延迟大 + 服务压力爆炸。

    http 是单向触发的,在应用中只能客户端发送请求,服务端响应,如果服务端硬想向客户端推消息:

    • 客户端必须自己跑 HTTP Server
    • NAT/防火墙大概率拦截客户端的消息

    本质上还是要有一种通用的协议,让客户端去支持接收主动推送

  • 如果用 长轮询(Comet):连接挂着,等有消息再返回 → 还是要重新建立连接(握手开销大)。

而 WebSocket 就是为了解决这个问题:

  • 用户进入直播间,建立连接,先走一次 HTTP 握手(方便穿过代理、防火墙)。
  • 成功后,升级为 WebSocket 协议(全双工、持久连接)。
  • 之后,客户端和服务端都能主动推消息,不用反复建连接。

微服务架构下的设计

推送服务多实例

在后台服务有多个实例的情况下,不会让一个客户端同时与同一个服务的多个实例分别建立 ws 连接,此时可以添加一层中间层:wsproxy 服务,作为专门处理 ws 连接的代理。

wsproxy 服务本身作为一个协议转换和消息转发的服务:

  • 面向客户端,管理和维护大量 WebSocket 长连接
  • 面向后台服务,提供 HTTP 推送接口供后台进行推送

代理服务多实例

同时,需要注意到,wsproxy 服务本身也需要部署多个实例,所以,当后台服务需要主动推送消息到前端时,一个重要的问题就是,相应的连接是由哪个 wsproxy 服务来维护:

对 user ID 取一致性 hash 值,对 hash 值取模与一个 wsproxy 进程相一一对应,当后台需要主动推送消息时,到 Redis 或注册中心去找 wsproxy 服务的实例

推送服务的同步

比如,在弹幕的场景下,需要通过 websocket 实现实时的推送功能,同时需要有一个多个服务实例的广播机制来统一数据

image-20250824205451776

另外,这里还需要一个旁路的持久化逻辑,来做一个弹幕数据的异步存储:

使用 Redis List + Kafka 异步消费落库