首页 文章

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

提问于
浏览
145

在使用新服务(例如非RDBMS数据存储或消息队列)时,我想到的第一件事是:“我应该如何构建我的数据?” .

我已经阅读并观看了一些介绍性材料 . 特别是,举例来说,Kafka: a Distributed Messaging System for Log Processing,写道:

  • "a Topic is the container with which messages are associated"

  • "the smallest unit of parallelism is the partition of a topic. This implies that all messages that ... belong to a particular partition of a topic will be consumed by a consumer in a consumer group."

知道这一点,什么是一个很好的例子,说明如何使用主题和分区?应该什么时候成为主题?什么时候应该是一个分区?

举个例子,假设我的(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 ?分区怎么样?

我该如何决定?

4 回答

  • 120

    在为Kafka构建数据时,它实际上取决于它的消费意义 .

    在我看来,一个主题是一组相似类型的消息将由同一类型的消费者使用,所以在上面的例子中,我只有一个主题,如果你决定推动其他类型的通过Kafka的数据,您可以稍后为其添加新主题 .

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

    另一方面,分区是一种并行化消息消耗的方法,并且代理群集中的分区总数需要至少与消费者组中的消费者数量相同才能理解分区功能 . 消费者群体中的消费者将根据分区将处理主题的负担分开,以便一个消费者仅关注分区本身中的消息被“分配给” .

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

  • 47

    这与问题并不完全相关,但如果您已经根据主题确定了记录的逻辑隔离,并希望优化Kafka中的主题/分区计数,this博客可能会派上用场 .

    简而言之:关键要点:

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

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

    • 当代理不正常关闭(例如,kill -9)时,观察到的不可用性可能与分区数成比例 .

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

  • 3

    我认为主题名称是一种消息的结论, 生产环境 者通过订阅主题向主题和消费者订阅消息发布消息 .

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

    Kafka由LinkedIn开发,用于日志聚合和交付 . 这个场景非常好,作为一个例子 .

    您的Web或应用程序上的用户事件可以由Web服务器记录,然后通过 生产环境 者发送到Kafka代理 . 在 生产环境 者中,您可以指定分区方法,例如:事件类型(不同的事件保存在不同的分区中)或事件时间(根据您的应用程序逻辑将一天分区到不同的时间段)或用户类型或只是没有逻辑和 balancer 所有日志进入许多分区 .

    关于您的案例,您可以创建一个名为“page-view-event”的主题,并通过哈希键创建N个分区,以便将日志均匀地分配到所有分区 . 或者您可以选择分区逻辑来根据您的精神分配日志 .

  • 1

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

    @Ludd是正确的 - 您选择的分区结构在很大程度上取决于您想要处理的方式事件流 . 理想情况下,您需要一个分区键,这意味着您的事件处理是 partition-local .

    例如:

    • 如果您关心用户的平均现场时间,则应按 :user-id 进行分区 . 这样,与单个用户的站点活动相关的所有事件都将在同一分区中可用 . 这意味着,只需查看单个分区中的事件,流处理引擎(如Apache Samza)就可以计算给定用户的平均现场时间 . 这避免了必须执行任何类型的昂贵 partition-global 处理

    • 如果您关心网站上最受欢迎的页面,则应按 :viewed 页面进行分区 . 同样,Samza将能够通过查看单个分区中的事件来保持给定页面视图的计数

    通常,我们试图避免不得不依赖全局状态(例如在DynamoDB或Cassandra等远程数据库中保留计数),而是能够使用分区本地状态 . 这是因为local state is a fundamental primitive in stream processing .

    如果你需要上述两个用例,那么Kafka的一个常见模式是首先按 :user-id 进行分区,然后按 re-partition 进行 :viewed 准备进行下一阶段的处理 .

    关于主题名称 - 这里显而易见的是 eventsuser-events . 更具体地说,您可以使用 events-by-user-id 和/或 events-by-viewed .

相关问题