Kafka - 生产者初步学习

原创 2018年04月17日 14:21:56

Kafka - 生产者初步学习


一、kafka生产者组件

kafka.png-157.9kB

  1. 我们从创建一个 ProducerRecord 对象开始,ProducerRecord 对象需要包含目标主题和要发送的内容。我们还可以指定键或分区。在发送 ProducerRecord 对象时,生产者要先把键和值对象序列化成字节数组,这样它们才能够在网络上传输。
  2. 接下来,数据被传给分区器。如果之前在 ProducerRecord 对象里指定了分区,那么分区器就不会再做任何事情,直接把指定的分区返回。如果没有指定分区,那么分区器会根据 ProducerRecord 对象的键来选择一个分区。
  3. 选好分区以后,生产者就知道该往哪个主题和分区发送这条记录了。紧接着,这条记录被添加到一个记录批次里,这个批次里的所有消息会被发送到相同的主题和分区上。有一个独立的线程负责把这些记录批次发送到相应的 broker 上。
  4. 服务器在收到这些消息时会返回一个响应。如果消息成功写入 Kafka,就返回一个 RecordMetaData 对象,它包含了主题和分区信息,以及记录在分区里的偏移量。如果写入失败,则会返回一个错误。生产者在收到错误之后会尝试重新发送消息,几次之后如果还是失败,就返回错误信息。

二、使用Java API创建生产者

2.1 pom文件依赖

<properties>
    <java.version>1.8</java.version>
    <kafka.version>1.1.0</kafka.version>
</properties>


<dependencies>
    <dependency>
        <groupId>org.apache.kafka</groupId>
        <artifactId>kafka-clients</artifactId>
        <version>${kafka.version}</version>
    </dependency>
</dependencies>

目前kafka的最新稳定版本为1.1.0,因此本次也是用配套的客户端版本api。

2.2 连接必备属性

要往 Kafka 写入消息,首先要创建一个生产者对象,并设置一些属性。Kafka 生产者有 3 个必选的属性。

  1. bootstrap.servers:该属性指定了 broker 的地址清单,地址的格式为host:port。清单中不需要包含所有的borker地址,生产者会从给定的 broker 里面寻找其他的 broker 信息。不过在实际使用的时候,建议提供至少两个 broker 信息。这是因为一旦其中一个机器宕机,生产者仍然能够连接在集群上。
  2. key.serializer:broker 希望接受到的信息都是字节数组,生产者接口允许使用参数化类型,因此可以把 Java 对象作为键和值发送给 broker。这样的代码具有良好的可读性。但是生产者本身并不清楚如何讲 Java 对象序列化为字节数组,因此我们需要设置这个属性为一个实现了org.apache.kafka.common.serialization.Serializer接口的类,生产者就会使用这个类把键对象序列化为字节数组。
  3. value.serializer:与 key.serializer 一样,value.serializer 指定的类会将值进行序列化。如果键和值均为同一个数据类型,那么使用同一个序列化器。如果数据类型不同,则需要使用不同的序列化器。

注:
Kafka客户端目前只提供了如下的序列化器:

  1. ByteArraySerializer
  2. StringSerializer
  3. IntegerSerializer

当只使用常见的 Java 对象的时候无需自定义序列化器,但是当有其他需求的时候,就需要自己实现。同时要注意的是:就算你只打算发送 值(value), key.serializer 属性也是必须设置的。

一下是个代码段,这里只指定了必要的属性

import java.util.Properties;

Properties kafkaProps = new Properties();
kafkaProps.put("bootstrap.servers", "master:9092");
kafkaProps.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
kafkaProps.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");

三、kafka发送方式

接下来只需要实例化生产者对象,就可以发送消息。发送消息目前主要有三种方式:

  1. 发送并忘记(fire-and-forget)
  2. 同步发送
  3. 异步发送

3.1 发送并忘记(fire-and-forget)

我们把消息发送给服务器,但并不关心它是否正常到达。大多数情况下,消息会正常到达,因为 Kafka 是高可用的,而且生产者会自动尝试重发。不过,使用这种方式有时候也会丢失一些消息。

