我正在研究一种简单的解决方案,其中生产者服务将事件推送到消息队列,然后让流服务通过gRPC流API使这些事件可用。
Cloud Pub / Sub似乎非常适合这项工作,但是扩展流服务意味着该服务的每个副本都需要创建自己的订阅并在缩减之前将其删除,这似乎不必要地复杂,而不是平台的意图
另一方面,Kafka似乎可以很好地处理此类问题,但我想避免不得不管理底层平台本身,而是利用云基础架构。
我还应该提到拥有流API的原因是允许流向前端(可能无法访问底层基础结构的流)
是否有更好的方法可以在不使用部署和管理自己的基础架构的情况下使用GCP平台执行类似的事情?
答案 0 :(得分:2)
如果您本质上需要临时订阅,那么在创建订阅时可以在Subscription对象上进行一些设置:
将expiration_policy
设置为较小的持续时间。当订阅者在该时间段内未收到消息时,订阅将被删除。权衡是,如果您的订户由于持续时间长于此时间段的暂时性问题而关闭,则该订阅将被删除。默认情况下,有效期为31天。您可以将其设置为低至1天。对于请求订阅者,订阅者仅需停止向Cloud Pub / Sub发出请求,以在其到期时启动计时器。对于推送订阅,计时器基于没有成功将消息传递到端点的时间来启动。因此,如果没有消息发布,或者端点为所有推送的消息返回错误,则计时器有效。
减少message_retention_duration
的值。这是在订户未收到消息并确认消息的情况下保留消息的时间段。默认情况下,这是7天。您可以将其设置为10分钟。折衷方案是,如果您的订户断开连接或在处理消息方面落后于此持续时间,则早于该消息的消息将被删除,订户将看不到它们。
完全关闭的订阅者可能会自己调用DeleteSubscription以便订阅立即消失,但是对于那些意外关闭的订阅者,设置这两个属性将最大限度地减少订阅继续存在的时间和消息数量(永远不会交付)将被保留。
请记住,Cloud Pub/Sub quotas限制每个主题和每个项目一个到10,000个订阅。因此,如果创建了很多订阅,并且它们是活动的或未清除(手动,或者在expiration_policy
的{{1}}通过之后自动清除),则可能无法创建新的订阅。
答案 1 :(得分:0)
我认为你最初的想法比临时订阅更好。我的意思是它有效,但感觉完全不自然。看你的要求是什么。例如,客户端是否只需要在连接时接收消息,还是都需要获取所有消息?
你最初的想法是更好的imo。我可能会做的是创建一个客户端可以连接到的 gRPC 流服务。实现本质上是一个观察者模式。消费者将收到一条消息,然后遍历订阅者对所有订阅者进行“发送”。从那里,任何时候客户端连接到服务,它只是向观察者集合注册自己,并在断开连接时取消注册。水平扩展是被动的,因为客户端会粘在他们连接到的任何实例上。
这个概念与上面的类似,但客户端不会在断开连接时隐式地从观察者那里取消注册。相反,它将显式注册和取消注册(通过设计用于这样做的方法/命令)。修改“on disconnected”逻辑以告诉观察者列表客户端已离线。那么消费者的广播逻辑就略有不同。现在它遍历列表并说“如果在线,则发送,否则排队”,并将消息发送到临时队列(属于客户端)。然后,您的“连接时”逻辑会将队列中的所有消息发送到客户端,然后再通知消费者它已重新上线。基本上是一个收件箱。在 RabbitMQ 等大多数产品中,设置临时的、自删除的队列非常容易。我认为你必须做一些管理是否可以删除队列。例如,除非客户端明确取消订阅或长时间处于非活动状态,否则永远不要删除队列。不这样做,整个收件箱的想法就会崩溃。
上面选择的答案与我在这里订阅的最相似,因为订阅是队列。如果我这样做,那么我可能会将它实现为内部总线而不是观察者(因为它是不必要的)-您可以按需为连接客户端创建一个消费者,该消费者实际上只是转发消息。消息消费者根据客户端是否连接来订阅和取消订阅。正如 Kamal 所指出的,如果您的规模超过了 pubsub 允许的最大订阅数,您就会遇到问题。如果你发现自己处于那个位置,那么你可以通过实现上面的模式来解除这个限制。这基本上是相同的模式,但您将责任转移到您的基础设施上,唯一的限制是您自己的资源。
gRPC 使这种机制变得非常简单。或者,对于 Web,如果您使用的是 Microsoft 堆栈,那么 SignalR 也可以让这一切变得非常简单。客户端连接到集线器,您可以发布到所有连接的客户端。此处的消费者模式基本保持不变,但您不必手动实现观察者模式。
(注意:图中箭头是依赖方向,不是数据流)