我们有一个带有两个消费者的Kafka队列,这两个消费者都从同一个分区读取(扇出场景(。其中一个消费者应该是金丝雀,处理1%的消息,而另一个则处理剩下的99%。
其想法是根据消息的属性做出决定,例如消息ID或时间戳(例如mod 100(,并根据该属性接受或放弃,只是金丝雀和非金丝雀的逻辑相反。
现在,我们面临的问题是如何稳健地做到这一点,例如,在运行时重新配置百分比,避免丢失消息或处理它们两次。这似乎升级为一个分布式共识问题,以保持决策逻辑的同步,这是我们非常希望避免的,尽管我们可以使用ZooKeeper来实现这一点。
这是一个可行的策略吗?或者有更好的方法吗?可能是一个避免达成共识的问题?
更新:不幸的是,Kafka集群不在我们的控制之下,我们无法进行任何更改。
更新2消息的延迟不是一个大问题,添加几百个100ms是可以的,不会被注意到。
我看不出有任何方法可以在不"忽略"或双重处理记录的情况下更改两台机器之间的"采样策略"。由于不同的Kafka消费者可能在分区中处于不同的位置,也可能在不同的时间获得新的配置,因此您不可避免地会遇到以下两种情况之一:
- 两台机器对同一记录进行双重处理
- "跳过"记录,因为两台机器都不认为看到它时应该"拥有"它
我建议对您的架构进行一个小的更改:
- 让99%的机器(非金丝雀(拾取所有记录,然后决定是否要处理每个记录,或者它是否属于金丝雀
- 如果它属于金丝雀,则将记录发送到第二个主题(来自99%的机器(
- Canary机器只监听第二个主题,并处理每个到达的记录
现在您有了一个管道设置,其中只在一个点上做出决策,不会遗漏或重复处理任何记录。
明显的缺点是金丝雀机器的延迟更高。如果你绝对不能容忍延迟,那么就把制作哪个主题的决定推到制作人的上游?(我不知道这对你来说有多可行(
不允许第二个主题时的变体
如果(正如你上面所说的(你不能有第二个主题,你仍然可以只在99%的机器上做出决定,那么对于需要进入金丝雀的记录,用某种"标记"(在有效负载中或作为kafka标头,由你决定(将它们重新生成到原始分区中。99%的机器将忽略任何带有标记的传入记录,金丝雀机器将仅处理带有标记的记录。
同样,主要的缺点是增加了延迟。