Kafka源码解析与实战

kafka第一课-Kafka快速实战以及基本原理详解 ​ 1、Topic是一个逻辑概念,Producer和Consumer通过Topic进行业务沟通。​ 2、Topic并不存储数据,Topic下的数据分为多组Partition,尽量平均的分散到各个Broker上。每组Partition包含Topic下一部分的消息。每组Partition包含一个Leader Partition以及若干个Follower Partition进行备份,每组Partition的个数称为备份因子 replica factor。 阅读详情

Kafka的架构

包括Kafka的基本组成,Kafka的拓扑结构以及Kafka的内部通信协议。Kafka内部的通信协议是建立在Kafka的拓扑结构之上,而Kafka的拓扑结构是由Kafka的基本模块所组成的。
AK RELEASE 2.5.0
APRIL 15, 2020

Kafka的基本组成

Kafka集群中生产者将消息发送给以Topic命名的消息队列Queue中,消费者订阅发往以某个Topic命名的消息队列Queue中的消息。其中Kafka集群由若干个Broker组成,Topic由若干个Partition组成,每个Partition里的消息通过Offset来获取。
基本组成包括:

  • Broker:一台Kafka服务器就是一个Broker,一个集群由多个Broker组成,一个Broker可以容纳多个Topic,Broker和Broker之间没有Master和Standby的概念,他们之间地位是平等的
  • Topic:每条发送到Kafka集群的消息都属于某个主题,这个主题就称为Topic。物理上不同Topic的消息分开存储,逻辑上一个Topic的消息虽然保存在一个或多个Broker上,但是用户只需指定消息主题Topic即可生产或消费数据而不需要关心数据存放在何处。
  • Partition:为了实现可扩展性,一个非常大的Topic可以被分为多个Partition,从而分布到多台Broker上。Partition中的每条消息都会被分配一个自增Id(Offset)。Kafka只保证按照一个Partition中的顺序将消息发送给消费者,但是不保证单个Topic中多个Partition之间的顺序。
  • Offset:消息在Topic的Partition中的位置,同一个Partition中的消息随着消息的写入其对应的Offset也自增。
  • Replica:副本,Topic的Partition有N个副本,N为副本因子。其中一个Replica为Leader,其他都为Follower,Leader处理Partition的所有读写请求,Follower定期同步Leader上的数据。
  • Message:消息是通信的基本单位。每个Producer可以向一个Topic发布消息
  • Producer:消息生产者,将消息发布到指定的Topic中,也能够决定消息所属的Partition:比如基于Round-Robin或者Hash算法
  • Consumer:消息消费者,向指定的Topic获取消息,根据指定Topic的分区索引及其对应分区上的消息偏移量来获取消息
  • Consumer Group:消费者组,每个消费者都属于一个组。当消费者具有相同组时,消息会在消费者之间负载均衡。一个Partition的消息只会被相同消费者组中的某个消费者消费。不同消费者组是相互独立的。
  • Zookeeper:存放Kafka集群相关元数据的组件。Zookeeper集群中保存了Topic的状态信息,例如分区个数、分区组成、分区的分布情况等;保存Broker的状态信息;保存消费者的消费信息等。通过这些信息,Kafka很好地将消息生产、消息存储、消息消费的过程结合起来。

Kafka的拓扑结构

一个典型的Kafka集群中包含若干个Producer(可以是某个模块下发的Command,或者是Web前端产生的PageView,或者是服务器日志,系统CPU、Memory等),若干个Broker(Kafka集群支持水平扩展,一般Broker数量越多,整个Kafka集群的吞吐率也就越高),若干个Consumer Group,以及一个Zookeeper集群。Kafka通过Zookeeper管理集群配置。Producer使用Push模式将消息发布到Broker上,Consumer使用Pull模式从Broker上订阅并消费消息。

简单的消息发送流程如下:

  1. Producer根据指定的路由方法,将消息Push到Topic的某个Partition里
  2. Kafka集群接收到Producer发过来的消息并持久化到硬盘,并保留消息指定时长(可配置),不关注消息是否被消费。
  3. Consumer从Kafka集群Pull数据,并控制获取消息的Offset

Kafka内部的通信协议

Kafka内部各个Broker之间的角色并不是完全相等的,Broker内部负责管理分区和副本状态以及异常情况下分区的重新分片等这些功能的模块称为KafkaController。每个Kafka集群中有且只有一个Leader状态的KafkaController,当其出现异常时,其余Standby状态的KafkaController会通过Zookeeper选举出有一个Leader状态的KafkaController。

维度一:通信协议详情

  • ProducerRequest:生产者发送消息的请求,生产者将消息发送至Kafka集群中的某个Broker,Broker接收到此请求后持久化此消息并更新相关元数据信息。
    ProducerRequest.requiredAcks的取值为0时,生产者不关心Broker Server端持久化执行结果,但是高级消费者发送的提交偏移量的请求还是需要返回具体执行结果。为1则生产者消费者都需要将Broker Server端持久化的执行结果返回客户端。为-1时,不会立刻返回Broker Server端消息持久化的结果,而是需要等待Partition的ISR列表中的Replica完成数据同步,并且ISR列表的个数大于min.insync.replicas时才会将响应返回给对应客户端。这里采用的是称为Purgatory的策略。Broker Server上对应的Partition的HighWatermark发生改变才触发检查。
  • TopicMetadataRequest:获取Topic元数据信息的请求,无论是生产者还是消费者都需要通过此请求来获取感兴趣的Topic的元数据。
  • FetchRequest:消费者获取Topic的某个分区的消息的请求。分区状态为Follower的副本也需要利用此请求去同步分区状态为Leader的对应副本数据。
  • OffsetRequest:消费者发送至Kafka集群来获取感兴趣Topic的分区偏移量的请求,通过此请求可以获知当前Topic所有分区在不同时间段的偏移量详情。
  • OffsetCommitRequest:消费者提交Topic被消费的分区偏移量信息至Broker,Broker接收到此请求后持久化相关偏移量信息。
  • OffsetFetchRequest:消费者发送获取提交至Kafka集群的相关Topic被消费详细信息,和OffsetCommitRequest相互对应。
  • LeaderAndIsrRequest:当Topic的某个分区状态发送变化时,处于Leader状态的KafkaController发送至相关Broker通知其做出相应处理。
    当某个Replica称为Leader:暂停Fetch→添加进Assigned Replica列表→添加进In-Sync Replica列表→删除已经不存在的Assigned Replica→初始化Leader Replica的HighWatermark
    当某个Replica成为Follower:暂停旧的Fetch线程→截断数据至HighWatermark以下→开启新的Fetch线程→添加进Assigned Replica列表→删除已经不存在的Assigned Replica
  • StopReplicaRequest:当Topic的某个分区被删除或者下线的时候,处于Leader状态KafkaController发送至相关Broker通知其做出相应处理。
  • UpdateMetadataRequest:当Topic的元数据信息发生变化时,处于Leader状态的KafkaController发送至相关Broker通知其做出相应处理。
  • BrokerControllerShutdownRequest:当Broker正常下线时,发送此请求到处于Leader状态的KafkaController。
  • ConsumerMetadataRequest:获取保存特定Consumer Group消费详情的分区信息

