Kafka Java API 之Producer源码解析

转载 2015年11月20日 10:08:32

原帖地址:http://blog.csdn.net/xeseo/article/details/18315451

从我的OneNote copy过来,格式似乎有点问题,懒得整了。将就着看吧,各位。

    Kafka提供了Producer类作为java producerapi该类有syncasync两种发送方式。

     

    默认是sync方式,即producer的调用类在消息真正发送到队列中去以后才返回,其工作原理如下:

     

  1. new Producer

     

    当我们new了一个kafka java api提供的Producer类时,其底层,实际会产生两个核心类的实例:Producer(Scala的,不是java api提供的那个)DefaultEventHandler。在创建的同时,会默认new一个ProducerPool,即我们每new一个javaProducer类,就会有一个scalaProducerEventHandlerProducerPool

     

  2. producer.send()

    当我们调用javaproducer.send方法时,底层调用scalaProducersend方法,其内部其实调的是eventhandler.handle(message)方法。

    1. eventHandler会首先序列化该消息,

                 eventHandler.serialize(events

     

    1. 然后会根据传入的broker信息、topic信息,去取最新的该topicmetadata信息

    BrokerPartitionInfo.updateInfo

     | -> ClientUtils.fetchTopicMetadata   //创建一个topicMetadataRequest,并随机的选取传入的broker信息中任何一个去取metadata,直到取到为止

             | -> val producer: SyncProducer = ProducerPool.createSyncProducer(producerConfig, shuffledBrokers(i)) //对随机选到的broker会创建一个SyncProducer

                         | -> SyncProducer.send  //发送topicMetadataRequest到该broker去取metadata,获得该topic所对应的所有的broker信息

     

    看到这里也就明白了为什么kafkaapi里面并不要求你提供完整的整个kafka集群的broker信息,而是任选一个或几个。因为在这里它会去你提供的broker取该topic的最新的所有的broker信息。

    这里要注意的是,用于发送topicMetadataRequest的SyncProducer虽然是用ProducerPool.createSyncProducer方法建出来的,但用完并不还回pool,而是直接Close,所以会发现有INFO log打出来

    [INFO] <main> Connected toxxx.xxx.xxx.xxx:9092 for producing

    [INFO] <main> Disconnecting fromxxx.xxx.xxx.xxx:9092

    注意:

    这个刷新metadata并不仅在第一次初始化时做。为了能适应kafka broker运行中因为各种原因挂掉、paritition改变等变化,eventHandler会定期的再去刷新一次该metadata,刷新的间隔用参数topic.metadata.refresh.interval.ms定义,默认值是10分钟。

    这里有三点需要强调:

    1. 不调用send, 不会建立socket,不会去定期刷新metadata
    2. 在每次取metadata时,kafka会单独开一个socket去取metadata,开完再关掉。
    3. 根据取得的最新的完整的metadata,刷新Pool中到broker的连接(第一次建立时,pool里面是空的)
    4. 每10分钟的刷新会直接重新把到每个broker的socket连接重建,意味着在这之后的第一个请求会有几百毫秒的延迟。如果不想要该延迟,把topic.metadata.refresh.interval.ms值改为-1,这样只有在发送失败时,才会重新刷新。Kafka的集群中如果某个partition所在的broker挂了,可以检查错误后重启重新加入集群,手动做rebalance,producer的连接会再次断掉,直到rebalance完成,那么刷新后取到的连接着中就会有这个新加入的broker。

    在ClientUtils.fetchTopicMetadata调用完成后,回到BrokerPartitionInfo.updateInfo继续执行,在其末尾,pool会根据上面取得的最新的metadata建立所有的SyncProducer,即Socket通道producerPool.updateProducer(topicsMetadata)

    注意:

    ProducerPool中,SyncProducer的数目是由该topicpartition数目控制的,即每一个SyncProducer对应一个broker,内部封了一个到该brokersocket连接。

    每次刷新时,会把已存在SyncProducerclose掉,即关闭socket连接,然后新建SyncProducer,即新建socket连接,去覆盖老的。

    如果不存在,则直接创建新的。

     

    1. 然后,才是真正发送数据

    dispatchSerializedData(outstandingProduceRequests)

     

    1. 如果发送失败,会进行重试。重试时,又会刷新metadata,而kafkaleader选举需要一定的时间,所以这次刷新可能需要等待,最大等待时间由参数retry.backoff.ms(默认为100)定义。

    重试最大次数由参数message.send.max.retries定义默认为3

     

     

    async方式通过参数producer.type控制,例子:

    Properties p = new Properties();

    props.put("producer.type", "async");

    ProducerConfig config = new ProducerConfig(props);

    producer = new Producer<String, byte[]>(config);

     

    async方式与sync方式的不同在于,在初始化scalaproducer时,会创建一个ProducerSendThread对象。然后,在调用send时,它并不是直接调用eventHandler.handle方法,而是把消息放入一个长度由queue.buffering.max.messages参数定义的队列(默认10000),当队列满足以下两种条件时,会由ProducerSendThread触发eventHandler.handle方法,把队列中的消息作为一个batch发送

    1. 时间超过queue.buffering.max.ms定义的值,默认5000ms
    2. 队列中当前消息个数超过batch.num.messages定义的值,默认200

     

结论:

1. Kafka提供的java api中的Producer,底层只是维护该topic到每个broker的连接,并不是一个传统意义上的连接池。在使用sync方式时,我们应该自己实现一个连接池,里面包含若干Producer对象,以实现最大化写入效率。我自己写了一个简单的:https://github.com/EdisonXu/simple-kafka-producer-pool

2. 在写入的数据频率不高或要求获得写入结果时,应使用sync方式,否则会因async的等待时间引入额外的延迟

3. 在写入的数据频率很高时,应使用async方式,以batch的形式写入,获得最大效率

相关文章推荐

Delphi7高级应用开发随书源码

  • 2003年04月30日 00:00
  • 676KB
  • 下载

kafka详解三:开发Kafka应用

问题导读 1.Kafka系统由什么组成? 2.Kafka中和producer相关的API是什么? 一、整体看一下Kafka 我们知道,Kaf...

Kafka源码深度解析-序列4 -Producer -network层核心原理

在上一篇我们分析了Java NIO的原理和使用方式,本篇将进一步分析Kafka client是如何基于NIO构建自己的network层。network层的分层架构下图展示了从最上层的KafkaProd...

Kafka Java API 之Producer源码解析

本文系原创,转载请注明! 原帖地址: 从我的OneNote copy过来,格式似乎有点问题,懒得整了。将就着看吧,各位。 Kafka 提供了Producer类作为java producer ...
  • xeseo
  • xeseo
  • 2014年01月15日 17:15
  • 8827

kafka介绍,安装以及简单的java调用kafka代码

kafka介绍,安装以及简单的java调用kafka代码
  • hwssg
  • hwssg
  • 2015年10月01日 20:50
  • 15694

java编写Producer(线程池,kafka)

1.将kafka带的jar包导入项目内 2.public class TestThreadPool{ public static void main(String args[]){ /...

Kafka Java API示例

Kafka Java API示例

kafka源码分析之producer

kafka源码分析之kafka producer发送数据源码分析

Kafka producer程序本地运行时发送信息失败解决方案

kafka.common.FailedToSendMessageException: Failed to send messages解决办法
  • yxinzju
  • yxinzju
  • 2015年12月11日 12:02
  • 4332

kafka 连接不上的解决方法

安装了kafka ,使用kafka本地的console-producer 可以成功的发送log, 但是不能在别的节点使用java api发送message。提示错误: kafka.common.Fai...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Kafka Java API 之Producer源码解析
举报原因:
原因补充:

(最多只允许输入30个字)