Kafka--原理详解

Kafka是一种高吞吐量的分布式消息系统,提供发布订阅和队列模型。它保证消息顺序,支持容错存储和灵活的数据处理。通过消费者组实现广播和单播,每个分区只能被一个消费者消费,保证了分区内的顺序。Kafka的存储策略基于分区,消息以顺序存储。应用包括数据管道、实时流处理等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

kafka简介

kafka是一种高吞吐量分布式发布订阅消息系统,它可以处理消费者规模的网站中的所有动作流数据。这种动作(网页浏览,搜索和其他用户的行动)是在现代网络上的许多社会功能的一个关键因素。这些数据通常是由于吞吐量的要求而通过处理日志和日志聚合来解决。


为什么需要消息队列

  1. 解耦:允许你独立的扩展或修改两边的处理过程,只要确保它们遵守同样的接口约束。
  2. 冗余:消息队列把数据进行持久化直到它们已经被完全处理,通过这一方式规避了数据丢失风险。许多消息队列所采的"插入-获取-删除"范式中,在把一个消息从队列中删除之前,需要你的处理系统明确的指出该消息已经被处理完毕,从而确保你的数据被安全的保存直到你使用完毕。
  3. 扩展性:因为消息队列解耦了你的处理过程,所以增大消息入队和处理的频率是很容易的,只要另外增加处理过程即可。
  4. 灵活性 & 峰值处理能力:在访问量剧增的情况下,应用仍然需要继续发挥作用,但是这样的突发流量并不常见。如果为以能处理这类峰值访问为标准来投入资源随时待命无疑是巨大的浪费。使用消息队列能够使关键组件顶住突发的访问压力,而不会因为突发的超负荷的请求而完全崩溃。
  5. 可恢复性:系统的一部分组件失效时,不会影响到整个系统。消息队列降低了进程间的耦合度,所以即使一个处理消息的进程挂掉,加入队列中的消息仍然可以在系统恢复后被处理。
  6. 顺序保证:在大多使用场景下,数据处理的顺序都很重要。大部分消息队列本来就是排序的,并且能保证数据会按照特定的顺序来处理。(Kafka 保证一个 Partition 内的消息的有序性)
  7. 缓冲:有助于控制和优化数据流经过系统的速度,解决生产消息和消费消息的处理速度不一致的情况。
  8. 异步通信:很多时候,用户不想也不需要立即处理消息。消息队列提供了异步处理机制,允许用户把一个消息放入队列,但并不立即处理它。想向队列中放入多少消息就放多少,然后在需要的时候再去处理它们。

主要功能

  1. 发布和订阅消息流,这个功能类似于消息队列,这也是kafka归类为消息队列框架的原因(It lets you publish and subscribe to streams of records.)
  2. 以容错的方式记录消息流,kafka以文件的方式来存储消息流(It lets you store streams of records in a fault-tolerant way.)
  3. 可以再消息发布的时候进行处理(It lets you process streams of records as they occur.)

kafka基本原理

通常来讲,消息模型可以分为两种:队列发布-订阅式

  1. 队列的处理方式是一组消费者从服务器读取消息,一条消息只有其中的一个消费者来处理。
  2. 发布-订阅模型中,消息被广播给所有的消费者,接收到消息的消费者都可以处理此消息。

      

Kafka为这两种模型提供了单一的消费者抽象模型: 消费者组(consumer group)。消费者用一个消费者组名标记自己。

 一个发布在Topic上消息被分发给此消费者组中的一个消费者。假如所有的消费者都在一个组中,那么这就变成了queue模型。假如所有的消费者都在不同的组中,那么就完全变成了发布-订阅模型。更通用的, 我们可以创建一些消费者组作为逻辑上的订阅者。每个组包含数目不等的消费者,一个组内多个消费者可以用来扩展性能和容错。       

 并且,kafka能够保证生产者发送到一个特定的Topic的分区上,消息将会按照它们发送的顺序依次加入,也就是说,如果一个消息M1和M2使用相同的producer发送,M1先发送,那么M1将比M2的offset低,并且优先的出现在日志中。消费者收到的消息也是此顺序。如果一个Topic配置了复制因子(replication facto)为N,那么可以允许N-1服务器宕机而不丢失任何已经提交(committed)的消息。此特性说明kafka有比传统的消息系统更强的顺序保证。但是,相同的消费者组中不能有比分区更多的消费者,否则多出的消费者一直处于空等待,不会收到消息。

