用Kafka进行数据建模?主题和分区


168

使用新服务(例如非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吗?viewedat?分区呢?

我该如何决定?


3
奇怪的是谈论主题和分区,但不一定讨论其中的数据演变。如果您想将用户代理或标题附加到那些“用户视图”事件上,该怎么办?您如何发展并将其传达给下游消费者?
OneCricketeer

Answers:


136

在为Kafka构建数据时,它实际上取决于数据的使用方式。

在我看来,主题是一组将由相同类型的消费者使用的相似类型的消息,因此在上面的示例中,我将只有一个主题,并且如果您决定推送某种其他类型的消息,通过Kafka获取数据,以后可以添加一个新主题。

主题已在ZooKeeper中注册,这意味着如果尝试添加过多主题,则可能会遇到问题,例如,如果您拥有一百万个用户,并决定为每个用户创建一个主题。

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

可以使用生产者端的分区键显式设置分区,或者如果未提供分区,则会为每条消息选择一个随机分区。


5
因此,与其使用主题作为获取每个用户ID数据的方式,而不是让Zookeeper感到不知所措,不如按用户ID进行分区,并让基于用户ID的使用者订阅每个分区更好吗?
拉文德拉纳特·阿基拉


4
@RavindranathAkila Kafka is designed to have of the order of few thousands of partitions roughly less than 10,000. And the main bottleneck is zookeeper. A better way to design such a system is to have fewer partitions and use keyed messages to distribute the data over a fixed set of partitions. 让我认为它不是您所描述的正确工具-但更多的是,主题将是“页面查看事件”?并且所有页面浏览量都将位于该“主题”中。分区似乎更多地涉及并行性,副本和内容?
Dembinski

谢谢:)最后我有一个答复:P
Ravindranath Akila 18'Jan

62

一旦知道如何对事件流进行分区,主题名称将变得很容易,因此让我们首先回答该问题。

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

例如:

  1. 如果您关心用户的平均网站停留时间,则应按进行分区:user-id。这样,与单个用户的站点活动有关的所有事件将在同一分区中可用。这意味着像Apache Samza这样的流处理引擎仅通过查看单个分区中的事件就可以计算给定用户的平均现场停留时间。这样可以避免执行任何昂贵的分区全局处理
  2. 如果您关心网站上最受欢迎的页面,则应按页面进行分区:viewed。同样,Samza将仅通过查看单个分区中的事件就能够保留给定页面的视图计数

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

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

在主题名称-在这里一个明显的例子是eventsuser-events。更具体地说,您可以使用events-by-user-id和/或events-by-viewed


8
我已经看到了将事件发布到两个主题的参考:每个工人一个/预期用途。在这种情况下,可能会有两个主题,并且具有两种不同的分区方案。
弗朗索瓦·博索里尔

7

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

关键要点:

  • 通常,Kafka群集中的分区越多,可以实现的吞吐量就越高。设单个分区上可实现的最大最大值为p,消耗量为c。假设您的目标吞吐量为t。然后,您至少需要有max(t / pt / c)个分区。

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

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

  • Kafka中的端到端延迟是由生产者发布消息到消费者读取消息的时间定义的。根据经验,如果您关心延迟,将每个代理的分区数限制为100 x b x r可能是一个好主意,其中b是Kafka集群中代理的数量,r是复制因子。


4

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

一个主题可以有很多分区。分区有利于并行性。分区也是复制的单元,因此在Kafka中,领导者和跟随者也被称为分区级别。实际上,分区是一个有序队列,其顺序是消息到达顺序。主题由一个或多个简单的词组成。这对我们建模结构很有用。

Kafka由LinkedIn开发,用于日志聚合和传递。这个场景是很好的例子。

您的Web或服务器上的用户事件可以通过Web服务器记录下来,然后通过生产者发送给Kafka经纪人。在生产者中,您可以指定分区方法,例如:事件类型(不同的事件保存在不同的分区中)或事件时间(根据您的应用程序逻辑将一天划分为不同的时间段)或用户类型或仅无逻辑并平衡所有日志分成许多分区。

关于您所讨论的情况,您可以创建一个名为“ page-view-event”的主题,并通过哈希键创建N个分区,以将日志平均分配到所有分区中。或者,您可以选择分区逻辑以根据自己的意愿进行日志分发。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.