Apache kafka 如何使用Kafka流处理无序的事件
我有一个应用程序,其中基于用户操作(如用户登录、用户中间操作(可选)和用户注销)发送卡夫卡主题的事件。每个事件在事件对象中都有一些信息以及userId,例如登录事件有loginTime;添加注释具有注释(中间操作)。类似地,注销事件具有logoutTime。需求是在接收到每个用户的注销事件并将其发送到下游后,将所有这些事件中的信息聚合到一个对象中 由于某些原因(网络延迟、多个事件生成器),事件可能没有按顺序出现(用户注销事件可能出现在中间事件之前),因此问题是如何处理此类场景?我不能在收到用户注销事件后等待中间事件,因为根据用户的操作,中间事件是可选的Apache kafka 如何使用Kafka流处理无序的事件,apache-kafka,apache-kafka-streams,Apache Kafka,Apache Kafka Streams,我有一个应用程序,其中基于用户操作(如用户登录、用户中间操作(可选)和用户注销)发送卡夫卡主题的事件。每个事件在事件对象中都有一些信息以及userId,例如登录事件有loginTime;添加注释具有注释(中间操作)。类似地,注销事件具有logoutTime。需求是在接收到每个用户的注销事件并将其发送到下游后,将所有这些事件中的信息聚合到一个对象中 由于某些原因(网络延迟、多个事件生成器),事件可能没有按顺序出现(用户注销事件可能出现在中间事件之前),因此问题是如何处理此类场景?我不能在收到用户注
在这里,我认为唯一的选择是在收到用户注销事件后等待一段时间,如果在该等待时间内收到,则处理中间事件并发送已处理的事件,但同样不确定如何实现这一点。
Kafka
不保证主题上的顺序,它保证分区上的顺序。一个主题可以有多个分区,因此使用您的主题的每个使用者都将使用一个分区。这就是卡夫卡实现可伸缩性的方式。所以你所经历的是正常的行为(它不是bug或与网络延迟或类似的事情相关)。您可以做的是确保所有要按顺序处理的消息都发送到同一分区。您可以通过将分区数设置为1来实现这一点,这是最愚蠢的方法。当您使用producer发送消息时,默认情况下kafka会查看密钥,对其进行散列,并通过该散列知道应该在哪个分区上发送消息。您可以确保所有消息的密钥都相同。这样,所有密钥的散列都将是相同的,所有消息都将转到同一分区。此外,您还可以实现自定义分区器,并覆盖kafka选择哪个分区消息的默认方式。这样,所有消息都将按顺序到达。如果您不能执行这些操作,那么您将收到无序的事件,您必须考虑如何无序地使用它们,但这与卡夫卡无关。如果您无法保持事件的顺序(注销将是最后一个事件),
您可以使用Kafka Streams实现您的需求。Kafka Streams DSL可以与处理器API结合使用(更多详细信息)
您可以有多个分区,但特定用户的所有事件都必须发送到同一分区
您必须实现自定义处理器/转换器。
您的处理器将把每个事件/活动放入状态存储(将特定用户的所有事件聚合到同一个键下)。
处理器API使您能够创建某种调度器()。
您可以为特定用户安排每X秒检查一次事件。如果注销早在很久以前,您将获得所有事件/活动,并进行一些聚合,并将结果发送到下游。如其他答案所述,在卡夫卡中,顺序是基于每个分区维护的
既然您正在谈论用户事件,为什么不将UserID作为您的卡夫卡主题键?因此,与特定用户相关的所有事件都将始终被订购(前提是它们由单个生产者生产)
您应该确保(按设计)只有一个卡夫卡制作人将所有用户更改事件推送到给定主题。通过这种方式,您可以避免由于多个生产者而导致的无序消息
在streams中,您可能还希望查看Kafka streams中的窗口。例如,非重叠和固定大小。您可以在一段时间内聚合记录
现在,您可能希望按照时间戳(或者您说您有注销时间、登录时间等)对聚合的数据进行排序,并相应地采取行动
简单有效的解决方案
使用同步发送并将delivery.timeout.ms
和retries
设置为最大值。
要确保容错,请使用min.insync.replicas=2
(主题配置)设置acks=all
,并使用单个生产者推送到该主题。
您还应该将max.block.ms
设置为某个最大值,以便在获取元数据时出现错误时(例如,当Kafka关闭时),您的send()
不会立即返回
将同步发送与您的速率进行基准测试,并检查它是否符合您的要求或基准数字
这样可以确保先发的消息首先发送给卡夫卡,然后在成功确认前一条消息之前,不会发送下一条消息
如果你的基准数据没有达到,试试背压
类似内存/持久队列的机制
将事件添加到线程1中的队列
线程2中队列中的Peek(非出列)事件
在线程2中调用producer.send(…).get()
将线程2中的事件出列
您能详细解释一下,您想说什么吗?@Swapnil,请先阅读附件中的链接,然后如果您有任何问题,请询问我Superss API是否应该允许用户传递自定义逻辑(就像窗口聚合),但这与卡夫卡无关
——为什么不?这是绝对相关的!