kafka架构图如下:

      

  1. Producer :消息生产者,就是向 kafka broker 发消息的客户端。
  2. Consumer :消息消费者,向 kafka broker 取消息的客户端
  3. Topic :消息以topic为类别记录,Kafka将消息种子(Feed)分门别类,每一类的消息称之为一个主题(Topic)。理解为一个队列。
  4. Consumer Group (CG):这是kafka用来实现一个topic消息的广播(发给所有的consumer)和单播(发给任意一个 consumer)的手段。一个 topic 可以有多个 CG。topic 的消息会复制-给 consumer如果需要实现广播,只要每个 consumer 有一个独立的 CG 就可以了。要实现单播只要所有的 consumer 在同一个 CG。用 CG 还可以将 consumer 进行自由的分组而不需要多次发送消息到不同的 topic。
  5. Broker :一台 kafka 服务器就是一个 broker。一个集群由多个 broker 组成。一个 broker可以容纳多个 topic。
  6. Partition:为了实现扩展性,一个非常大的 topic 可以分布到多个 broker(即服务器)上,一个 topic 可以分为多个 partition,每个 partition 是一个有序的队列。partition 中的每条消息都会被分配一个有序的 id(offset)。kafka 只保证按一个 partition 中的顺序将消息发给consumer,不保证一个 topic 的整体(多个 partition 间)的顺序。
  7. Offset:kafka 的存储文件都是按照 offset.kafka 来命名,用 offset 做名字的好处是方便查找。例如你想找位于 2049 的位置,只要找到 2048.kafka 的文件即可。当然 the first offset 就是 00000000000.kafka

消息传输流程

   

  • producer:生产者。
  • consumer:消费者。
  • topic: 消息以topic为类别记录,Kafka将消息种子(Feed)分门别类,每一类的消息称之为一个主题(Topic)。
  • broker:以集群的方式运行,可以由一个或多个服务组成,每个服务叫做一个broker;消费者可以订阅一个或多个主题(topic),并从Broker拉数据,从而消费这些已发布的消息。

从上图中就可以看出同一个Topic下的消费者和生产者的数量并不是对应的。

每个消息(也叫作record记录,也被称为消息)是由一个key,一个value和时间戳构成。


kafka服务器消息存储策略

  

谈到kafka的存储,就不得不提到分区,即partitions,创建一个topic时,同时可以指定分区数目,分区数越多,其吞吐量也越大,但是需要的资源也越多,同时也会导致更高的不可用性,kafka在接收到生产者发送的消息之后,会根据均衡策略将消息存储到不同的分区中。

   

在每个分区中,消息以顺序存储,最晚接收的的消息会最后被消费。


与生产者的交互

  

生产者在向kafka集群发送消息的时候,可以通过指定分区来发送到指定的分区中,也可以通过指定均衡策略来将消息发送到不同的分区中,如果不指定,就会采用默认的随机均衡策略,将消息随机的存储到不同的分区中。


与消费者的交互

  

在消费者消费消息时,kafka使用offset来记录当前消费的位置

在kafka的设计中,可以有多个不同的group来同时消费同一个topic下的消息,如图,我们有两个不同的group同时消费,他们的的消费的记录位置offset各不项目,不互相干扰。

对于一个group而言,消费者的数量不应该多余分区的数量,因为在一个group中,每个分区至多只能绑定到一个消费者上,即一个消费者可以消费多个分区,一个分区只能给一个消费者消费

因此,若一个group中的消费者数量大于分区数量的话,多余的消费者将不会收到任何消息。


kafka四个核心API

  • 应用程序使用producer API发布消息到1个或多个topic中。
  • 应用程序使用consumer API来订阅一个或多个topic,并处理产生的消息。
  • 应用程序使用streams API充当一个流处理器,从1个或多个topic消费输入流,并产生一个输出流到1个或多个topic,有效地将输入流转换到输出流。
  • connector API允许构建或运行可重复使用的生产者或消费者,将topic链接到现有的应用程序或数据系统。

