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 ...
随机推荐
- firebug调试js时提示调试器未激活处理办法
firebug是web开发中最常用的分析调试软件,不过我今天使用在调试百度在线编辑器UEditor时一直提示调试器未激活. 从使用经验来看不应该啊,我都下了断点了为什么会提示调试器未激活呢!多次载入网 ...
- 169. Majority Element My Submissions Question
Total Accepted: 95925 Total Submissions: 239241 Difficulty: Easy Given an array of size n, find the ...
- C#对象XML序列化
1.Xml序列化操作类 .Net Framework提供了对应的System.Xml.Seriazliation.XmlSerializer负责把对象序列化到XML,和从XML中反序列化为对象. 以下 ...
- System.Windows.Forms.Timer反编译学习
using System; using System.ComponentModel; using System.Globalization; using System.Runtime; using S ...
- spring aop配置及用例说明(2)
欢迎交流转载:http://www.cnblogs.com/shizhongtao/p/3473362.html 这里先介绍下几个annotation的含义, @Before:表示在切入点之前执行. ...
- map容器按value值排序
1 vector<pair<key,value> >类型的容器中存放所有元素,sort(pair默认按照value比较大小?) 2 map<value,key>
- HTML5之广播聊天室
- 服务器端广播文本- 所有客户端都可以收到 --- 客户端 - 定义文本框- 定义发送事件 textarea accesskey =t oninput="sendmsg();"- ...
- Nodejs 处理gb2312内容乱码问题
在使用cheerio处理request模块返回的gb2312网页出现了乱码,从开始一直排查问题,一直排查到request.cheerio都有问题. 首先request会进行一次转码,这里需要设置req ...
- Easyui 生成layout
Easyui 生成layout var $tabs; var $body; var $south; function appendLayout(title, href) { if (!$body) $ ...
- C# CRC32
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threa ...