维度二:通信协议交互

  • Producer和Kafka集群:Producer需要利用ProducerRequest和TopicMetadataRequest来完成Topic元数据的查询、消息的发送。
  • Consumer和Kafka集群:Consumer需要利用TopicMetadataRequest请求、FetchRequest请求、OffsetRequest、OffsetCommitRequest、OffsetFetchRequest、ConsumerMetadataRequest来完成Topic元数据的查询、消息的订阅、历史偏移量的查询、偏移量的提交、当前偏移量的查询。
  • KafkaController状态为Leader的Broker和KafkaController状态为Standby的Broker:Leader需要用LeaderAndIsrRequest、StopReplicaRequest、UpdateMetadataRequest来完成对Topic的管理。Standby需要利用BrokerControllerShutdownRequest来通知Leader自己的下线动作。
  • Broker和Broker之间:Broker相互之间需要利用FetchRequest请求来同步Topic分区的副本数据,这样才能使Topic分区各副本数据保持一致。

Broker概述

Broker内部存在的功能模块包括SocketServer、KafkaRequestHandlerPool、LogManager、ReplicaManager、OffsetManager、KafkaScheduler、KafkaApis、KafkaHealthcheck和TopicConfigManager九大基本模块以及KafkaController集群控制管理模块。

  • SocketServer:首先开启一个Acceptor线程,新的Socket连接成功建立时会将对应的SocketChannel以轮询方式转发给N个Processor线程中的某一个,由其处理接下来SocketChannel的请求,将请求放置在RequestChannel中的请求队列;当Processor线程监听到SocketChannel请求的响应时,会将响应从RequestChannel中的响应队列中取出来并发给客户端
  • KafkaRequestHandlerPool:真正处理Socket请求的线程池,其个数默认为8个,由参数num.io.threads决定。该线程池里面的线程KafkaRequestHandler从RequestChannel的请求队列中获取Socket请求,然后调用KafkaApis完成真正业务逻辑最后将响应写回至RequestChannel中的响应队列,并交给SocketServer中对应的Processer线程发给客户端。
  • LogManager:Kafka的日志管理模块,主要提供针删除任何过期数据和冗余数据,刷新脏数据,对日志文件进行Checkpoint以及日志合并的功能。
    负责提供Broker Server上Topic的分区数据读取和写入功能,负责读取和写入位于Broker Server上的所有分区副本数据。如果Partition有多个Replica,则每个Broker Server不会存在相同Partition的Replica,如果存在一旦遇到Broker Server下线会丢失Partition的多份副本可用性降低。
    LogManager中包含多个TopicAndPartition,每个TopicAndPartition对应一个Log,每个Log中包含多个LogSegment(每个LogSegment文件包括一个日志数据文件【.log】和两个索引文件(偏移量索引文件【.index】和消息时间戳索引文件【.timeindex】))。LogSegment的结构中log代表消息集合,每条消息都有一个Offset,这是针对Partition中的偏移量;index代表的是消息的索引信息,以KV对的形式记录,其中K为消息在log中的相对偏移量,V为消息在log中的绝对位置;baseOffset代表的是该LogSegment日志段的起始偏移量;indexIntervalByte代表的索引粒度,即写入多少字节之后生成一条索引。OffsetIndex不会保存每条消息的索引,因此其索引文件是一个稀疏索引文件(稀疏索引:索引项中只对应主文件中的部分记录,即不会给每条记录建立索引)。
    稀疏索引