public static void main(String[] args) {
    Properties kafkaProps = new Properties();
    kafkaProps.put("bootstrap.servers", "master:9092");
    kafkaProps.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
    kafkaProps.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");

    KafkaProducer producer = new KafkaProducer<String, String>(kafkaProps);

    ProducerRecord<String, String> record = new ProducerRecord<>("test", "Precision Products", "USA");

    try {
        producer.send(record);
    } catch (Exception e) {
        e.printStackTrace();
    }
}
  1. 生产者的 send() 方法将 ProducerRecord 对象作为参数,所以我们要先创建一个 ProducerRecord 对象。
  2. 我们使用生产者的 send() 方法发送 ProducerRecord 对象。从生产者的架构图里可以看到,消息先是被放进缓冲区,然后使用单独的线程发送到服务器端。send() 方法会返回一个包含 RecordMetadata 的 Future 对象,不过因为我们会忽略返回值,所以无法知道消息是否发送成功。如果不关心发送结果,那么可以使用这种发送方式。比如,记录 Twitter 消息日志,或记录不太重要的应用程序日志。
  3. 我们可以忽略发送消息时可能发生的错误或在服务器端可能发生的错误,但在发送消息之前,生产者还是有可能发生其他的异常。这些异常有可能是 SerializationException(说明序列化消息失败)、BufferExhaustedException 或 TimeoutException(说明缓冲区已满),又或者是 InterruptException(说明发送线程被中断)。

3.2 同步发送

我们使用 send() 方法发送消息,它会返回一个 Future 对象,调用 get() 方法进行等待,就可以知道消息是否发送成功。

public static void main(String[] args) {
    Properties kafkaProps = new Properties();
    kafkaProps.put("bootstrap.servers", "master:9092");
    kafkaProps.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
    kafkaProps.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");

    KafkaProducer producer = new KafkaProducer<String, String>(kafkaProps);

    ProducerRecord<String, String> record = new ProducerRecord<>("test", "Precision Products", "USA");

    try {
        producer.send(record).get();
    } catch (Exception e) {
        e.printStackTrace();
    }
}
  1. 在这里,producer.send() 方法先返回一个 Future 对象,然后调用 Future 对象的 get() 方法等待 Kafka 响应。如果服务器返回错误,get() 方法会抛出异常。如果没有发生错误,我们会得到一个 RecordMetadata 对象,可以用它获取消息的偏移量。
  2. 如果在发送数据之前或者在发送过程中发生了任何错误,比如 broker 返回了一个不允许重发消息的异常或者已经超过了重发的次数,那么就会抛出异常。我们只是简单地把异常信息打印出来。

3.3 异步发送

我们调用 send() 方法,并指定一个回调函数,服务器在返回响应时调用该函数。

假设消息在应用程序和 Kafka 集群之间一个来回需要 10ms。如果在发送完每个消息后都等待回应,那么发送 100 个消息需要 1 秒。但如果只发送消息而不等待响应,那么发送 100 个消息所需要的时间会少很多。

大多数时候,我们并不需要等待响应——尽管 Kafka 会把目标主题、分区信息和消息的偏移量发送回来,但对于发送端的应用程序来说不是必需的。不过在遇到消息发送失败时,我们需要抛出异常、记录错误日志,或者把消息写入“错误消息”文件以便日后分析。

为了在异步发送消息的同时能够对异常情况进行处理,生产者提供了回调支持。下面是使用回调的一个例子。

public static void main(String[] args) {
    Properties kafkaProps = new Properties();
    kafkaProps.put("bootstrap.servers", "master:9092");
    kafkaProps.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
    kafkaProps.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");

    KafkaProducer producer = new KafkaProducer<String, String>(kafkaProps);

    ProducerRecord<String, String> record = new ProducerRecord<>("test", "Precision Products", "USA");

    try {
        producer.send(record, new DemoProducerCallback());
    } catch (Exception e) {
        e.printStackTrace();
    }
}

