基于卡夫卡主题和划分的数据建模

在使用新服务(如非 RDBMS 数据存储或消息队列)时,我首先考虑的事情之一是: “我应该如何构造我的数据?”.

我阅读和观看了一些入门材料,特别是以 分布式日志处理消息系统 Kafka为例,它写道:

  • “主题是与消息相关联的容器”
  • 最小的并行度单位是主题的分区。这意味着... ... 属于某个主题的特定分区的所有消息都将被某个消费者群体中的消费者消费。”

了解了这一点,有什么好的示例可以说明如何使用主题和分区?什么时候应该有一个话题?什么时候某个东西应该是一个分区?

例如,假设我的(Clojure)数据类似于:

{:user-id 101 :viewed "/page1.html" :at #inst "2013-04-12T23:20:50.22Z"}
{:user-id 102 :viewed "/page2.html" :at #inst "2013-04-12T23:20:55.50Z"}

主题是否应该基于 user-id? viewed? at? 那么分区呢?

我该怎么决定?

56539 次浏览

当构建卡夫卡的数据时,它实际上取决于如何使用它。

在我看来,主题是一组类似类型的信息,它们将被同一类型的消费者消费,所以在上面的例子中,我只有一个主题,如果你决定通过卡夫卡推送其他类型的数据,你可以稍后添加一个新的主题。

主题是在 ZooKeeper 中注册的,这意味着如果你试图添加太多主题,你可能会遇到问题,例如,你有一百万用户,并决定为每个用户创建一个主题。

另一方面,分区是并行消息使用的一种方法。代理集群中的分区总数至少需要与使用者组中的使用者数相同,才能理解分区特性。消费者组中的消费者将根据分区在他们之间分担处理主题的负担,这样一个消费者将只关心“分配给”的分区本身中的消息。

可以使用生成器端的分区键显式设置分区,或者如果没有提供分区,将为每条消息选择一个随机分区。

一旦您知道如何划分事件流,主题名称就很容易了,所以让我们先回答这个问题。

@ Ludd 是正确的-您选择的分区结构将在很大程度上取决于您希望如何处理事件流。理想情况下,您需要一个分区键,这意味着您的事件处理是 分区-本地

例如:

  1. 如果您关心用户的平均现场时间,那么您应该按 :user-id进行分区。这样,与单个用户的站点活动相关的所有事件都可以在同一个分区中使用。这意味着流处理引擎(如 Apache Samza)可以通过查看单个分区中的事件来计算给定用户的平均现场时间。这就避免了执行任何类型的代价高昂的 分区-全局处理
  2. 如果你关心你网站上最流行的页面,你应该按照 :viewed页面进行分区。同样,Samza 将能够仅通过查看单个分区中的事件来保存给定页面的视图计数

通常,我们尽量避免依赖全局状态(比如在 DynamoDB 或 Cassandra 这样的远程数据库中保存计数) ,而是能够使用分区-本地状态工作。这是因为 局部状态是流处理的基本原理

如果您同时需要上述两个用例,那么 Kafka 的一个常见模式是首先通过比如 :user-id进行分区,然后通过 :viewed进行 重新分区分区,为下一阶段的处理做好准备。

关于主题名称——这里一个显而易见的名称是 eventsuser-events。更具体地说,你可以选择 events-by-user-id和/或 events-by-viewed

我认为主题名称是一种消息的总结,生产者通过订阅主题向主题发布消息,消费者通过订阅主题发布消息。

一个主题可以有许多分区。分区有利于并行性。划分也是复制的单位,所以在卡夫卡中,领导者和追随者也是在划分的层次上说的。实际上,一个分区是一个有序的队列,其顺序是消息到达的顺序。主题由一个简单单词中的一个或多个队列组成。这对我们建模我们的结构很有用。

Kafka 由 LinkedIn 开发,用于日志聚合和发布。

用户的事件在您的网络或应用程序可以记录在您的网络服务器,然后发送到卡夫卡经纪人通过生产商。在生产者中,你可以指定分区方法,例如: 事件类型(不同的事件被保存在不同的分区中)或事件时间(根据你的应用程序逻辑将一天划分为不同的时间段)或者用户类型,或者只是没有逻辑并将所有日志平衡到多个分区中。

关于您遇到的问题,您可以创建一个名为“ page-view-event”的主题,并通过散列键创建 N 个分区,以便将日志均匀地分布到所有分区中。或者您可以选择一个分区逻辑来使日志按照您的精神分发。

这与问题并不完全相关,但是如果你已经决定了基于主题的记录的逻辑隔离,并且想要优化 Kafka 的主题/分区计数,那么 这个的博客文章可能会派上用场。

简而言之,关键要点是:

  • 一般来说,卡夫卡集群中的分区越多,可以实现的吞吐量就越高。让一个生产分区上可达到的最大值为 ,消耗为 。假设您的目标吞吐量是 。然后,您需要至少有最大(//)分区。

  • 目前,在卡夫卡,每个代理打开一个文件句柄的索引和数据文件的每个日志段。因此,分区越多,在底层操作系统中配置打开文件句柄限制所需的分区就越高。例如,在我们的生产系统中,我们曾经看到一个说 too many files are open的错误,而我们有大约3600个主题分区。

  • 当代理被不干净地关闭(例如 kill -9)时,观察到的不可用性可能与分区的数量成正比。

  • 卡夫卡中的端到端延迟是由生产者发布消息到消费者读取消息的时间来定义的。根据经验,如果您关心延迟,最好将每个代理的分区数限制在100 x B x R,其中 B是卡夫卡集群中的代理数,而 R是复制因子。