后台还会维护一个日志合并线程,Kafka发送消息的时候需要携带3个参数(Topic,Key,Message),针对相同的Key值不同的Message只保留最后一个Key值对应的消息内容。

  • ReplicaManager:Kafka副本管理模块。主要提供针对Topic分区副本数据的管理功能,包括有关副本的Leader和ISR的状态变化、副本的删除、副本的监测等。ISR全称是In-Syn Replicas,处于同步状态的副本。AR全称是Assign Replicas的缩写,代表分配给Partition的副本。
    主要利用ReplicaFetcherThread(副本数据拉取线程)和High Watermark Mechanism(高水位线机制)来实现数据的同步管理。单个ReplicaFetcherThread线程负责某个Broker Server上部分TopicAndPartition的Replica数据同步。将拉取的消息写入log,更新当前Replica的HighWatermark,代表的是ISR中所有replicas的last commited message的最小起始偏移量。当某个Broker Server上被分配到Replica的时候会进入becomeLeaderOrFollower处理流程;当Replica被删除为进入stopReplicas处理流程;当Follower状态的Replica长时间没有同步Leader状态的Replica的时候会进入maybeShrinkIsr处理流程。
  • OffsetManager:Kafka的偏移量管理模块,主要提供针对偏移量的保存读取的功能,两种方式保存:一种是把偏移量保存到Zookeeper上,另一种是Kafka,把偏移量提交至Kafka内部Topic为"__consumer_offsets"的日志里面,主要由offsets.storage参数决定。默认为Zookeeper。
  • KafkaScheduler:Kafka的后台任务调度资源池。提供后台定时任务的调度,主要为LogManager、ReplicaManager、OffsetManager提供调度服务。
  • KafkaApis:Kafka的业务逻辑实现层,根据不同的Request执行不同的操作,其中利用LogManager、ReplicaManager、OffsetManager来完成内部处理。
  • KafkaHealthcheck:Broker Server在./brokers/ids上注册自己的ID,当Broker在线的时候,则对应的ID存在;当离线时对应ID不存在,从而达到集群状态监测的目的。
  • TopicConfigManager:在/config/changes上注册自己的回调函数来监测Topic配置信息的变化
  • KafkaController:Kafka集群控制管理模块。由于Zookeeper上保存了Kafka机器的元数据信息,因为KafkaController通过在不同目录注册不同的回调函数来达到监测集群状态的目的,以及响应集群状态的变化:
    1. /controller目录保存了Kafka集群中状态为Leader的KafkaController标识,通过监测这个目录的变化可以即使响应KafkaController状态的切换
    2. /admin/reassign_partitions目录保存了Topic重分区的信息,通过监测这个目录的变化可以及时响应Topic分区变化的请求
    3. /admin/preferred_replica_election目录保存了Topic分区副本的信息,通过监测这个目录的变化可以及时响应Topic分区副本变化的请求。
    4. /brokers/topics目录保存了Topic的信息,通过监测这个目录的变化可以及时响应Topic创建和删除的请求。
    5. /brokers/ids目录保存了Broker的状态,通过监测这个目录的变化可以及时响应Broker的上下线情况。

Broker的控制管理模块

每个Broker内部都会存在一个KafkaController模块,但是有且只有一个Broker内部的KafkaController模块对外提供控制管理Kafka集群的功能,例如负责Topic的创建、分区的重分配以及分区副本Leader的重新选举等。

KafkaController的选举策略

Leader和Follower的选举是基于Zookeeper实现的,尝试在Zookeeper的相同路径上创建瞬时节点(Ephemeral Node),只有一个KafkaController会创建成功。其中负责状态管理的类为ZookeeperLeaderElector,字面意思上就可以看出是基于Zookeeper的Leader选举权。其中包含了controllerContext当前Topic的元数据信息以及集群的元数据信息等;electionPath为多个KafkaController竞争写的路径,其值为/controller;onBecomingLeader为状态转化成Leader时候的回调函数;onResigningAsLeader为状态转化位Follower时候的回调函数;brokerId为当前Broker Server的Id。ZookeeperLeaderElector启动后负责观察数据节点状态,瞬时节点消失触发再次选举,尝试写入的节点内容就是brokerId。

KafkaController的初始化

当选举为Leader时分为下面几步:

  1. 初始化Kafka集群内部的时钟,存放在Zookeeper的/controller_epoch,Broker Server用这个值区分请求的时效性
  2. 注册各种监听函数,针对Zookeeper不同目录下Kafka存储的不同元数据进行监听。
  3. 通过initializeControllerContext()、replicaStateMachine.startup()和partitionStateMachine.startup()初始化Kafka集群内部元数据信息。建立和集群内其他状态为Follower的KafkaController的通信链路,处理集群启动前没有及时处理的用户请求,此时可能会变更Kafka集群内部的元数据信息,最后通过sendUpdateMetadataRequest()将Kafka集群内部的元数据信息同步给其他状态为Follower的KafkaController。
  4. 根据auto.leader.rebalance.enable配置项按需启动Kafka集群内部的负载均衡线程,默认开启
  5. 根据delete.topic.enable配置项按需启动Kafka集群内部的Topic删除线程,默认关闭

选举为Follower的时候分为下面几步,正好与Controller相反:

  1. 取消Zookeeper路径上的监听函数
  2. 根据delete.topic.enable配置项按需启动Kafka集群内部的Topic删除线程,默认关闭
  3. 关闭Kafka集群内部的负载均衡线程
  4. 断开和集群内其他状态为Follower的KafkaController的通信线路
  5. 重置集群内部时钟

Topic的分区状态转化机制

Topic的分区状态维护是由PartitionStateMachine模块负责的,通过在/brokers/topics 和 /admin/delete_topics目录上注册不同的监听函数,监听Topic的创建和删除事件触发Topic分区状态的转换。
PartitionStateMachine中分区状态由PartitionState用一个字节表示不同状态,分为四种:

  • NonExistentPartition:代表分区从来没有被创建或者被创建之后又被删除呃状态
  • NewPartition:分区刚创建包含AR,但是此时Leader或ISR还没有创建,处于非活动状态无法接收数据
  • OnlinePartition:分区Leader已经被选举,产生来对应的ISR,处于活动状态可以接收数据
  • OfflinePartition:代表分区Leader由于某种原因下线时导致分区暂时不可用

每个状态都是由一个合理的前置状态转换而来。

Topic分区的领导者副本选举策略