private static class DemoProducerCallback implements Callback {
    @Override
    public void onCompletion(RecordMetadata metadata, Exception exception) {
        if (exception != null) {
            exception.printStackTrace();
        }
    }
}
  1. 为了使用回调,需要一个实现了 org.apache.kafka.clients.producer.Callback 接口的类,这个接口只有一个 onCompletion 方法。
  2. 如果 Kafka 返回一个错误,onCompletion 方法会抛出一个非空(non null)异常。这里我们只是简单地把它打印出来,但是在生产环境应该有更好的处理方式。
  3. 在发送消息时传进去一个回调对象。

3.4 注意

KafkaProducer 一般会发生两类错误。

  • 其中一类是可重试错误,这类错误可以通过重发消息来解决。比如对于连接错误,可以通过再次建立连接来解决,“无主(no
    leader)”错误则可以通过重新为分区选举首领来解决。KafkaProducer
    可以被配置成自动重试,如果在多次重试后仍无法解决问题,应用程序会收到一个重试异常。
  • 另一类错误无法通过重试解决,比如“消息太大”异常。对于这类错误,KafkaProducer 不会进行任何重试,直接抛出异常。
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u011669700/article/details/79974275

kafka生产者客户端——那年我趟过的坑

前言: 最近有个需求需要用到kafka中间件做消息队列的中间件,于是看了某博客上的一些kafka生产者博文,参考地写了个程序,但是It dosn"t work.一开始还以为我编码问题,但 我发...
  • sunrise_zhu
  • sunrise_zhu
  • 2017-04-11 11:30:37
  • 2365

kafka 生产者和消费者实例

一、环境安装配置 1、去官网下载kafka 我下载的版本是 kafka_2.11-0.10.0.1.tgz,下面的实例也是基于该版本。 2、解压安装 tar -xzf kafka_2.11-0.10....
  • wanghuiqi2008
  • wanghuiqi2008
  • 2016-09-27 20:14:00
  • 6074

Kafka的生产者与消费者

创建一个maven工程,程序的结构如下:pom文件
  • qq_20641565
  • qq_20641565
  • 2017-03-08 00:37:19
  • 3685

kafka 自定义生产者示例

代码如下: public class SendMessage { /** * 自定义kafka生产者demo */ public static void main(String[] ar...
  • BrotherDong90
  • BrotherDong90
  • 2015-12-02 15:51:11
  • 625

kafka的生产者和消费者的理解

Producers     Producer将消息发布到指定的Topic中,同时Producer也能决定将此消息归属于哪个partition;比如基于"round-robin"方式或者通过其他的一些...
  • yz7074998
  • yz7074998
  • 2015-04-09 16:46:14
  • 3530

Kafka消费者生产者实例

为了更为直观展示Kafka的消息生产消费的过程,我会从基于Console和基于Application两个方面介绍使用实例。Kafka是一个分布式流处理平台,具体来说有三层含义: 它允许发布和订阅记录流...
  • u011116672
  • u011116672
  • 2017-07-30 18:22:56
  • 3933

kafka生产者原理详解

1. 介绍 以前分享过一篇文章kafka原理以及设计实现思想,但是很多东西讲的还是不够深入。今天这篇文章主要分析下生产者的具体设计和原理。 这篇文章参考了很多其他资料,使用的版本也较老,基...
  • jiiiang400
  • jiiiang400
  • 2017-05-25 11:26:39
  • 1122

Kafka学习(六):Kafka的生产者编程模型

Kafka的生产模型分为两种: 1.同步生产模型(一条一条的发送) 2.异步生产模型(很多条等待后,一次性发送)       生产者每次都发送一条消息都会等待,zooke...
  • ZuoAnYinXiang
  • ZuoAnYinXiang
  • 2016-04-27 18:05:12
  • 1037

kafka生产者

kafka生产者对象
  • huxin889
  • huxin889
  • 2017-01-09 16:35:24
  • 294

kafka生产者消费者Demo

  • 2016年12月21日 17:28
  • 44.83MB
  • 下载
收藏助手
不良信息举报
您举报文章:Kafka - 生产者初步学习
举报原因:
原因补充:

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