Kafka 之 async producer (1)
问题
- 很多条消息是怎么打包在一起的?
- 如果消息是发给很多不同的topic的, async producer如何在按batch发送的同时区分topic的
- 它是如何用key来做partition的?
- 是如何实现对消息成批量的压缩的?
async producer是将producer.type设为async时启用的producer
此时,调用send方法的线程和实际完成消息发送的线程是分开的。
当调用java API中producer的send方法时,最终会调用kafka.producer.Producer的send方法。在kafka.producer.Producer类中,会根据producer.type配置使用不同的方法发送消息。
def send(messages: KeyedMessage[K,V]*) {
lock synchronized {
if (hasShutdown.get)
throw new ProducerClosedException
recordStats(messages)
sync match {
case true => eventHandler.handle(messages)
case false => asyncSend(messages)
}
}
}
当async时,会使用asyncSend。asyncSend方法会根据“queue.enqueue.timeout.ms”配置选项采用BlockingQueue的put或offer方法把消息放入kafka.producer.Producer持有的一个LinkedBlockingQueue。一个ProducerSendThread线程从queue里取消息,成批量的用eventHandler来处理。
当使用sync时,对每条消息会直接使用eventHandler来处理。这就是为什么前一种方式会被称为"asynchornization",而这一种会称为”synchronization"
private val queue = new LinkedBlockingQueue[KeyedMessage[K,V]](config.queueBufferingMaxMessages)
在kafka.producer.Producer构造时,会检查"producer.type“,如果是asnyc,就会开启一个送发线程。
config.producerType match {
case "sync" =>
case "async" =>
sync = false
producerSendThread = new ProducerSendThread[K,V]("ProducerSendThread-" + config.clientId,
queue,
eventHandler,
config.queueBufferingMaxMs,
config.batchNumMessages,
config.clientId)
producerSendThread.start()
现在有了一个队列,一个发送线程 。看来这个ProducerSendThread是来完成大部分发送的工作,而"async"的特性都主要都是由它来实现。
这个线程的run方法实现为:
override def run {
try {
processEvents
}catch {
case e: Throwable => error("Error in sending events: ", e)
}finally {
shutdownLatch.countDown
}
}
看来实际工作由processEvents方法来实现喽
private def processEvents() {
var lastSend = SystemTime.milliseconds //上一次发送的时间,每发送一次会更新
var events = new ArrayBuffer[KeyedMessage[K,V]] //一起发送的消息的集合,发送完后也会更新
var full: Boolean = false //是否消息的数量已大于指定的batch大小(batch大小指多少消息在一起发送,由"batch.num.messages"确定) // drain the queue until you get a shutdown command
//构造一个流,它的每个元素为queue.poll(timeout)取出来的值。
//timeout的值是这么计算的:lastSend+queueTime表示下次发送的时间,再减去当前时间,就是最多还能等多长时间,也就是poll阻塞的最长时间
//takeWhile接受的函数参数决定了当item是shutdownCommand时,流就结束了。这个shutdownCommand是shutdown()方法执行时,往队列里发的一个特殊消息
Stream.continually(queue.poll(scala.math.max(0, (lastSend + queueTime) - SystemTime.milliseconds), TimeUnit.MILLISECONDS))
.takeWhile(item => if(item != null) item ne shutdownCommand else true).foreach {
currentQueueItem => //对每一条处理的消息
val elapsed = (SystemTime.milliseconds - lastSend) //距上次发送已逝去的时间,只记录在debug里,并不会以它作为是否发送的条件
// check if the queue time is reached. This happens when the poll method above returns after a timeout and
// returns a null object
val expired = currentQueueItem == null //当poll方法超时,就返回一个null,说明一定已经是时候发送这批消息了。当时间到了,poll(timeout)中timeout为负值时,poll一定返回null
if(currentQueueItem != null) {
trace("Dequeued item for topic %s, partition key: %s, data: %s"
.format(currentQueueItem.topic, currentQueueItem.key, currentQueueItem.message))
events += currentQueueItem //如果当前消息不为空,就附加在发送集合里
} // check if the batch size is reached
full = events.size >= batchSize //是否当前发送集合的大小已经大于batch size if(full || expired) { //如果发送集合有了足够多的消息或者按时间计可以发送了,就发送
if(expired)
debug(elapsed + " ms elapsed. Queue time reached. Sending..")
if(full)
debug("Batch full. Sending..")
// if either queue time has reached or batch size has reached, dispatch to event handler
tryToHandle(events)
lastSend = SystemTime.milliseconds //更新lastSend,将一个新的ArrayBuffer的引用赋给events
events = new ArrayBuffer[KeyedMessage[K,V]]
}
}
// send the last batch of events
tryToHandle(events) //当shutdownCommand遇到时,流会终结。此时之前的消息只要不是恰好发送完,就还会有一些在events里,做为最后一批发送。
if(queue.size > 0) //些时producerSendThread已经不再发消息了,但是queue里若还有没发完的,就是一种异常情况
throw new IllegalQueueStateException("Invalid queue state! After queue shutdown, %d remaining items in the queue"
.format(queue.size))
}
看来Scala的Stream帮了不少忙。shutdown方法将一个特殊的shutdownCommand发给queue,也正好使得这个Stream可以用takeWhile方法正确结束。
好吧,搞了这么多,这个ProducerSendThread只有打包的逻辑 ,并没有处理topic、partition、压缩的逻辑,这些逻辑都在另一个类中。明天再来看看这个handler
Kafka 之 async producer (1)的更多相关文章
- Kafka 之 async producer (2) kafka.producer.async.DefaultEventHandler
上次留下来的问题 如果消息是发给很多不同的topic的, async producer如何在按batch发送的同时区分topic的 它是如何用key来做partition的? 是如何实现对消息成批量的 ...
- Kafka 0.8 Producer处理逻辑
Kafka Producer产生数据发送给Kafka Server,具体的分发逻辑及负载均衡逻辑,全部由producer维护. 1.Kafka Producer默认调用逻辑 1.1 默认Partiti ...
- Kafka设计解析(二十一)关于Kafka幂等producer的讨论
转载自 huxihx,原文链接 关于Kafka幂等producer的讨论 众所周知,Kafka 0.11.0.0版本正式支持精确一次处理语义(exactly once semantics,下称EOS) ...
- apache kafka系列之Producer处理逻辑
最近研究producer的负载均衡策略,,,,我在librdkafka里边用代码实现了partition 值的轮询方法,,,但是在现场验证时,他的负载均衡不起作用,,,所以来找找原因: 下文是一篇描 ...
- Kafka 0.8 Producer (0.9以前版本适用)
Kafka旧版本producer由scala编写,0.9以后已经废除,但是很多公司还在使用0.9以前的版本,所以总结如下: 要注意包Producer是 kafka.javaapi.producer.P ...
- kafka性能测试(转)KAFKA 0.8 PRODUCER PERFORMANCE
来自:http://blog.liveramp.com/2013/04/08/kafka-0-8-producer-performance-2/ At LiveRamp, we constantly ...
- Kafka 0.10 Producer网络流程简述
1.Producer 网络请求 1.1 Producer Client角度 KafkaProducer主要靠Sender来发送数据给Broker. Sender: 该线程handles the sen ...
- springboot kafka集成(实现producer和consumer)
本文介绍如何在springboot项目中集成kafka收发message. 1.先解决依赖 springboot相关的依赖我们就不提了,和kafka相关的只依赖一个spring-kafka集成包 &l ...
- Apache Kafka - KIP-42: Add Producer and Consumer Interceptors
kafka 0.10.0.0 released Interceptors的概念应该来自flume 参考,http://blog.csdn.net/xiao_jun_0820/article/det ...
随机推荐
- 小生功能贴<一> --- 动态添加应用 具有长按删除功能
---恢复内容开始--- 动态添加应用 具有长按删除功能 功能如下图: (图片显示功能不是你要的,那就默默关闭页面吧) 设计思路: 页面一:用girdview网格显示图标 ...
- 如何查看JDK是64bit还是32bit
在eclipse或MyEclipse中创建一个Java Project并运行如下代码: public class Test { public static void main(String[] arg ...
- 个人实验记录之EIGRP基本配置
一.EIGRP的基本配置 1(1).进入接口配置IP R1(config)#inter s1/0 R1(config-if)#ip address 200.1.1.1 255.255.255.0 R1 ...
- Linux multiple open a device
Linux multiple open a device a device = /dev/wiegand Linux在多次打开同一个设备(/dev/wiegand)的时候,打开结果都是成功,但是在用w ...
- Poj OpenJudge 百练 1860 Currency Exchang
1.Link: http://poj.org/problem?id=1860 http://bailian.openjudge.cn/practice/1860 2.Content: Currency ...
- Android SDK Manager国内无法更新的解决方案
万里长城永不倒,千里黄河水滔滔.算了跑题了. 但还是要吐槽这下这个万里长城,感谢 方滨兴 叫兽 给我们净化了互联网,靠!什么&!@#¥ 此处略去一万字. 现在由于GWF,google基本和咱们 ...
- PHP实现获得一段时间内所在的所有周的时间
function getWeek($startdate,$enddate) { //参数不能为空 if(!empty($startdate) && !empty($enddate)){ ...
- 超棒的阿里巴巴矢量图标库——支持IE6
Iconfont.cn 是由阿里巴巴UX部门推出的矢量图标管理网站,也是国内首家推广Webfont形式图标的平台.网站涵盖了1000多个常用图标并还在持续更新 中,Iconfont平台为用户提供在线图 ...
- DB2分区表删除和添加分区
1.数据库版本 2.具体procedure DROP PROCEDURE DB2USER.TOOLS_PARTITION_TABLE_SHOW (VARCHAR ()); )) /********** ...
- 使用saltstack批量部署服务器运行环境事例——批量部署nagios客户端
之前关于搭建web服务器集群实验的这篇文章http://www.cnblogs.com/cjyfff/p/3553579.html中,关于如何用saltstack批量部署服务器这一点当时没有记录到文章 ...