Topic分区的Leader Replica在不同场景下的选举策略是不一样的,不同选举策略都基础PartitionLeaderSelector。其根据Topic、Partition、当前Leader、当前的ISR选举出新的Leader,新的ISR和新的AR(在线状态),共有5种不同的策略:

  • NoOpLeaderSelector:默认的选举策略
  • ReassignedPartitionLeaderSelector:当分区AR重新分配时使用的策略
  • PreferredReplicaPartitionLeaderSelector:集群内部自动平衡负载或者用户触发手动平衡负载时使用的策略
    随着Topic的新建删除以及Broker Server的上下线,原本Topic分区的Leader Replica在集群中的分布越来越不均匀。 auto.leader.rebalance.enable为true,则会自动触发分区的Leader Replica选举,或者管理员下发分区Leader Replica选举指令。这会在Zookeeper的 /admin/preferred_replica_election指定具体的Topic和分区,此时Leader状态的KafkaController监测到这个路径的数据变化就会触发相应的回调函数,促使对应的Topic分区发生Leader Replica的选举。
  • OfflinePartitionLeaderSelector:分区状态从OfflinePartition或者NewPartition切换为OnlinePartition时使用的策略
  1. 筛选出在线的ISR和AR
  2. 优先从在线的ISR中选择,如果列表不为空则选择列表中的第一个,选举结束
  3. 在线ISR为空,根据 unclean.leader.election.enable 决定是否从在线的AR中选举Leader,如果允许,则选择AR列表中的第一个,结束选举,如果AR列表为空选举失败。
  • ControllerShutdownLeaderSelector:Leader状态的KafkaController处理其他Broker Server下线导致分区的Leader Replica发生切换时使用的策略。
  1. 筛选出在线的ISR
  2. 剔除离线的ISR形成新的ISR列表
  3. 如果新的ISR列表不为空,则选举第一个Replica作为新的Leader,否则选举失败

Topic分区的副本状态转换机制

Topic分区的副本状态维护是由ReplicaStateMachine模块负责的,Topic分区的副本状态伴随着Topic分区状态的变化而变化
分区副本状态只要有7种:

  • NewReplica:分区刚被分配但是没有开始工作的状态
  • OnlineReplica:分区副本开始工作时的状态,此时该副本时该分区的Leader或者Follower
  • OfflineReplica:分区副本所在的Broker Server宕机时所导致的副本状态
  • ReplicaDeletionStarted:分区副本下线之后准备开始删除的状态
  • ReplicaDeletionSuccessful:相关Broker Server正确响应分区副本被删除请求之后的状态
  • ReplicaDeletionIneligible:相关Broker Server错误响应分区副本被删除请求之后的状态
  • NonExistentReplica:代表分区副本被彻底删除之后的状态

目标状态也是由合理的前置状态转换而来的。

KafkaController内部的监听器

KafkaController内部通过监听函数来维护集群的元数据。

  • TopicChangeListener:注册在 /broker/topics 路径,监听Topic的创建
  • AddPartitionListener:在Topic创建过程中会在 /broker/topics/[topic]目录下注册AddPartitionListener用于监听Topic分区的变化
  • PartitionReassignedListener:KafkaController转换为Leader的过程中在路径 /admin/reassign_partitions注册了PartitionReassignedListener用于监听Topic分区的重分配。在正式启动重分配之前会判断是否需要进行重分配,重分配之后的AR列表和当前的AR列表不相同并且重分配之后的AR列表所在的Broker Server都在线,满足上面两个条件才会触发分区的重分配。
  • ReassignedPartitionsIsrChangeListener:当Leader Replica所在的Broker Server接收到来自Follower Replica的FetchRequest请求时,KafkaApis的handleFetchRequest会统计每个Replica的状态,一旦发现改Replica同步上Leader Replica之后,此时会调用Partition的updateLeaderHWAndMaybeExpandIsr及时更新 /brokers/topics/[topic]/partitions/partitionId/state/ 目录上的Partition状态,包括Leader、ISR等信息,监听到分区状态发生变化会触发ReassignedPartitionsIsrChangeListener
  • PreferredReplicaElectionListener:每个Partition可以有多个Replica,即AR列表。在这个列表中的第一个Replica称为“Preferred Replica”,当创建Topic时,Kafka要确保所有的Topic的“Preferred Replica”均匀地分布在Kafka集群中。Topic的Partition需要重新均衡Leader Replica至Preferred Replica,此时会触发PreferredReplicaElectionListener
  • BrokerChangeListener:Broker Server的上下线影响着其中所有Replica的状态,因此ReplicaStateMachine在路径为/broker/topic的路径上注册了BrokerChangeListener,用于监听Broker Server的上下线。
    Broker Server上线时步骤为:
  1. Leader状态的KafkaController同步Kafka集群所有的Topic信息给新上线的Broker Server。
  2. 将原本位于该Broker Server上的所有Replica状态切换至OnlineReplica
  3. 如果Partition的Replica有且只有一个,并且正好位于Broker Server上,则切换Partition状态至OnlinePartition。
  4. 如果分区重分配之前由于该Broker Server下线导致推出的话,则尝试重新进行分区重分配。
  5. 如果之前由于Broker Server下线导致对应的Replica无法删除的话,则恢复删除流程。
    Broker Server下线步骤:
  6. 更新ControllerContext内部正在下线的Broker Server列表
  7. 将Leader Replica位于该Broker Server上的分区状态切换为OnlinePartition,紧接着触发分区状态切换为OnlinePartition,利用OfflinePartitionLeaderSelector副本选举策略进行Leader Replica的选举。
  8. 将位于该Broker Server上的Replica状态切换为OfflineReplica
  9. 如果对应Replica的Topic处于删除队列中的话,则标记暂时无法删除。
  • DeleteTopicsListener:监听Topic的删除

Kafka集群的负载均衡流程

Partition的AR列表的第一个Replica称为“Preferred Replica”,并均匀分布在整个Kafka集群中。由于每个Partition只有Leader Replica对外提供读写服务,并且Partition创建的时候默认的Leader Replica位于Preferred Replica之上,此时Kafka集群的负载是均衡的,如果Kafka集群长时间运行,Broker Server中途由于异常而发生重启,此时Partition的Leader Replica会发生迁移,这样会导致其Partition的Leader Replica在集群中不再均衡了。

Kafka集群的Topic删除流程

