【问题标题】:How to maintain SseEmitters list between multiple instances of a microservice?如何在微服务的多个实例之间维护 SseEmitters 列表?
【发布时间】:2019-05-18 15:15:42
【问题描述】:
语言:Spring Boot,JS
概述:我正在我的应用程序中实现服务器发送事件功能,该功能将部署在 Cloud Foundry 中,
其中基于队列中的新消息(我已在我的微服务中订阅),我将向我的客户端/浏览器(使用 EventSource)发送一些更新。
为此,我在服务器端维护了一个 SseEmitters 列表(用于维护所有活动的 SseEmitter)。一旦我从队列中收到一条新消息,基于 id(队列消息中的一个字段),我会将消息发送到相应的客户端。
问题:当我通过创建多个实例来扩展我的应用程序时,上述方案将如何工作。由于只有一个实例会收到新的队列消息,可能会发生 active SseEmitter 在该特定实例中没有维护,我该如何解决?
【问题讨论】:
标签:
java
spring-boot
microservices
spring-cloud
server-sent-events
【解决方案1】:
为了解决这个问题,可以观察以下方法。
DNS 概念
如果您仔细想想,知道您的用户(SSE 发射器)在哪里,就像知道某个网站在哪里一样。您可以使用 DNS-look-alike 协议来确定您的用户在哪里。协议如下:
- 当用户登陆您的任何实例时,将用户与该实例相关联。关联可以通过使用外部组件来完成,例如Redis 或 Hazelcast 等分布式地图解决方案。
- 每当用户从 SSE 断开连接时,删除关联。有时没有使用 Spring SSEEmiter 正确注册断开连接,因此可以在 sendig 消息失败时进行解除关联。
- 其他方(微服务)可以轻松查询 Redis/Hazelcast 以确定用户所在的实例。
消息路由概念
如果您使用消息中间件在微服务之间进行通信,则可以使用 AMQP 协议提供的路由功能。协议如下:
- 每个 SSE 实例在启动时创建自己的队列
- 用户登陆任何 SSE 实例,实例添加交换队列绑定,路由键 = 用户 uid
- 每当用户从 SSE 断开连接时,删除关联。有时没有使用 Spring SSEEmiter 正确注册断开连接,因此可以在 sendig 消息失败时进行解除关联。
- 其他方(微服务)需要向交换机发送消息并定义路由密钥。 AMQP 代理根据路由键确定应该接收消息的队列。
在 RabbitMQ 等现代 AMQP 代理上,绑定不是资源密集型的。
您的问题很老,如果您现在还没有弄清楚,希望这会有所帮助。