好记性不如烂笔头,趁热记录下,给未来的自己。
0 | 前言
在项目迭代的过程中,有些业务场景,比如客户端(浏览器)需要定期的获取后端的数据,一般比较常规的方式是通过客户端 long polling 的方式。除了这种方式外,还可以通过 Server-Send-Event(SSE)或者 WebSocket 的方式,更加实时的获取后端的数据。
其中:
- SSE
- 是流式单工的(服务端 -> 客户端)
- 基于 HTTP 协议 (很重要)
- 适合客户端监听,服务端主动推消息的场景,如获取日志信息,获取通知消息等
- WebSocket
- 是流式双工的(服务端 <-> 客户端)
- 基于 WS 协议,由 HTTP 协议升级而来,所以在比较复杂的部署架构里(有 LB,WAF,Gateway 等),需要整个链路上的中间件都支持 ws 协议
- 适合前后端交互频繁且实时的场景,如在线聊天
SSE 虽然是单工的,但是可以模拟双工通信,如客户端->服务端,可以发送 HTTP POST请求的方式操作。
本文将使用 SSE 来模拟客户端、服务端的双工通信。
1 | 方案说明
市面上现有的 SSE 技术文章,都是针对单副本服务展开的。如果需要水平扩展服务的副本数,那些方案就无法满足需求了,因为 SSE Emitters 容器是一个本地容器,多副本之间无法共享各自的本地容器,所以,当客户端订阅和发布消息的请求被调度到不同的副本上时,就会出现订阅消息无法推送到客户端问题。
那么如果需要水平扩展服务,来满足分布式 SSE 架构,该如何设计呢?
这里,可以引入 MQ,如 Kafka,来满足需求。大概流程如下:
- 客户端发起订阅请求,服务端将订阅信息存储在本地容器里;
- 客户端发送消息;
- 服务端接收消息,塞入 MQ;
- 服务端订阅 MQ topic,并接收消息;
- 服务端判断接收到的消息是否可以由本实例副本推送 SSE 到客户端(通过消息里的 clientId 从容器中拿 Sse Emitter 对象的方式);
- 如果本实例副本判断可以推送 SSE 消息,则执行;如