Topic是由Partition组成的,而Partition是由Replica组成的,因此只有Partition的Assigned Replica全部被删除了该Partition才可以被删除;只有Topic的所有Partition都被删除了,该Topic才可以最终真正的被删除。

KafkaController的通信模块

ControllerChannelManager提供了Leader状态的KafkaController和集群其他Broker Server通信的功能,内部针对每一个在线的Broker Server会维护一个通信链路,并分别通过各自的RequestSendThread线程将请求发送给对应的Broker Server。

Topic管理工具

kafka-topics.sh提供了Topic的创建、修改、列举、描述、删除功能,在内部时通过TopicCommand类来实现的。
kafka-reassign-partitions.sh提供来重新分配分区副本的能力。该工具可以促进Kafka集群的负载均衡。因为Follower Replica需要从Leader Replica Fetch数据以保持与与Leader Replica同步,仅保持Leader Replica分布的平衡对整个集群的负载均衡时不够的。另外当Kafka集群扩容后,该工具可以将已有Topic的Partition迁移到新加入的Broker上。
分区重分片是一个异步的流程,因此该脚本还提供了查看当前分区重分配进度的指令。
kafka-preferred-replica-election.sh用于在整个集群中恢复Leader Replica为Preferred Replica。

生产者

生产者是指消息的生成者。生产者可以通过特定的分区函数决定消息路由到Topic的某个分区。消息的生产者发送消息有两种模式,分别为同步模式和异步模式。
kafka.javaapi.producer.Producer#send方法发送
指定 metadata.broker.list 属性,配置Broker地址
指定 partitioner.class 属性,配置分区函数,分区函数决定路由。分区函数必须实现 kafka.producer.Partitioner的 partition接口,参数为消息key值,分区总数,返回值为分区的索引。

Producer内部包括以下几个主要模块:

  • ProducerSendThread:当producer.type配置为async,则其主要用于缓存客户端的KeyedMessage,然后累积到batch.num.messages配置数量或者间隔 queue.enqueue.timeout.ms配置的时间还没有获取到新的客户端的KeyedMessage,则调用DefaultEventHandler将KeyedMessage发送出去
  • ProducerPool:缓存客户端和各个Broker Server的通信,DefaultEventHandler从ProducerPool中获取和某个Broker Server的通信对象SyncProducer,然后通过SyncProducer将KeyedMessage发送给指定的Broker Server。
  • DefaultEventHandler:将KeyedMessage集合按照分区规则计算不同Broker Server所应该接收的部分KeyedMessage,然后通过SyncProducer将KeyedMessage发送出去。在DefaultEventHandler模块内部提供来SyncProducer发送失败的重试机制和平滑扩容Broker Server的机制。

发送模式

生产者由两种发送模式:同步和异步
当producer.type配置为sync时,同步发送消息。
当producer.type配置为async时,异步发送消息。

消费者

Kafka提供了两种不同的方式来获取消息:简单消费者和高级消费者。简单消费者获取消息时,用户需要知道待消费的消息位于哪个Topic的哪个分区,并且该目的分区的Leader Replica位于哪个Broker Server上;高级消费者获取消息时,只需要指定待消费的消息属于哪个Topic即可。

简单消费者

简单消费者提供的客户端API称为低级API,本质上客户端获取消息最终时利用FetchRequest请求从目的端Broker Server拉取消息。
FetchRequest请求中可以指定Topic的名称,Topic的分区,起始偏移量、最大字节数。
客户端无论生产消息还是消费消息,最终都是通过与目的地端Broker Server建立通信链路,并且以阻塞模式允许,然后通过该条链路将不同的请求发送出去。

高级消费者

高级消费者以Consumer Group(消费组)的形式来管理消息的消费,以Stream(流)的形式来提供具体消息的读取。Stream是指来自若干个Broker Server上的若干个Partition的消息。客户端需要正确设置Stream的个数,并且应该针对每个Stream开启一个线程进行消息的消费。一个Stream代表了多个Partition消息的聚合,但是每一个Partition只能映射到一个Stream。
消息的最终获取是通过遍历KafkaStream的迭代器ConsumerIterator来逐条获取的,其数据来源于分配给该KafkaStream的阻塞消息队列BlockingQueue,而BlockingQueue的数据来源针对每个Broker Server的FetchThread线程。FetchThread线程会将Broker Server上的部分Partition数据发送给对应的阻塞消息队列BlockingQueue,而KafkaStream正是从该阻塞消息队列BlockingQueue中不断的消费消息。
ConsumerThread本质上是客户端的消费线程,消费若干个Partition上的数据,并且与BlockingQueueu相互映射,只要确定了ConsumerThread和Partition之间的关系,也就确定了BlockingQueue和Partition之间的关系。Kafka提供了两种ConsumerThread和Partition的分配算法Range(范围分区分配)和RoundRobin(循环分区分配)
高级消费者中,每个具体消费者实例启动之后会在/consumers/[group]/ids/的Zookeeper目录下注册自己的id;Kafka集群内部Topic会在/brokers/topics/[topic]/的Zookeeper目录下注册自己的Partition,因此消费者实例一旦发现以上2个路径的数据发生变化时,则会触发高级消费者的负载均衡流程,除此之外,消费者实例一旦和Zookeeper的链接重新建立时也会触发高级消费者的负载均衡流程。
高级消费者内部针对Zookeeper的连接建立、Topic的Partition变化、Consumer的新增会建立3个不同的Listener,分别是ZKSessionExpireListener、ZKTopicPartitionChangeListener和ZKRebalancerListener。
高级消费者消费消息时提供了两种持久化偏移量的机制,由参数auto.commit.enable,默认为true自动提交。否则需要手动调用ZookeeperConsumerConnector的commitOffsets。Kafka根据参数offsets.storage,默认为zookeeper(保存路径为/consumers/[group]/offset/[topic]/[partition]),可以设置为kafka(保存再Topic为“__consumer_offsets”的日志中)。高级消费者内部会自动间隔一定时间(由参数 auto.commit.interval.ms决定,默认60*1000ms)

