kafka的线程模型之二

本文深入探讨Kafka的ExpirationReaper线程和Executor-Fetch线程,如何通过时间轮实现高效的定时任务管理,以处理DelayedFetch、DelayedProduce等操作的超时返回机制。时间轮采用delayQueue,由多个ExpirationReaper线程推进时间刻度并处理未取消的任务,Executor-Fetch线程负责执行任务。
摘要由CSDN通过智能技术生成

上一篇文章介绍了四种kafka的线程.

acceptor线程,负责接收新的tcp连接,并交给network线程.

network线程,负责与客户端或者其他broker的网络通行.

硬盘I/O线程.负责将producer或者consumer的数据,写入读出磁盘.

scheduler线程,定时负责flush磁盘,合并数据,更新index文件.


这篇文章将介介绍, ExpirationReaper 线程以及与之配套的Excecuter-fetch线程.

首先kafka中的kafka.server下可以看到,DelayedFetch,DelayedProduce,DelayedCreateTopics以及DelayedDeleteTopics这四个类,

这些类存在的目的是为了什么? 原因是kafka中有一些操作是无法也不需要同步返回的,需要实现超时返回失败的机制,比如如下的例子:

DelayedFetch 用过kafka-client的同学一定知道,自己在consume某一个topic的时候会设置batch-size.kafka尽量使消息能够批量的传递,在消费某一topic时,producer只要产生任意一条数据,就返回给订阅的consumer显然是不合适的也是低效的. 所以kafka返回数据给consumer会满足其中两个条件一下的一个1.累计到一定的消息大小或者条数.2.fetchRequest请求超过一定的时间阈值没有回应. 来保证consumer的高效.


DelayedProduce,用过kafka-client的同学一定知道.自己在produce某一个topic的时候会设置是否需要ack,分为不需要ack,在partition的leader上存下就返回ack或者在所有的ISR中存下才返回ack这几种情况.在最后一种所有ISR都存下Ack的要求下,broker无法确定在什么时候ISR中的broker会存下消息甚至不能保证ISR可以百分之百存下消息.所以kafka返回Ack给producer就会满足其中两个条件的一个1.所有的ISR都存下了数据.2.有的ISR超过一定时间都没能成功存下数据.


DelayedCreateTopics,kafka会根据规则,安排不同的leader给不同的partition,但是kafka集群的leader无法保证所有的定为partition leader的broker都能按照自己的要求成为leader.


DelayedDeleteTopic.道理同上,集群的leader无法保证follower中的partition leader能成功地删除数据.


就上面几种情况,我们可以知道.kafka需要一种高效的定时机制来完成这些定时任务,因为fetch与produce这两个请求可以说是kafka中最频繁的请求了,要是用朴素的方法比如一个请求一个线程再sleep(timeout)那么系统的资源会被很快用完的.针对这个问题kafka的解决方案便是:时间轮.

kafka的时间轮其实是很有意思的,因为我之前看过netty的时间轮源码,netty的时间轮写的很朴素,看到kafka的时间轮时有一种很惊艳的感觉.但是在这边我不会详细介绍,之后会专门写文章对比两者的时间轮有何异同的,在这里仅仅做简单的介绍.

kafka的时间轮是使用java中的delayQueue作为辅助的,可以理解为n个ExpirationReaper线程,阻塞在delayQueue的poll上,

"ExpirationReaper-12" #53 prio=5 os_prio=0 tid=0x00007fadb4d30000 nid=0x11a7e waiting on condition [0x00007fac1ebee000]
   java.lang.Thread.State: TIMED_WAITING (parking)
	at sun.misc.Unsafe.park(Native Method)
	- parking to wait for  <0x00000000c88a5e70> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
	at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2078)
	at java.util.concurrent.DelayQueue.poll(DelayQueue.java:259)
	at kafka.utils.timer.SystemTimer.advanceClock(Timer.scala:106)
	at kafka.server.DelayedOperationPurgatory.advanceClock(DelayedOperation.scala:350)
	at kafka.server.DelayedOperationPurgatory$ExpiredOperationReaper.doWork(DelayedOperation.scala:374)
	at kafka.utils.ShutdownableThread.run(ShutdownableThread.scala:63)

每次delayQueue会把到时间的任务返回给某一线程,这个苏醒的delayQueue负责

1.推进时间轮的刻度

2.判断这一任务有没有被取消,如果没有被取消,那么把ta交给Executor-Fetch线程处理

而Executor-Fetch是一个大小为1的ExecutorPool

Executors.newFixedThreadPool(1, new ThreadFactory() {
  def newThread(runnable: Runnable): Thread =
    Utils.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值