Kafka在时间戳方面消耗了多个主题

时间:2018-04-16 22:45:23

标签: apache-kafka

我需要创建一个能够从多个主题中提取并根据时间戳(Kafka消息时间戳)订购消息的消费者

有点像: enter image description here (抱歉画画不好......)

在这个例子中,我订阅了#34;主题A"和#34;主题B"并按照时间戳的顺序对消息进行排队

现在,只要所有主题只有一个分区,这个伪代码很容易解决:

kafka.subscribe(['topicA', 'topicB'])
messagesByTopic = {}
finalMessageQueue = []
while true:
    records = kafka.poll()
    for record in records:
        messagesByTopic[record.topic()].enqueue(record)

    while messagesByTopic.any(queue => !queue.notEmpty()):
        minQueue = messagesByTopic.min(queue => queue.peek().timestamp)
        finalMessageQueue.enqueue(minQueue.pop())

当我为每个主题引入多个分区时,会出现问题。 显然,不可能将多个主题排序为按时间排序的单个流,因为在主题内部,仅在分区内部不保证顺序,因此新问题是将多个主题排序为具有相同密钥的流。

enter image description here

想象一下2个主题,订单和退出 主题内的消息的关键是交易所属的客户ID。

目标是将所有主题流式传输到队列中(每个客户一个),按时间戳排序。

理论上应该是可能的,因为订单和提取主题中的消息按每个客户的时间戳排序,事实上,当处理每个主题的单个分区时,这个问题很容易解决。

现在,考虑2个订单分区和1个撤销分区的情况, 如果我有两个进程同时运行会发生什么?一个流程将取消所有客户,但只有一半客户的订单,第二个流程只有一半客户的订单,它会分开。

唯一的方法是以某种方式告诉Kafka确保相同的密钥(即使来自不同的主题)将始终路由到同一个进程,但据我所知,没有办法做到这一点。

我被困住了。 我需要了解如何处理它。

1 个答案:

答案 0 :(得分:1)

为了达到预期的效果,您应该通过更改生产者对消息进行分区的方式,或者在订购逻辑之前将原始主题中的数据重新划分为新的中间主题来确保两个主题之间的分区对应。 理想情况下,两个主题的分区之间会有一对一的对应关系。通常,您的并行性(线程数)受两个主题的分区计数之间的最高公因数限制,例如如果订单主题有12个分区且提取主题有9个,那么您可以将分区分配给HCF(12,9)= 3个线程,如下所示: 线程1:订单分区(0,1,2,3),提款分区(0,1,2) 线程2:订单分区(4,5,6,7),提款分区(3,4,5) 线程3:订单分区(8,9,10,11),提款分区(6,7,8) 为此,您需要为两个主题而不是默认主题实现自定义分区。

但是,如果一个主题有1个分区而另一个主题有2个,则HCF(1,2)为1,这意味着您只能以单线程方式执行此操作。