面试相关

kafka高吞吐量的原因:

一、顺序读写磁盘,充分利用了操作系统的预读机制。
二、linux中使用sendfile命令,减少一次数据拷贝,如下。
①把数据从硬盘读取到内核中的页缓存。
②把数据从内核中读取到用户空间。(sendfile命令将跳过此步骤)
③把用户空间中的数据写到socket缓冲区中。
④操作系统将数据从socket缓冲区中复制到网卡缓冲区,以便将数据经网络发出
三、生产者客户端缓存消息批量发送,消费者批量从broker获取消息,减少网络io次数,充分利用磁盘顺序读写的性能。
四、通常情况下kafka的瓶颈不是cpu或者磁盘,而是网络带宽,所以生产者可以对数据进行压缩。

kafka在高并发的情况下,如何避免消息丢失和消息重复?

消息丢失解决方案:
首先对kafka进行限速, 其次启用重试机制,重试间隔时间设置长一些,最后Kafka设置acks=all,即需要相应的所有处于ISR的分区都确认收到该消息后,才算发送成功
消息重复解决方案:
消息可以使用唯一id标识
生产者(ack=all 代表至少成功发送一次)
消费者 (offset手动提交,业务逻辑成功处理后,提交offset)
落表(主键或者唯一索引的方式,避免重复数据)
业务逻辑处理(选择唯一主键存储到Redis或者mongdb中,先查询是否存在,若存在则不处理;若不存在,先插入Redis或Mongdb,再进行业务逻辑处理)

kafka怎么保证数据消费一次且仅消费一次

幂等producer:保证发送单个分区的消息只会发送一次,不会出现重复消息
事务(transaction):保证原子性地写入到多个分区,即写入到多个分区的消息要么全部成功,要么全部回滚流处理EOS:流处理本质上可看成是“读取-处理-写入”的管道。此EOS保证整个过程的操作是原子性。注意,这只适用于Kafka Streams

kafka保证数据一致性和可靠性

数据一致性保证

一致性定义:若某条消息对client可见,那么即使Leader挂了,在新Leader上数据依然可以被读到
HW-HighWaterMark: client可以从Leader读到的最大msg offset,即对外可见的最大offset, HW=max(replica.offset)
对于Leader新收到的msg,client不能立刻消费,Leader会等待该消息被所有ISR中的replica同步后,更新HW,此时该消息才能被client消费,这样就保证了如果Leader fail,该消息仍然可以从新选举的Leader中获取。
对于来自内部Broker的读取请求,没有HW的限制。同时,Follower也会维护一份自己的HW,Folloer.HW = min(Leader.HW, Follower.offset)

数据可靠性保证

当Producer向Leader发送数据时,可以通过acks参数设置数据可靠性的级别
0: 不论写入是否成功,server不需要给Producer发送Response,如果发生异常,server会终止连接,触发Producer更新meta数据;
1: Leader写入成功后即发送Response,此种情况如果Leader fail,会丢失数据
-1: 等待所有ISR接收到消息后再给Producer发送Response,这是最强保证

kafka到spark streaming怎么保证数据完整性,怎么保证数据不重复消费?

保证数据不丢失(at-least)

spark RDD内部机制可以保证数据at-least语义。
Receiver方式
开启WAL(预写日志),将从kafka中接受到的数据写入到日志文件中,所有数据从失败中可恢复。
Direct方式
依靠checkpoint机制来保证。

保证数据不重复(exactly-once)

要保证数据不重复,即Exactly once语义。

  • 幂等操作:重复执行不会产生问题,不需要做额外的工作即可保证数据不重复。
  • 业务代码添加事务操作
    就是说针对每个partition的数据,产生一个uniqueId,只有这个partition的所有数据被完全消费,则算成功,否则算失效,要回滚。下次重复执行这个uniqueId时,如果已经被执行成功,则skip掉。
实战录 | Kafka-0.10 Consumer源码解析 《实战录》导语 前方高能!请注意本期攻城狮幽默细胞爆表,坐地铁的拉好把手,喝水的就建议暂时先别喝了:)本期分享人为云端卫士大数据工程师韩宝君,将带来Kafka-0.10 Consumer源码解析。本文3346字,大约需要花费8-10分钟时间阅读。 Kafka在0.9版本之后,对Consumer进行了重新设计,本人也在网上看了一些Consumer源码解析博客,发现讲的都不是很详细, 阅读详情

相关推荐

Kafka原理与代码实例讲解

Kafka原理与代码实例讲解 1.背景介绍 Apache Kafka是一个分布式流处理平台,最初由Linkedin公司开发,后来被顶级开源组织Apache软件基金会收购和维护。它是一个分布式、分区的、冗余的、容错的发布-订阅消息队列系统。Kafka被广泛应用于大数据领域,用于日志收集、消息系统、

AI天才研究院 1451

京东8年资深架构师为你解析:Kafka源码解析实战。为你解忧

我们在 linux 上查看内存的时候,经常可以看到 buff/cache,两者都是用来加速 IO 读写用的,而 cache 是作用于读,也就是说,磁盘的内容可以读到 cache 里面,这样应用程序读磁盘就非常快;而 kafka 正是把这两者发挥到了极致:Kafka 虽然是 scala 写的,但是依旧在 Java 的虚拟机上运行,尽管如此,kafka 它还是尽量避开了 JVM 的限制,它利用了 Page cache 来存储,这样躲开了数据在 JVM 因为 GC 而发生的 STW。

m0_69860228的博客 625

Kafka全面教程,适合项目实战(包括源码剖析)

Kafka属于Apache组织,是一个高性能跨语言分布式发布订阅消息队列系统[7]。本课程是精短视频教程,从初步认识,用户日志上报实时统计与分析,消息处理与集群维护、消费者与生产者实例(Python和java)、源码剖析。

