kafka-2.4.1
kafka-2.4.1源码
其实系一个须刨
这个作者很懒,什么都没留下…
展开
-
kafka 的 mmap文件读写方式
众所周知,kafka之所以吞吐量高,其中的一个重要原因就是因为其consumer在读取日志文件时使用了mmap的方式,mmap与常规文件读写的区别如下:总结:mmap之所以能有效提高kafka的吞吐量,是因为其在进行log文件读取的时候直接将log文件读入用户态进行缓存,绕过了内核态的page cache,避免了内核态和用户态的切换过程。参考:https://juejin.im/post/59f8691b51882534af254317#heading-16https://www.cnblogs转载 2021-06-01 19:42:22 · 540 阅读 · 0 评论 -
Kafka的哪些场景中使用了零拷贝(ZeroCOpy)?
在Kafka中,体现ZeroCopy使用场景的地方有两处:基于mmap的索引和日志文件读写所用的TransportLayer。mmap的索引 索引都是基于MappedByteBuffer的,也就是让用户态和内核态共享内核态的数据缓冲区,此时,数据不需要复制到用户态空间。不过,mmap虽然避免了不必要的拷贝,但是不一定就能保证很高的性能,在不同的操作系统下,mmap的创建和销毁成本可能是不一样的。很高的创建和销毁开销会抵消ZeroCopy带来的性能优势。由于这种不确定性,在Kafk...原创 2021-06-01 19:31:46 · 1233 阅读 · 1 评论 -
Kafka 消费者模块(四):rebalance的确认最终分配结果
onJoinComplete 完成rebalance最后一步,确认最终分配结果。protected void onJoinComplete(int generation, String memberId, String assignmentStrategy, ByteBuffer assignmentBuff...原创 2020-10-05 11:52:52 · 1608 阅读 · 0 评论 -
Kafka 消费者模块(三):rebalance的发送JoinGroupResult请求
完成了前期准备工作之后,消费者将正式开始执行分区再分配,这是一个客户端与服务端交互配合的过程,消费者需要构造并发送 JoinGroupResult 请求到对应的 GroupCoordinator 实例所在节点申请加入目标 group。 这一过程位于 AbstractCoordinator#initiateJoinGroup 方法中,该方法的主要工作就是切换当前消费者的状态为 REBALANCING,创建并缓存 JoinGroupRequest 请求,并处理申请加入的结果。如...原创 2020-10-05 11:52:43 · 4019 阅读 · 0 评论 -
Kafka 消费者模块(二):rebalance的准备工作
在开始执行分区再分配操作之前需要执行一些前期准备工作,这里使用了 needsJoinPrepare 字段进行控制,如果当前正在执行分区再分配,则 needsJoinPrepare 字段会被标记为 false,以防止重复执行。准备工作的逻辑实现位于 ConsumerCoordinator#onJoinPrepare 方法中,主要做了 3 件事情:如果开启了 offset 自动提交,则同步提交 offset 到集群。 激活注册的 ConsumerRebalanceListener 监听器的...原创 2020-10-05 11:52:31 · 1133 阅读 · 0 评论 -
Kafka 消费者模块(一):rebalance的触发
在消费者调用poll拉消息的时候,消费者会先检测当前是否需要执行分区再分配操作,如果需要则直接返回空的结果,这样在不超时的情况下,方法 KafkaConsumer#pollOnce 会立即被再次调用,从而开始对当前 topic 分区执行再分配,即调用 ConsumerCoordinator#poll 方法。public boolean poll(Timer timer) { maybeUpdateSubscriptionMetadata(); // 触发执行注册的监听 ...原创 2020-10-05 11:52:21 · 1021 阅读 · 0 评论 -
Kafka 生产者模块(五):KafkaProducer 的 sender线程之NetworkClient#poll方法
NetworkClient#poll 方法执行具体的网络请求和响应。下面来看一下 NetworkClient#poll 方法的具体实现:public List<ClientResponse> poll(long timeout, long now) { ensureActive(); if (!abortedSends.isEmpty()) { // If there are aborted sends because of unsuppor...原创 2020-10-05 11:52:09 · 3358 阅读 · 1 评论 -
Kafka 生产者模块(四):KafkaProducer 的 sender线程之sendProducerData方法
sendProducerData把实际要发的消息封装好,放入KakfaNetworkClient中。 private long sendProducerData(long now) { // 1. 计算需要以及可以向哪些节点发送请求 Cluster cluster = metadata.fetch(); // get the list of partitions with data ready to send // 计算需要向哪些节点发送请求 R...原创 2020-10-05 11:51:44 · 603 阅读 · 0 评论 -
Kafka 生产者模块(三):KafkaProducer 的 sender线程
客户端发送消息的过程实际上是一个异步的过程,由 2 个线程协同执行,其中 1 个线程将待发送的消息写入缓冲区,另外 1 个线程(Sender 线程)负责定期定量将缓冲区中的数据投递给远端 Kafka 集群,并反馈投递结果。 这一过程由 Sender 线程负责执行,前面的分析中曾多次唤醒过该线程,下面来看一下其实现,位于 Sender 类中,该类实现了 java.lang.Runnable 接口,其 Sender#run 方法实现如下: public void ru...原创 2020-10-03 14:42:43 · 711 阅读 · 0 评论 -
Kafka 生产者模块(二):KafkaProducer 的 send 接口发送消息
send接口会把消息经过处理后,放在一个缓存中,由后台sender线程从缓存中取出,然后发送到服务端,这一篇介绍放入缓存的send接口。了解了 KafkaProducer 的字段定义和对象的构造过程之后,下面正式开始对消息收集的过程进行分析,相关实现位于 KafkaProducer#send 方法中: public Future<RecordMetadata> send(ProducerRecord<K, V> record, Callback cal...原创 2020-10-03 14:36:33 · 2550 阅读 · 0 评论 -
Kafka 生产者模块(一):KafkaProducer 以及Metadata、Cluster定义
public class KafkaProducer<K, V> implements Producer<K, V> { private final Logger log; /** clientId 生成器,如果没有明确指定客户端 ID,则使用该字段顺序生成一个 */ private static final AtomicInteger PRODUCER_CLIENT_ID_SEQUENCE = new AtomicInteger(1); priva.原创 2020-10-03 14:33:02 · 582 阅读 · 0 评论 -
Kafka 消费者组管理模块(七):GroupCoordinator 处理组同步
组同步,是指当所有成员都成功加入组之后,Coordinator 指定其中一个成员为 Leader,然后将订阅分区信息发给 Leader 成员。接着,所有成员(包括 Leader 成员)向 Coordinator 发送 SyncGroupRequest 请求。需要注意的是,只有 Leader 成员发送的请求中包含了订阅分区消费分配方案,在其他成员发送的请求中,这部分的内容为空。当 Coordinator 接收到分配方案后,会通过向成员发送响应的方式,通知各个成员要消费哪些分区。 ...原创 2020-10-03 01:29:46 · 1389 阅读 · 0 评论 -
Kafka 消费者组管理模块(六):GroupCoordinator 处理成员入组
Rebalance 的流程大致分为两大步:加入组(JoinGroup)和组同步(SyncGroup)。 加入组,是指消费者组下的各个成员向 Coordinator 发送 JoinGroupRequest 请求加入进组的过程。这个过程有一个超时时间,如果有成员在超时时间之内,无法完成加入组操作,它就会被排除在这轮 Rebalance 之外。 下面直接看GroupCoordinator:处理成员入组handleJoinGroup 方法,来处理消费者组成员发送过来...原创 2020-10-03 01:28:14 · 1911 阅读 · 0 评论 -
Kafka 消费者组管理模块(五):__consumer_offsets的写入和读取
写入__consumer_offsets 之前介绍的 storeOffsets 方法调用它写入已提交位移消息。而本篇介绍的 storeGroup 方法调用它写入消费者组注册消息,即向 Coordinator 注册消费者组。 def storeGroup(group: GroupMetadata, groupAssignment: Map[String, Array[Byte]], responseCallback:...原创 2020-10-03 01:24:25 · 1125 阅读 · 0 评论 -
Kafka 消费者组管理模块(四):__consumer_offsets中保存的数据类型
__consumer_offsets 中的注册消息(Group Metadata)和位移消息(Offset Commit)。 位移主题有两类消息:消费者组注册消息(Group Metadata)和消费者组的已提交位移消息(Offset Commit)。注册消息 所谓的注册消息,就是指消费者组向位移主题写入注册类的消息。所有成员都加入组后:Coordinator 向位移主题写入注册消息,只是该消息不含分区消费分配方案;Leader 成员发送方案给 Coor...原创 2020-10-03 01:21:37 · 794 阅读 · 0 评论 -
Kafka 消费者组管理模块(三):GroupMetadataManager 消费者组位移管理
消费者组管理器,提供的是添加消费者组、移除组、查询组这样组级别的基础功能。先看GroupMetadataManager的定义 interBrokerProtocolVersion: ApiVersion, // interBrokerProtocolVersion:Broker端参数inter.broker.protocol.version值 config: OffsetConfi...原创 2020-10-03 01:14:06 · 694 阅读 · 0 评论 -
Kafka 消费者组管理模块(二):GroupMetadata 管理消费者组方法
GroupMetadata 中定义了很多管理消费者组状态的方法,这里介绍几个常用的。消费者组状态管理transitionTo 方法 transitionTo 方法的作用是将消费者组状态变更成给定状态。在变更前,代码需要确保这次变更必须是合法的状态转换。 同时,该方法还会更新状态变更的时间戳字段。Kafka 有个定时任务,会定期清除过期的消费者组位移数据,它就是依靠这个时间戳字段,来判断过期与否的。 def transitionTo(group...原创 2020-10-03 01:05:45 · 943 阅读 · 0 评论 -
Kafka 消费者组管理模块(一):组元数据与组成员元数据
消费者组的元数据主要是由 GroupMetadata 和 MemberMetadata 两个类组成,它们分别位于 GroupMetadata.scala 和 MemberMetadata.scala 这两个源码文件中。从它们的名字上也可以看出来,前者是保存消费者组的元数据,后者是保存消费者组下成员的元数据。MemberMetadata先看 MemberMetadata.scala 文件,包括 3 个类和对象MemberSummary 类:组成员概要数据,提取了最核心的元数据信息。...原创 2020-10-03 00:52:19 · 1048 阅读 · 0 评论 -
Kafka 副本管理模块(九):Broker 上的元数据缓存MetadataCache管理
MetadataCache 是指 Broker 上的元数据缓存,这些数据是 Controller 通过 UpdateMetadataRequest 请求发送给 Broker 的。换句话说,Controller 实现了一个异步更新机制,能够将最新的集群信息广播给所有 Broker,Kafka 通过异步更新机制来保证所有 Broker 上的元数据缓存实现最终一致性。每台 Broker 上都要保存这份相同的数据有两个原因。保存了这部分数据,Broker 就能够及时响应客户端发送的元数据请求,...原创 2020-10-02 15:14:12 · 683 阅读 · 0 评论 -
Kafka 副本管理模块(八):ReplicaManager 副本管理之HW 和 LEO 位置管理
Partition 定义了 Partition#checkEnoughReplicasReachOffset 方法和 Partition#maybeIncrementLeaderHW 方法,分别用于检测指定 offset 之前的消息是否已经被 ISR 集合中足够多的 follower 副本确认(ack),以及尝试向后移动 leader 副本的 HW 值。.checkEnoughReplicasReachOffset方法 用于检测指定 offset 之前的消息是否已经被 ...原创 2020-10-02 15:09:04 · 293 阅读 · 0 评论 -
Kafka 副本管理模块(七):ReplicaManager 副本管理之ISR变更处理
除了读写副本、管理分区和副本的功能之外,副本管理器还有一个重要的功能,那就是管理 ISR。这里的管理主要体现在两个方法:maybeShrinkIsr 方法:作用是阶段性地查看 ISR 中的副本集合是否需要收缩;收缩是指,把 ISR 副本集合中那些与 Leader 差距过大的副本移除的过程。所谓的差距过大,就是 ISR 中 Follower 副本滞后 Leader 副本的时间,超过了 Broker 端参数 replica.lag.time.max.ms 值的 1.5 倍。 maybePr...原创 2020-10-02 15:06:49 · 678 阅读 · 0 评论 -
Kafka 副本管理模块(六):ReplicaManager 副本管理之分区Leader/Follower切换
除了对副本进行读写之外,副本管理器还有一个重要的功能,就是管理副本和对应的分区。ReplicaManager 管理它们的方式,ReplicaManager 通过直接操作分区对象来间接管理下属的副本对象。 管理下辖的分区和副本对象的主要方式,就是要确定在它保存的这些副本中,哪些是 Leader 副本、哪些是 Follower 副本。这些划分可不是一成不变的,而是随着时间的推移不断变化的。这些变更是通过 Controller 给 Broker 发送 LeaderAndIsrReque...原创 2020-10-02 14:59:49 · 1236 阅读 · 0 评论 -
Kafka 副本管理模块(五):副本读取 fetchMessages 方法
副本读取:fetchMessages方法读取需要的消息,它逻辑如下: def fetchMessages(timeout: Long, // 请求处理超时时间。 replicaId: Int, // 副本 ID。对于消费者而言,该参数值是 -1;对于 Follower 副本而言,该值就是 Follower 副本所在的 Broker ID。 fetchMinBytes: Int, // 够获取的最小字节数。原创 2020-10-02 14:47:37 · 708 阅读 · 0 评论 -
Kafka 副本管理模块(四):副本写入 appendRecords 方法
副本写入,是指向副本底层日志写入消息。在 ReplicaManager 类中,实现副本写入的方法叫 appendRecords。放眼整个 Kafka 源码世界,需要副本写入的场景有 4 个。生产者向 Leader 副本写入消息 Follower 副本拉取消息后写入副本 消费者组写入组信息 事务管理器写入事务信息(包括事务标记、事务元数据等)下面直接看ReplicaManager 类中实现副本写入的方法 appendRecords。 def appendRecords(ti...原创 2020-10-02 14:45:41 · 658 阅读 · 0 评论 -
Kafka 副本管理模块(三):ReplicaManager 类介绍
ReplicaManager 负责管理和操作集群中 Broker 的副本,它定义如下:class ReplicaManager(val config: KafkaConfig, // 配置管理类 metrics: Metrics, // 监控指标类 time: Time, // 定时器类 val zkClient: KafkaZkClient, // ZooKeeper客户端原创 2020-10-02 14:51:32 · 382 阅读 · 0 评论 -
Kafka 副本管理模块(二):ReplicaFetcherThread
ReplicaFetcherThread是AbstractFetcherThread的子类,实现了对应的函数,它的定义如下:class ReplicaFetcherThread(name: String, // 线程名称 // 单台 Broker 上,允许存在多个 ReplicaFetcherThread 线程。Broker 端参数 num.replica.fetchers,决定了 Kafka 到底创建多少个 Follower 拉取线程。原创 2020-10-02 14:39:27 · 1639 阅读 · 0 评论 -
Kafka 副本管理模块(一):AbstractFetcherThread
Follower 副本从 Leader 副本拉取数据是在ReplicaFetcherThread 线程完成的,现在先看看他的抽象基类AbstractFetcherThread的定义。 abstract class AbstractFetcherThread(name: String, // 线程名称 clientId: String, // Client Id,用于日志输出原创 2020-10-02 14:34:44 · 726 阅读 · 0 评论 -
Kafka 延迟操作模块(四):DelayedProduce 与 DelayedFetch
kafka中有很多运用到延迟操作,比较典型的延时任务实现:DelayedProduce 和 DelayedFetch。DelayedProduce当生产者追加消息到集群时(对应 ProduceRequest 请求),实际上是与对应 topic 分区的 leader 副本进行交互,当消息写入 leader 副本成功后,为了保证 leader 节点宕机时消息数据不丢失,一般需要将消息同步到位于 ISR 集合中的全部 follower 副本,只有当 ISR 集合中所有的 follower ...原创 2020-10-01 01:24:06 · 804 阅读 · 0 评论 -
Kafka 延迟操作模块(三):DelayedOperation 与 DelayedOperationPurgatory
DelayedOperation DelayedOperation 是延时任务的抽象,它实现了 TimerTask 特质,abstract class DelayedOperation(override val delayMs: Long, // DelayedOperation 类是一个抽象类,它的构造函数中只需要传入一个超时时间即可。 // 这个超时时间通常是...原创 2020-10-01 01:15:57 · 597 阅读 · 0 评论 -
Kafka 延迟操作模块(二):Timer定时器
上面介绍的 TimingWheel 提供了添加延时任务和推进时间轮指针的操作,而具体执行延时任务的操作则交由定时器 SystemTimer 完成。SystemTimer 类实现了 Timer 特质,该特质描绘了定时器应该具备的基本方法。Timer 接口定义了管理延迟操作的方法,而 SystemTimer 是实现延迟操作的关键代码。Timer 接口类Timer 接口定义如下:trait Timer { /** * Add a new task to this executor...原创 2020-10-01 01:09:45 · 1165 阅读 · 0 评论 -
Kafka 延迟操作模块(一):TimingWheel时间轮
kafka使用的是层级时间时间轮处理实现延迟功能。例如我们的手表,手表由时针、分针和秒针组成,它们各自有独立的刻度,这就是典型的分层时间轮。和手表不一样的是,Kafka 自己有专门的术语。在 Kafka 中,手表中的“一格”叫“一个桶(Bucket)”,而“推进”对应于 Kafka 中的“滴答”,也就是 tick。Kafka 的分层时间轮算法在实现上主要涉及 TimingWheel、TimerTaskList、TimerTaskEntry,以及 TimerTask 这 4 个类,各个类的作用说明如下:原创 2020-10-01 01:05:16 · 1283 阅读 · 1 评论 -
Kafka 状态机模块(三):TopicDeletionManager 删除主题管理
TopicDeletionManager 负责对指定 Kafka 主题执行删除操作,清除待删除主题在集群上的各类“痕迹”,包括 3 个部分。class TopicDeletionManager(config: KafkaConfig, // KafkaConfig类,保存Broker端参数 controllerContext: ControllerContext, // 集群元数据 replic原创 2020-09-29 21:47:59 · 319 阅读 · 0 评论 -
Kafka 状态机模块(二):ReplicaStateMachine副本状态机
ReplicaStateMachine 定义了 Kafka Controller 的副本状态机,用于管理集群中副本的状态信息,每个 Kafka Controller 都定义了自己的副本状态机,但是只有在当前 Controller 实例成为 leader 角色时才会启动运行名下的状态机。 副本状态及状态管理流程副本状态机一旦被启动,就意味着它要行使它最重要的职责了:管理副本状态的转换。 它的启动逻辑如下: def startup(): Unit = { info("...原创 2020-09-29 21:43:21 · 205 阅读 · 0 评论 -
Kafka 状态机模块(一):PartitionStateMachine分区状态机
PartitionStateMachine 定义了 Kafka Controller 的分区状态机,用于管理集群中分区的状态信息,每个 Kafka Controller 都定义了自己的分区状态机,但只有在当前 Controller 实例成为 leader 角色时才会启动运行名下的状态机。它启动逻辑如下: def startup(): Unit = { info("Initializing partition state") // // 初始化本地记录的所有分区状态...原创 2020-09-29 21:40:58 · 731 阅读 · 1 评论 -
Kafka Controller模块(五):Controller 集群成员管理与主题管理
集群成员管理首先,我们来看 Controller 管理集群成员部分的代码。这里的成员管理包含两个方面:成员数量的管理,主要体现在新增成员和移除现有成员; 单个成员的管理,如变更单个 Broker 的数据等。成员数量管理 每个 Broker 在启动的时候,会在 ZooKeeper 的 /brokers/ids 节点下创建一个名为 broker.id 参数值的临时节点。一旦发现新增或删除 Broker,/brokers/ids 下的子节点数目一定会发生变化。 一旦发现新...原创 2020-09-27 22:40:09 · 214 阅读 · 0 评论 -
Kafka Controller模块(四):Controller 选举
集群上所有的 Broker 都在实时监听 ZooKeeper 上的 /controller 节点。我们先看看KafkaController 类class KafkaController(val config: KafkaConfig, // config:Kafka配置信息,通过它,你能拿到Broker端所有参数的值 zkClient: KafkaZkClient, // zkClient:ZooKeeper客户端,Controller与ZooKeeper的原创 2020-09-27 22:36:30 · 1086 阅读 · 1 评论 -
Kafka Controller模块(三):ControllerEventManager 处理事件
Controller 端有多个线程向事件队列写入不同种类的事件,比如,ZooKeeper 端注册的 Watcher 线程、KafkaRequestHandler 线程、Kafka 定时任务线程。在事件队列的另一端,只有一个名为 ControllerEventThread 的线程专门负责“消费”或处理队列中的事件。这就是所谓的单线程事件队列模型。ControllerEventProcessor:Controller 端的事件处理器接口。 ControllerEvent:Controlle...原创 2020-09-27 22:30:30 · 617 阅读 · 0 评论 -
Kafka Controller模块(二):Controller 请求发送
当前,Controller 只会向 Broker 发送三类请求,分别是 LeaderAndIsrRequest、StopReplicaRequest 和 UpdateMetadataRequest。LeaderAndIsrRequest:告诉 Broker 相关主题各个分区的 Leader 副本位于哪台 Broker 上、ISR 中的副本都在哪些 Broker 上。 StopReplicaRequest:告知指定 Broker 停止它上面的副本对象,该请求甚至还能删除副本底层的日志数据...原创 2020-09-27 22:13:24 · 773 阅读 · 0 评论 -
Kafka Controller模块(一):集群元数据ControllerContext
ControllerContext储存kafka集群的元数据,定义如下:class ControllerContext { val stats = new ControllerStats // Controller统计信息类 var offlinePartitionCount = 0 // 离线分区计数器 var shuttingDownBrokerIds: mutable.Set[Int] = mutable.Set.empty // 关闭中Broker的Id列表 private v原创 2020-09-27 22:06:26 · 311 阅读 · 0 评论 -
Kafka日志模块(九):LogCleaner(重复日志数据清理compact)
之前介绍了按照时间空间老化消息的定时任务,本篇来看一下 LogCleaner 线程,如果在配置中指定了 log.cleaner.enable=true,那么在 LogManager#startup 方法的最后会调用 LogCleaner#startup 方法启动 LogCleaner 线程对日志数据执行清理工作。本篇针对配置了 cleanup.policy=compact 策略的清理方式,kafka 的 LogCleaner 线程就会对具备相同 key 的消息进行清理操作,仅保留当前具备最大...原创 2020-09-24 14:38:57 · 2495 阅读 · 0 评论