kafka应用场景

  • 构建实时的流数据管道,可靠地获取系统和应用程序之间的数据。
  • 构建实时流的应用程序,对数据流进行转换或反应。

主题和日志 (Topic和Log)

每一个分区(partition)都是一个顺序的、不可变的消息队列,并且可以持续的添加。分区中的消息都被分了一个序列号,称之为偏移量(offset),在每个分区中此偏移量都是唯一的。Kafka集群保持所有的消息,直到它们过期,无论消息是否被消费了。实际上消费者所持有的仅有的元数据就是这个偏移量,也就是消费者在这个log中的位置。 这个偏移量由消费者控制:正常情况当消费者消费消息的时候,偏移量也线性的的增加。但是实际偏移量由消费者控制,消费者可以将偏移量重置为更老的一个偏移量,重新读取消息。 可以看到这种设计对消费者来说操作自如, 一个消费者的操作不会影响其它消费者对此log的处理。

再说说分区。Kafka中采用分区的设计有几个目的。

  1.  可以处理更多的消息,不受单台服务器的限制。Topic拥有多个分区意味着它可以不受限的处理更多的数据。
  2.  分区可以作为并行处理的单元,稍后会谈到这一点。

分布式(Distribution)

Log的分区被分布到集群中的多个服务器上。每个服务器处理它分到的分区。根据配置每个分区还可以复制到其它服务器作为备份容错。 每个分区有一个leader,零或多个follower。Leader处理此分区的所有的读写请求,而follower被动的复制数据。如果leader宕机,其它的一个follower会被推举为新的leader。 一台服务器可能同时是一个分区的leader,另一个分区的follower。 这样可以平衡负载,避免所有的请求都只让一台或者某几台服务器处理。每个分区的副本中只有主副本接受读写,所以每个服务器
端都会作为某些分区的主副本,以及另外一些分区的备份副本,这样 Kafka 集群的所有服务端整体上对客户端是负载均衡的。
Kafka 的生产者和消费者相对于服务器端而言都是客户端。
Kafka 生产者客户端发布消息到服务端的指定主题,会指定消息所属的分区。生产者发布消息时根据消息是否有键,采用不同的分区策略。消息没有键时,通过轮询方式进行客户端负载均衡;消息有键时,根据分区语义(例如 hash)确保相同键的消息总是发送到同一分区。
Kafka 的消费者通过订阅主题来消费消息,并且每个消费者都会设置一个消费组名称。因为生产者发布到主题的每一条消息都只会发送给消费者组的一个消费者。所以,如果要实现传统消息系统的“队列”模型,可以让每个消费者都拥有相同的消费组名称,这样消息就会负责均衡到所有的消费者;如果要实现“发布-订阅”模型,则每个消费者的消费者组名称都不相同,这样每条消息就会广播给所有的消费者。

Kafka 的消费者消费消息时,只保证在一个分区内的消息的完全有序性,并不保证同一个主题汇中多个分区的消息顺序。而且,消费者读取一个分区消息的顺序和生产者写入到这个分区的顺序是一致的。比如,生产者写入“hello”和“Kafka”两条消息到分区 P1,则消费者读取到的顺序也一定是“hello”和“Kafka”。如果业务上需要保证所有消息完全一致,只能通过设置一个分区完成,但这种做法的缺点是最多只能有一个消费者进行消费。一般来说,只需要保证每个分区的有序性,再对消息假设键来保证相同键的所有消息落入同一分区,就可以满足绝大多数的应用。


End