Kafka 核心源码解读

在开始介绍时间轮之前,思考这样一个问题:“怎么实现 Kafka 中的延时请求呢?”针对这个问题,第一反应是使用Java的DelayQueue。毕竟,这个类是 Java 天然提供的延时队列,非常适合建模延时对象处理。实际上,Kafka 的第一版延时请求就是使用 DelayQueue 做的。但是,DelayQueue 有一个弊端:它插入和删除队列元素的时间复杂度是 O(logN)。对于 Kafka 这种非常容易积攒几十万个延时请求的场景来说,该数据结构的性能是瓶颈。

justlpf的专栏 2129

AI影像组学在结直肠癌诊疗中的应用:从特征提取到临床决策

影像组学通过高通量计算从医学影像中提取定量特征,揭示肿瘤内部的微观生物学行为,这些特征反映了纹理异质性、形状不规则度等影像表型。其核心原理在于将图像数据转化为可分析的数字特征,结合机器学习算法进行模式识别,从而实现对疾病状态的精准预测。这一技术的价值在于能够无创、定量地评估肿瘤特性,为精准医疗提供关键支持。在临床实践中,AI驱动的影像组学模型广泛应用于结直肠癌的诊疗全链条,包括肿瘤良恶性鉴别、基因突变预测、治疗反应评估和预后分析等场景。通过整合影像组学特征与临床数据,可以构建预测模型,辅助医生进行更准确的诊

weixin_28295799的博客 409

线上专利申请(超详细)| 签名确认

在【法人登录】页面点击【证书登录】按钮,弹出证书登录提示框,点击【确 认】按钮,进入到输入证书密码页面,点击【取消】按钮,取消本次操作。企业在提交申请时,需要增加签名,如使用企业账户点击提交,会弹出“法人、代理机构不能签名,请使用经办人签名”,这个时候就需要换个账号了。在需要签名时,将专利官网的登录方式点击法人登录,选择扫码登录,使用移动端经办人账户的扫一扫功能扫描登录。登录完成后,再点击签名,使用移动端扫一扫功能,扫描签名,输入证书号,确认签名,并提交。最后,祝大家的申请都成功!

weixin_62112323的博客 9110

欢迎购买《Kafka源码解析与实战》

沉静了大半年终于把Kafka相关的知识整理了下,欢迎大家购买。 购买方式:登陆京东,搜索关键字:Kafka源码解析与实战。或者点击此链接https://item.jd.com/12277714.html

wl044090432的博客 1766

Costas环参数调优指南:QPSK载波同步中的环路滤波器设计技巧

本文深入解析QPSK载波同步中Costas环的参数调优,特别是环路滤波器的设计技巧。通过分析星座图异常现象,提供从理论计算到MATLAB仿真的实战调优指南,涵盖环路带宽、阻尼系数等关键参数在不同信噪比场景下的选择策略,旨在解决载波同步失锁、性能下降等工程难题。

weixin_29035147的博客 536

kafka计算机专业读法_Kafka源码解析与实战/大数据技术丛书

导语内容提要由王亮编著的《Kafka源码解析与实战/大数据技术丛书》系统介绍Kafka的实现原理和应用方法,并介绍Kafka的运维工具、客户端编程方法和第三方集成方式,深入浅出、图文并茂、分析透彻。本书共10章,主要内容包括:第1章介绍Kafka诞生的背景和主要涉及目标。第2章介绍Kafka的基本组成、拓扑结构以及内部的通信协议。第3章介绍BrokerServer及内部的模块组成。第4章介绍Bro...

weixin_31610297的博客 162

vfsglobal预约系统登录问题全解析(by quqi99)

本文全面解析VFS Global预约系统登录常见问题,包括IP限制、验证码验证失败及账号自动删除等。提供详细的解决方案,如DNS配置、浏览器设置及邮箱选择建议,帮助用户顺利完成签证预约。特别针对中国用户遇到的IP限制问题,给出了实用技巧。

gamma的博客 1340

迪文串口屏开发环境搭建全流程:从DGUS Tool到串口联调

串口屏作为嵌入式人机交互的核心组件,通过串口通信实现主控MCU与显示终端的指令交互。其工作原理基于变量地址映射,主控读写VP地址即可驱动屏上控件,兼具低功耗与高稳定性。在工业控制、医疗设备及智能家居面板等场景中,串口屏能显著降低开发门槛与硬件成本。迪文屏凭借DGUS Tool上位机与自定义串口协议,成为主流选择。掌握DGUS Tool版本匹配、串口驱动安装及VP地址规划,是快速搭建开发环境的关键。

weixin_33937499的博客 603

Flink 消费 Kafka 中数据- 实战+源码解析

对于实时计算来说,Flink 可以说是如日中天,国内很多公司也开始慢慢转向于 Flink 的使用。而对于 Flink 来说最常见的使用场景莫过于读取 Kafka 中的数据,若对此熟练掌握,在面试中拔得头筹也不是不可能的。 在本场 Chat 中,以 Flink 最新版本1.10为基础,会讲到如下内容: 实战篇: Flink 消费 Kafak的基本方式,比如如何从指定 offset 处消费记录 Fl...

GitChat 1152

高比例风电电力系统储能运行及配置研究(python&Matlab实现)

目录1 概述2 案例3 Matlab实现 3.1 题目及分析3.2 Matlab代码 4 七个题全部代码(值得学习) 下面我们先以第二题为例,然后给出Matlab代码:先考虑风电装机300MW直接替代机组3的发电功率曲线,观察系统功率平衡发生的变化情况。然后在此场景下,以最小发电成本为目标函数,将负荷分配给两台火电机组1、2和风电机组,绘制机组日发电计划图。再将风电装机容量作为一个决策变量,以最小发电成本为目标函数,求取最小发电成本对应的风电装机容量,绘制机组日发电计划图。1. 风电装机300MW、直接

