问题

  1. 很多条消息是怎么打包在一起的?
  2. 如果消息是发给很多不同的topic的, async producer如何在按batch发送的同时区分topic的
  3. 它是如何用key来做partition的?
  4. 是如何实现对消息成批量的压缩的?

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)的更多相关文章

  1. Kafka 之 async producer (2) kafka.producer.async.DefaultEventHandler

    上次留下来的问题 如果消息是发给很多不同的topic的, async producer如何在按batch发送的同时区分topic的 它是如何用key来做partition的? 是如何实现对消息成批量的 ...

  2. Kafka 0.8 Producer处理逻辑

    Kafka Producer产生数据发送给Kafka Server,具体的分发逻辑及负载均衡逻辑,全部由producer维护. 1.Kafka Producer默认调用逻辑 1.1 默认Partiti ...

  3. Kafka设计解析(二十一)关于Kafka幂等producer的讨论

    转载自 huxihx,原文链接 关于Kafka幂等producer的讨论 众所周知,Kafka 0.11.0.0版本正式支持精确一次处理语义(exactly once semantics,下称EOS) ...

  4. apache kafka系列之Producer处理逻辑

     最近研究producer的负载均衡策略,,,,我在librdkafka里边用代码实现了partition 值的轮询方法,,,但是在现场验证时,他的负载均衡不起作用,,,所以来找找原因: 下文是一篇描 ...

  5. Kafka 0.8 Producer (0.9以前版本适用)

    Kafka旧版本producer由scala编写,0.9以后已经废除,但是很多公司还在使用0.9以前的版本,所以总结如下: 要注意包Producer是 kafka.javaapi.producer.P ...

  6. kafka性能测试(转)KAFKA 0.8 PRODUCER PERFORMANCE

    来自:http://blog.liveramp.com/2013/04/08/kafka-0-8-producer-performance-2/ At LiveRamp, we constantly ...

  7. Kafka 0.10 Producer网络流程简述

    1.Producer 网络请求 1.1 Producer Client角度 KafkaProducer主要靠Sender来发送数据给Broker. Sender: 该线程handles the sen ...

  8. springboot kafka集成(实现producer和consumer)

    本文介绍如何在springboot项目中集成kafka收发message. 1.先解决依赖 springboot相关的依赖我们就不提了,和kafka相关的只依赖一个spring-kafka集成包 &l ...

  9. 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 ...

随机推荐

  1. 小生功能贴<一> --- 动态添加应用 具有长按删除功能

    ---恢复内容开始--- 动态添加应用 具有长按删除功能 功能如下图:                (图片显示功能不是你要的,那就默默关闭页面吧) 设计思路: 页面一:用girdview网格显示图标 ...

  2. 如何查看JDK是64bit还是32bit

    在eclipse或MyEclipse中创建一个Java Project并运行如下代码: public class Test { public static void main(String[] arg ...

  3. 个人实验记录之EIGRP基本配置

    一.EIGRP的基本配置 1(1).进入接口配置IP R1(config)#inter s1/0 R1(config-if)#ip address 200.1.1.1 255.255.255.0 R1 ...

  4. Linux multiple open a device

    Linux multiple open a device a device = /dev/wiegand Linux在多次打开同一个设备(/dev/wiegand)的时候,打开结果都是成功,但是在用w ...

  5. Poj OpenJudge 百练 1860 Currency Exchang

    1.Link: http://poj.org/problem?id=1860 http://bailian.openjudge.cn/practice/1860 2.Content: Currency ...

  6. Android SDK Manager国内无法更新的解决方案

    万里长城永不倒,千里黄河水滔滔.算了跑题了. 但还是要吐槽这下这个万里长城,感谢 方滨兴 叫兽 给我们净化了互联网,靠!什么&!@#¥ 此处略去一万字. 现在由于GWF,google基本和咱们 ...

  7. PHP实现获得一段时间内所在的所有周的时间

    function getWeek($startdate,$enddate) { //参数不能为空 if(!empty($startdate) && !empty($enddate)){ ...

  8. 超棒的阿里巴巴矢量图标库——支持IE6

    Iconfont.cn 是由阿里巴巴UX部门推出的矢量图标管理网站,也是国内首家推广Webfont形式图标的平台.网站涵盖了1000多个常用图标并还在持续更新 中,Iconfont平台为用户提供在线图 ...

  9. DB2分区表删除和添加分区

    1.数据库版本 2.具体procedure DROP PROCEDURE DB2USER.TOOLS_PARTITION_TABLE_SHOW (VARCHAR ()); )) /********** ...

  10. 使用saltstack批量部署服务器运行环境事例——批量部署nagios客户端

    之前关于搭建web服务器集群实验的这篇文章http://www.cnblogs.com/cjyfff/p/3553579.html中,关于如何用saltstack批量部署服务器这一点当时没有记录到文章 ...