<think>好的,用户想了解Kafka的底层原理和工作机制,特别是消息存储、消费者组和分区机制。我需要结合提供的引用内容来组织回答。首先,我需要先回忆一下Kafka的基本架构,然后分部分解析。 消息存储方面,引用5提到了分区下的segment结构,每个segment由index和log文件组成。应该详细说明存储的逻辑结构,比如分区如何分成多个segment,segment的作用是什么,index文件如何帮助快速定位消息。另外,可能还需要提到消息的持久化机制和日志追加方式,但用户提供的引用中没有这部分,可能需要依赖已有的知识补充。 然后是消费者组。引用4提到消费者主动拉取消息,且采用发布订阅模式。消费者组的概念需要解释,比如同一个消费者组内的消费者如何分配分区,实现负载均衡。可能还要提到消费者组的rebalance机制,当消费者加入或离开时如何重新分配分区,但引用中没有直接提到这点,可能需要结合一般知识说明。 分区机制方面,引用1和3提到了动态分区和分区器的实现。需要说明分区的基本作用,比如提高并发和吞吐量,动态分区如何扩展,以及生产者的分区策略,比如默认的哈希分区和自定义分区器。引用3中的DefaultPartitioner和自定义分区的实现方法也需要解释清楚。 另外,引用2提到ZooKeeper的作用,比如存储配置、选举Leader副本和监控状态。这部分可能需要放在整体架构中,说明ZooKeeper在Kafka中的角色,尤其是在分区Leader选举中的作用,保证高可用性。 需要确保各部分内容连贯,并且正确引用提供的参考文献。例如,在讲动态分区时引用[^1],在ZooKeeper部分引用[^2],分区器部分引用[^3],消费者拉取消息引用[^4],segment结构引用[^5]。 可能还需要检查是否有遗漏的要点,比如消息的顺序性、副本机制、ISR集合等,但根据用户的问题,重点在消息存储、消费者组和分区机制,所以可能需要简要提及副本机制,但引用中没有详细说明,可以点到为止。 最后,生成的相关问题需要基于回答内容,确保用户可能想进一步了解的方面,比如如何保证消息顺序、分区分配策略或消费者组的rebalance过程等。</think>### Kafka底层原理详解 #### 一、消息存储机制 Kafka的消息存储以**分区(Partition)**为核心,每个分区被划分为多个**分段(Segment)**,每个分段由`index`索引文件和`log`日志文件组成。`log`文件存储实际消息内容,而`index`文件记录消息的偏移量(Offset)和物理位置,支持快速定位消息[^5]。 例如,当消费者需要读取偏移量为$n$的消息时,Kafka通过二分查找快速定位到对应的Segment,再通过索引找到具体的物理位置。 **存储特点**: 1. **顺序写入**:消息追加到日志末尾,减少磁盘寻道时间。 2. **分段管理**:避免单个文件过大,支持定期清理旧数据。 #### 二、消费者组(Consumer Group)机制 消费者组通过**分区分配**实现并行消费。每个消费者组内的消费者实例负责消费不同分区的数据,例如: - 若一个消费者组有3个消费者,而主题有6个分区,则每个消费者分配2个分区[^4]。 - 若消费者数量超过分区数,多余的消费者会处于闲置状态。 **关键行为**: 1. **消费者重平衡(Rebalance)**:当消费者加入或离开时,触发分区重新分配,确保负载均衡。 2. **偏移量提交**:消费者定期提交消费进度到Kafka内部主题(`__consumer_offsets`),避免重复消费。 #### 三、分区机制与动态扩展 1. **分区的作用** - **并发处理**:分区是并行处理的基本单位,生产者将消息按规则分发到不同分区。 - **数据有序性**:单个分区内消息有序,但全局无序(需业务层处理)。 2. **分区分配策略** - **默认分区器**:根据Key的哈希值选择分区(公式:$partition = \text{hash}(key) \mod N$)[^3]。 - **自定义分区器**:可通过实现`Partitioner`接口定义业务逻辑(如按地理位置分区)。 3. **动态分区扩展** Kafka支持运行时增加分区数量以提升吞吐量,但需注意: - 已有数据的分区不会重新分配,新分区仅对新数据生效。 - 需结合消费者组调整消费策略,避免数据倾斜[^1]。 #### 四、ZooKeeper的协同作用 Kafka依赖ZooKeeper实现以下功能: 1. **元数据管理**:存储Broker、主题、分区的元信息。 2. **Leader选举**:分区副本的Leader选举通过ZooKeeper协调,确保高可用[^2]。 3. **消费者组状态跟踪**:记录消费者组与分区的映射关系。 #### 五、消息传递流程示例 $$ \text{Producer} \xrightarrow{\text{按分区规则发送}} \text{Leader Partition} \xrightarrow{\text{同步复制}} \text{Follower Partitions} $$ 消费者从Leader分区拉取消息,Follower副本仅用于故障恢复[^4]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值