weixin_46039719的博客 1740

大厂最全nginx实战,kafka源码解析与实战,性能调优实战案例分享

前言: 实战经验一向是进入大厂的一项必备技能,然而大厂里面的实战项目优势怎么样子的呢,今天给大家分享下大厂nginx实战,kafka源码解析与实战是怎样进行的,都是由一些大牛写成的一本本书籍。 nginx实战 Nginx简介 Nginx服务器的安装与配置 Nginx的基本配置与优化 Nginx与PHP(FastCGI)的安装、配置与优化 Nginx与JSP、ASP.NET、Perl的安装与配置 Nginx HTTP负载均衡和反向代理的配置与优化 Nginx的Rewr...

weixin_45127309的博客 340

基于STC8G1K08A单片机的PCA捕获外部信号(100~1000HZ)程序实现

基于STC8G1K08A单片机的PCA捕获外部信号(100~1000HZ)程序实现

weixin_74013772的博客 254

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

elasticsearch源码解析与优化实战_Kafka源码实战解析,助你徜徉大数据时代

在大数据时代飞速发展的当下,Kafka凭借着其高吞吐低延迟、高压缩性、持久性、可靠性、容错性以及高并发的优势,解决了“在巨大数据下进行准确收集并分析”的难题,也受到了不少大厂以及工程师的青睐,但是有大部分的人,在学习以及面试的过程中才发现自己并没有完全掌握其奥义,对于常见问题仍旧一知半解,这主要是源码阅读的过程中存在问题:(1)源文件太多,不知道重点;(2)源码量太大,无数次从开始到...

weixin_33980343的博客 137

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

读书笔记:Kafka源码解析与实战——Kafka的简介

这里写自定义目录标题简介概述消息系统介绍点对点消息传递模式发布-订阅消息传递模式Kafka的优点解耦冗余(副本)扩展性灵活性&峰值处理能力可恢复性顺序保证缓冲异步通信常用Message Queue对比RabbitMQRedisZeroMQActiveMQKafka/JafkaKafka中的术语解释概述brokerTopicPartitionProducerConsumerConsumer GroupLeaderFollower 简介 概述 Kafka是最初由Linkedin公司开发,是一个分布式、分

肥叔菌的博客 2211

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

读书笔记:Kafka源码解析与实战——Kafka的架构

Kafka集群由若干个Broker组成,Topic由若干个Partition组成,每个Partition里面的消息通过Offset来获取。

肥叔菌的博客 2948

kafka源码_十年资深架构师多年工作经验结晶:Kafka源码解析与实战

前言本篇系统介绍Kafka的实现原理和应用方法,并介绍Kafka的运维工具、客户端编程方法和第三方集成方式,深入浅出、图文并茂、分析透彻。本篇将从初学者的角度出发,循序渐进地讲解Kafka内部的实现原理,但是由于Kafka是基于Scala语言编写的,因此为了更好地阅读本篇,希望读者对于Scala语言有大致的了解。阅读指南本篇将从Kafka的内部实现原理、运维工具、客户端编程以及实际应用这四个方面出...

weixin_39981681的博客 245

读书笔记:Kafka源码解析与实战——Broker概述

Kafka安装包目录结构如下:bin、config、libs、LICENSE、logs、NOTICE,bin目录存放

肥叔菌的博客 2689

kafka源码解析与实战_Kafka 源码解析之 Consumer 两种订阅模式(八)

在前面两篇 Kafka Consumer 的文章中,Consumer Poll 模型这部分基本上已经完整结束,Consumer 这块的文章计划是要写五篇,这篇是 Consumer 这块的第三篇,本来计划是要从其中的三个小块细节内容着手,这三个地方有一个相同之处,那就是在 Kafka Consumer 中都提供了两个不同的解决方案,但具体怎么去使用是需要用户根据自己的业务场景去配置,这里会讲述其底层...

weixin_39576270的博客 300

深入解析Kafka高可用与可靠性:Exactly-Once语义、幂等生产者和事务实现的源码与实战

在分布式消息系统中,高可用性和可靠性是确保数据正确流转的核心基石。Apache Kafka通过其精心设计的架构机制,为现代数据管道和流处理应用提供了强大的保障。理解这些机制不仅有助于系统设计,还能为后续深入探讨Exactly-Once语义的实现奠定基础。Kafka的高可用性主要依赖于其副本(Replication)机制和Leader选举策略。

zuiyuelong的博客 1371

一问Kafka就心慌?我却凭着这份《Kafka源码实战》碾压面试官!

一问Kafka就心慌?我却凭着这份《Kafka源码实战》碾压面试官!

jcc4261的博客 920

写给大忙人看的Flink 消费 Kafka

这是一篇软文: 对于实时计算来说,Flink 可以说是如日中天,国内很多公司也开始慢慢转向于 Flink 的使用。而对于 Flink 来说最常见的使用场景莫过于读取 Kafka 中的数据,若对此熟练掌握,在面试中拔得头筹也不是不可能的。 在本场 Chat 中,以 Flink 最新版本1.10为基础,会讲到如下内容: 实战篇: Flink 消费 Kafak的基本方式,比如如何从指定 offs...

shengjk1的博客 2066

字节大神熬夜整理,MyBatis+Redis+Kafka+spring 源码与实战技术齐飞

相信大家都清楚作为 Java 程序员,每天都在跟开源项目打交道,几乎每个项目都会引入开源项目,比如我们常用的 Web 容器 Spring、Spring Boot,数据库 MySQL 等。这些开源项目也因为被更多的人使用,不断的在优化完善,经过多年的沉淀,都变成了经典。

m0_72327953的博客 1332
上一篇: Redis实战
下一篇: 分布式系统中间件整理
陈晨_软件五千言
陈晨_软件五千言 领域专家: 后端开发技术领域 领域专家: 后端开发技术领域
博客等级 码龄20年 91粉丝 48原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值