这张图是作者做的。
介绍本文最早发布于 https://vutr.substack.com。
我一直想学学Apache Kafka,但总是把它搁置一边,因为我还有更重要的事情要先研究。
(用这么花哨的理由来给自己磨蹭找借口)
在找这篇博客的主题时,我决定写关于Kafka的文章,这也让我有机会好好研究一下这个系统。
我计划写一些关于卡夫卡的博客文章,这些文章和我的学习过程相符。
这篇博客是该系列的第一部分,本文将介绍Kafka的基本概念及其在LinkedIn数据架构中的应用。
高层次概览像LinkedIn这样的互联网公司生成了大量的日志数据,包括用户活动记录(如登录、页面浏览和点击)和运营指标(如服务调用延迟时间、错误或系统资源使用情况)。这些日志数据传统上用来追踪用户的参与度和系统的运行状态,现在也被用于诸如搜索相关性、推荐等功能,例如广告推送。
为了应对 LinkedIn 对日志处理的高要求,LinkedIn 内部开发团队由 Jay Kreps 带领,开发了一个名为 Kafka 的消息系统。该系统综合了传统日志聚合器和发布-订阅消息系统的特性。Kafka 被设计为具有高吞吐量和可扩展性。它提供了一个类似消息系统的 API,让应用程序能够消费实时的日志数据。
发布-订阅(pub/sub)消息系统是一种通信模型,其中发布者无需知道订阅者,就可以将消息发布到特定主题,订阅者只需订阅相应主题,即可接收消息。这有助于解耦消息生产者和消费者。
此外,在卡夫卡所处的时代,大多数现有系统使用的是“推送”模型,在这种模型中,代理向消费者推送数据。领英团队觉得“拉取”模型更适合他们的需求,因为消费者可以按其承受的最大速率获取消息,并避免被推送速度超过其处理能力的消息淹没。
消息在以下几节中,我们将看看一些术语,以便更轻松地理解Kafka架构的理念。
作者绘制的图片。
Kafka的数据单元称为消息。可以将这想象成数据库世界中的行或记录。例如,a. 消息可以有一个可选的元数据部分称为key。内部来看,消息和key在内部都是字节数组。如果用户希望对分区有更多的控制权,可以使用key;例如,Kafka可以通过对key使用一致性哈希算法,确保具有相同key的消息会被分配到同一个分区。
存储在Kafka中的消息并不具有明确的消息ID。相反,每条消息使用其逻辑偏移量。这省去了维护消息ID到实际位置索引结构的开销。要计算下一个消息的偏移量,消费者需要在其偏移量上加上当前消息的长度。
一个话题和分组作者创作的这张图片。
Kafka中的消息被组织到不同的主题。你可以将主题理解为数据库系统中的表。一个主题可以分成多个分区。
分区是Kafka提供冗余和扩展性的一种方式。分区可以部署在不同的服务器上,这意味着主题可以在多个服务器之间水平扩展。
每个主题的分区都对应一个逻辑日志。在物理实现上,每个日志由一组大小大致相等的段文件组成(例如,1GB)。每当消息被写入分区时,代理会将该消息追加到最新的段文件。
制作人:作者创作的图片。
这些发布消息到主题的客户端被称为生产者。生产者将消息写入特定分区。这是通过使用消息的键和分区器生成哈希值并将该哈希值映射到特定分区来实现的。默认情况下,生产者会将消息平均分配到所有主题的分区。在某些情况下,生产者可以将消息导向特定分区。这是通过在消息的键上应用特定的分区方案来实现的。
我打算在接下来的几周里专门写一篇关于 Kafka 生产者 (Producer) 的文章。
消费者群体客户端通过从一个或多个订阅的主题中拉取消息进行阅读。消费者会按照消息在分区中的写入顺序来读取消息。消费者通过消息偏移量来跟踪其消费。一旦消费者确认了某个消息偏移量,就表示它已经收到了该偏移量之前的所有消息。
消费者作为消费组的一部分工作,一个或多个消费者一起工作来消费一个主题。这个设计确保每个分区只有一个消费者在处理数据。让我们来看一个例子;在以下示例中,包含四个分区(p0,p1,p2,p3)的消息主题以及三个消费者(c0,c1,c2)的消费组;一种可能的分区-消费者映射是:c0与p0,c1与p1和p2,c2与p3。
作者所作的图片。
和那些“生产者”一样,我计划不久为 Kafka 消费者写一篇关于 Kafka 消费者的文章,分享我的见解。
基于建议的翻译:交易中介(中介)解释:使用了更口语化的“交易中介”,并在其后加上“中介”来进一步明确角色,同时也去掉了英文标题中使用的“#”符号,以符合中文文本的标准格式。
发布的消息被存储在一组称为代理(brokers)的服务器上。代理接收生产者发送的消息,分配偏移,并将它们写入磁盘。它并通过响应消费者的获取请求来服务。
集群Kafka代理作为集群的一部分工作。在一个集群中,一个代理将充当集群控制器。控制器负责运维任务。
在 Kafka 中,复制提供了分区中消息的副本,使得当某个主节点发生故障时,其中一个从节点可以接管主节点。所有生产者必须连接到主节点来发布消息,但消费者可以从主节点或其中一个从节点中拉取消息。
集群中有一个代理负责一个分区。这个代理被称为该分区的领导者。复制分区被分配给其他代理,这些代理被称为该分区的跟随者。
建筑作者创作的图片
一个 Kafka 集群通常由多个 broker 组成。为了负载均衡,一个 topic 分成多个 partitions,每个 broker 存储一个或多个分区。许多生产者和消费者可以同时发布和接收消息。
简单了解了 Apache Kafka 之后,下一节我们将介绍 LinkedIn 是如何使用 Kafka 的。
卡夫卡的LinkedIn对于此部分,我参考了2011年撰写的一篇关于卡夫卡的文章,这可能已不再反映当前卡夫卡系统的使用情况。
这张图是作者画的。
在 LinkedIn,每个数据中心都有一个位于同一地点的 Kafka 集群。前端应用生成日志数据并将其批量发布到本地 Kafka 代理。它们使用一个负载均衡器将发布请求均匀分配。从该集群中获取消息的消费者同样运行在同一数据中心。
LinkedIn有一个专门用于离线分析的独立Kafka集群,该集群位于他们Hadoop集群附近。该Kafka实例通过嵌入式消费者从主集群拉取数据进行复制。离线集群中的数据用于生成报告、执行分析和处理即席查询。
LinkedIn的工程师开发了一个审计系统,以确保不会发生数据丢失。每个消息在创建时会附上时间戳和服务器名称。定期地,生产者会生成监控事件,记录每个主题在固定时间窗口内发布的消息总数。然后,生产者把这些消息发布到一个单独的Kafka主题中。专门的消费者会统计每个主题的消息数量,并与监控事件进行验证,以确保一切正常运行。
数据和消息偏移存储在HDFS中。从Kafka加载数据至Hadoop集群使用了一种特殊的Kafka输入格式,使得MapReduce作业可以直接从Kafka中读取数据。
他们选择了Avro作为序列化协议,因为它高效且灵活,支持模式演化。对于每个消息,他们存储其Avro模式的ID以及负载数据中的序列化字节。这个模式确保了生产者和消费者的兼容性。此外,LinkedIn使用了一个轻量级模式注册表服务,将模式ID映射到实际模式。
尾声通过这篇文章,我们了解了Apache Kafka的高层次概述,它的术语和架构,最后也看到了LinkedIn是如何在其内部使用Kafka的。
接下来的一篇文章会讲到Kafka中的一些重要设计决定。
那么,下周再聊。
参考资料[1] Jay Kreps, Neha Narkhede, Jun Rao, Kafka: 一个分布式消息处理系统,用于日志处理 (2011)
Gwen Shapira, Todd Palino, Rajini Sivaram, Krit Petty, 《Kafka 权威指南:实时数据处理与大规模流计算》(Kafka The Definitive Guide Real-Time Data and Stream Processing at Scale) (2021)
我的通讯稿是一封每周的电子邮件,在这封邮件里,我分享我从比我聪明的人那里学到的东西。
共同学习,写下你的评论
评论加载中...
作者其他优质文章