一个应用程序在很多情况下需要往Kafka写入消息:记录用户的活动(用于审计和分析),记录度量指标,保存日志消息,记录智能家电的信息,与其他应用程序进行异步通信,缓冲即将写入到数据库的数据,等等。

多样的使用场景意味着多样的需求:是否每个消息都很重要?是否允许丢失一小部分消息?偶尔出现重复消息是否可以接受?是否有严格的延迟和吞吐量要求?

不同的使用场景对生产者API的使用和配置会有直接的影响。

消息发送过程

首先创建一个ProducerRecord对象。

  ProducerRecord对象包含目标主题和要发送的内容。

  可以指定键或分区。

如果有键的话,将键序列化成字节数组,以便在网络上传输。同样地,要发送的内容,即值,也需要序列化成字节数组。

接下来,数据被传给分区器。

  如果之前在ProducerRecord对象里指定了分区,那么分区器就不会再做任何事情,直接把指定的分区返回。

  如果没有指定分区,那么分区器会根据ProducerRecord对象的键来选择一个分区。

选好分区后,生产者就知道该往哪个主题和分区发送记录了。

紧接着,这条记录被添加到了一个记录批次里。

  这个批次里的所有消息都会被发送到相同的主题和分区上。

  有一个独立的线程负责把这些记录批次发送到相应的broker上。

服务器在收到这些消息时会返回一个相应。

  如果消息成功写入Kafka,就返回一个RecordMetaData对象,它包含了主题和分区信息,以及记录在分区里的偏移量。

  如果写入失败,则会返回一个错误。

生产者在接收到错误之后会尝试重新发送消息,几次之后如果还是失败,就返回错误信息。

发送消息的方式

生产者可以使用单个消费者单个线程,也可以使用单个消费者多个线程。

或者增加消费者。

发送并忘记

producer.send(record)

我们把消息发送给服务器,但并不关心它是否正常到达。

大多数情况下,消息会正常到达, 因为Kafka是高可用的,而且生产者会自动尝试重发。

不过这种方式有时候也会丢失一些消息。

同步发送

producer.send(record).get()

如果服务器返回错误,get()方法会抛出异常。如果没有发生错误,我们会的到一个RecordMetadata对象,可以用它获取消息的偏移量。

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

异步发送

producer.send(record, ? extends org.apache.kafka.clients.producer.Callback)

Callback接口只有一个onCompletion方法。

如果Kafka返回一个错误,onCompletion方法会抛出一个非空异常。

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

KafkaProducer异常

KafkaProducer一般会发生两类错误。

其中一类是可重试错误。这类错误通过重发消息来解决。比如连接错误,无主错误等。KafkaProducer可以被配置成自动测试,如果在多次重试后仍无法解决问题,应用程序会收到一个重试异常。

另一类错误无法通过重试解决,比如消息太大异常。对于这类错误,KafkaProducer不会进行任何重试,直接抛出异常。

生产者配置

org.apache.kafka.clients.producer.ProducerConfig

bootstrap.servers

该属性指定broker的地址清单,地址的格式为host:port。

清单不需要包含所有的broker地址,生产者会从给定的broker里查找到其他broker的信息。

建议至少要提供两个broker的信息,一旦其中一个单机,生产者仍然能够连接到集群上。

该参数为必选参数。

key.serializer

broker希望接收到的消息的键和值都是字节数组。

生产者接口允许使用参数化类型,因此可以把Java对象作为键和值发送给broker。这样的代码具有良好的可读性,不过生产者需要知道如何把这些Java对象转化成字节数组。

key。serializer必须被设置为一个实现了org.apache.kafka.common.serialization.Serializer接口的类,生产者会使用这个类把键对象序列化成字节数组。

Kafka客户端默认提供了ByteArraySerializer,StringSerializer和IntegerSerializer。

该参数必须设置,即使只发送值。

value.serializer

用指定的类将值序列化。

该参数必须设置。

acks

acks参数指定了必须要有多少个分区副本接收到消息,生产者才会认为消息写入是陈宫的。

这个参数对消息丢失的可能性有重要影响。

该参数有如下选项:

  acks=0.生产者在写入消息之前不会等待任何来自服务器的响应。所以该值可以以网络能够支持的最大速度发送消息,从而达到很高的吞吐量。

  acks=1.只要集群的首领结点接收到消息,生产者就会收到一个来自服务器的成功响应。如果首领结点发生崩溃,一个没有收到消息的结点称为新首领,消息将丢失。

  acks=all.只有当所有参与复制的结点全部接收到消息时,生产者才会收到一个来自服务器的成功响应。这种模式是最安全的,但是延迟最高。

buffer.memory

该参数用来设置生产者内存缓冲区的大小,生产者用它缓冲要发送到服务器的消息。

如果应用程序发送消息的速度超过发送到服务器的速度,会导致生产者空间不足。这个时候,send()方法调用要么被阻塞,要么抛出异常,取决于如何设置max.block.ms参数。

compression.type

默认情况下,消息发送时不会被压缩。

使用压缩可以降低网络传输开销和存储开销,这也往往是Kafka发送消息的瓶颈所在。

该参数指定了消息被发送给broker之前使用哪一种压缩算法进行压缩,可以设置为:

  snappy -- 占用较少的cpu,提供较好的性能和相当可观的压缩比

  gzip -- 占用较多的cpu,提供更高的压缩比

  lz4

retries

生产者从服务器收到的错误有可能是临时性的错误(比如分区找不到首领)。

retries参数的值决定了生产者可以重发消息的次数,如果达到这个次数,生产者会放弃重试并返回错误。

默认情况下,生产者会在每次重试之间等待100ms,不过可以通过retry.backoff.ms参数来改变这个时间间隔。

一般情况下,因为生产者会自动进行重试,所以就没必要在代码逻辑里处理那些可重试的错误。只需要处理那些不可重试的错误或重试次数超出上限的情况。

batch.size

该参数指定了一个批次可以使用的内存大小,按照字节计算(而不是消息个数)。

当有多个消息需要被发送到同一个分区时,生产者会把它们放到同一个批次里。

当批次被填满,批次里的所有消息会被发送出去。

不过生产者并不一定都会等到批次被填满时才发送(见下一个参数linger.ms)。

所以,就算把批次大小设置的很大,也不会造成延迟,只是会占用更多的内存而已。

但如果设置的太小,因为生产者需要更频繁的发送消息,会增加一些额外的开销。

linger.ms

该参数指定了生产者在发送批次之前等待更多消息加入批次的时间。

KafkaProducer毁在批次填满或linger.ms达到上限时把批次发送出去。

默认情况下, 只要有可用的线程,生产者就会把消息发送出去,就算批次里只有一个消息。

把linger.ms设置成比0大的书,让生产者在发送批次之前等待一会儿,使更多的消息加入到这个批次。虽然这样会增加延迟,但也会提升吞吐量。

https://www.itread01.com/content/1524315728.html

只要滿足linger.ms和batch.size滿了就會激活sender線程來發送消息。

client.id

该参数可以使任意的字符串,服务器会用它来识别消息的来源,还可以用在日志和配额指标里。

max.in.flight.requests.per.connection

该参数指定了生产者在接收到服务器响应之前可以发送多少个消息。

它的值越高,就会占用越多的内存,不过也会提升吞吐量。

把它设为1可以保证消息时按照发送的顺序写入服务器,即使发生了重试。

timeout.ms

该参数制定了broker等待同步副本返回消息确认的时间,也acks的配置相匹配。

如果在指定时间内没有收到同步副本的确认,那么broker就会返回一个错误。

request.timeout.ms

该参数制定了生产者在发送数据时等待服务器返回响应的时间。

如果等待响应超时,那么生产者要么重试发送数据,要么返回一个错误。

medata.fetch.timeout.ms

该参数制定了生产者在获取元数据时等待服务器返回相应的时间。

max.block.ms

该参数制定了在调用send()方法或使用partitionsFor()方法获取元数据时生产者的阻塞时间。

当生产者的发送缓冲区已满,或者没有可用的元数据时,这些方法就会阻塞。在则色时间达到max.block.ms时,生产者会抛出超时异常。

max.request.size

该参数用于控制生产者发送的请求大小。

它可以指定能发送的单个消息的最大值,也可以指单个请求里所有消息总的大小。

另外,broke对可接收的消息最大值也有自己的限制(message.max.bytes),所以,两边的配置最好可以匹配,避免生产者发送的消息被broker拒绝。

receive.buffer.bytes

该参数指定了TCP socker接收数据包的缓冲区大小。

如果被设为-1,就使用操作系统的默认值。

如果生产者或消费者与broker处于不同的数据中心,那么可以适当增大这些值,因为跨数据中心的网络一般都有比较高的延迟和比较低的宽带。

send.buffer.bytes

该参数指定了TCP socker发送数据包的缓冲区大小。

如果被设为-1,就使用操作系统的默认值。

如果生产者或消费者与broker处于不同的数据中心,那么可以适当增大这些值,因为跨数据中心的网络一般都有比较高的延迟和比较低的宽带。

序列化器

创建一个生产者对象必须制定序列化器。

自定义序列化器

如果发送到Kafka的对象不是简单的字符串或整型,那么可以使用序列化框架来创建消息记录,如Avro,Thrift或Protobuf,或者自定义序列化器。

建议使用通用的序列化框架。

自定义序列化器需要实现org.apache.kafka.common.serialization.Serializer接口。

Avro

Apache Avro是一种与编程语言无关的序列化格式。

Avro数据通过与语言无关的schema来定义。

schema通过JSON来描述,数据被序列化成二进制文件或JSON文件,不过一般会使用二进制文件。

Avro在读写文件时需要用到schema,schema一般会被内嵌在数据文件里。

Avro有一个很有意思的特性,当负责写消息的应用程序使用的新的schema,负责读消息的应用程序可以继续处理消息而无需做任何改动,这个特性使得它特别适合用在像Kafka这样的消息系统上。

不过,有以下两个需要注意的地方:

  用于写入数据和读取数据的schema必须是相互兼容的。

  反序列化器需要用到用于写入数据的schema,即使它可能与用于读取数据的schema不一样。Avro数据文件里就包含了用于写入数据的schema,不过在Kafka里一般会将schema文件注册到注册表中。

在Kafka里使用Avro

Avro的数据文件里包含了整个schema,不过这样的开销是可接受的。

但是如果在每条Kafka记录里都嵌入schema,会让记录的大小成倍地增加。

通过schema注册表可以将schema保存在注册表中,然后在记录里引用schema的标识符。

分区

ProducerRecord对象包含了目标主题,键和值。

Kafka的消息是一个个键值对,ProducerRecord对象可以只包含目标主题和值,键可以设置为默认的null,不过大多数应用程序会用到键。

键有两个用途:

  作为消息的附加信息

  决定消息该被写到主题的哪个分区

如果键值为null,并且使用了默认的分区器,那么记录将被随机地发送到主体内各个可用的分区上。

分区器使用轮询算法将消息均匀地分布到各个分区上。

如果键不为空,并且使用了默认的分区器,那么Kafka会对键进行散列,然后根据散列值把消息映射到特定的分区上。

同一个键总是被映射到同一个分区上,所以在进行映射时,我们会使用主题所有的分区,而不仅仅是可用的分区。这也意味着,如果写入数据的分区时不可用的,那么就会发生错误。

只有在不改变主题分区数量的情况下, 键与分区之间的映射才能保持不变。

如果要使用键来映射分区,那么最好在创建主题的时候就把分区规划好,而且永远不要增加新分区。

自定义分区策略

实现org.apache.kafka.clients.producer.Partitioner接口

Kafka--生产者的更多相关文章

  1. 【转】 详解Kafka生产者Producer配置

    粘贴一下这个配置,与我自己的程序做对比,看看能不能完善我的异步带代码:   -----------------------------------------    详解Kafka生产者Produce ...

  2. Kafka生产者-向Kafka中写入数据

    (1)生产者概览 (1)不同的应用场景对消息有不同的需求,即是否允许消息丢失.重复.延迟以及吞吐量的要求.不同场景对Kafka生产者的API使用和配置会有直接的影响. 例子1:信用卡事务处理系统,不允 ...

  3. Python 使用python-kafka类库开发kafka生产者&消费者&客户端

    使用python-kafka类库开发kafka生产者&消费者&客户端   By: 授客 QQ:1033553122       1.测试环境 python 3.4 zookeeper- ...

  4. Kafka集群安装部署、Kafka生产者、Kafka消费者

    Storm上游数据源之Kakfa 目标: 理解Storm消费的数据来源.理解JMS规范.理解Kafka核心组件.掌握Kakfa生产者API.掌握Kafka消费者API.对流式计算的生态环境有深入的了解 ...

  5. [Spark][kafka]kafka 生产者,消费者 互动例子

    [Spark][kafka]kafka 生产者,消费者 互动例子 # pwd/usr/local/kafka_2.11-0.10.0.1/bin 创建topic:# ./kafka-topics.sh ...

  6. Kafka权威指南 读书笔记之(三)Kafka 生产者一一向 Kafka 写入数据

    不管是把 Kafka 作为消息队列.消息总线还是数据存储平台来使用 ,总是需要有一个可以往 Kafka 写入数据的生产者和一个从 Kafka 读取数据的消费者,或者一个兼具两种角色的应用程序. 开发者 ...

  7. kafka生产者

    1.kafka生产者是线程安全的,她允许多个线程共享一个kafka实例 2.kafka管理一个简单的后台线程,所有的IO操作以及与每个broker的tcp连接通信,如果没有正确的关闭生产者可能会造成资 ...

  8. java实现Kafka生产者示例

    使用java实现Kafka的生产者 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 3 ...

  9. kafka生产者和消费者流程

    前言 根据源码分析kafka java客户端的生产者和消费者的流程. 基于zookeeper的旧消费者 kafka消费者从消费数据到关闭经历的流程. 由于3个核心线程 基于zookeeper的连接器监 ...

  10. JAVA封装消息中间件调用一(kafka生产者篇)

    这段时间因为工作关系一直在忙于消息中间件的发开,现在趁着项目收尾阶段分享下对kafka的一些使用心得. kafka的原理我这里就不做介绍了,可参考http://orchome.com/kafka/in ...

随机推荐

  1. 阿里云服务器ubantu创建新用户登录显示问题

    在root用户下输入:vi /etc/passwd,找到添加的用户,在后面加上/bin/bash 重新登录即回复正常

  2. CSS - 去除图片img底侧空白缝隙

    1. 图片底部有空隙 <!DOCTYPE html> <html lang="en"> <head> <meta charset=&quo ...

  3. Press Key关键字用法

    语法:Press Key  locator   按键编码 press key关键字后面的键位对应ascii码实际为16进制格式 NULL = '\ue000'CANCEL = '\ue001'  # ...

  4. 每天一点点之vue框架 watch监听变量(深度监听)

    <div> <p>FullName: {{fullName}}</p> <p>FirstName: <input type="text& ...

  5. Hadoop基准测试(二)

    Hadoop Examples 除了<Hadoop基准测试(一)>提到的测试,Hadoop还自带了一些例子,比如WordCount和TeraSort,这些例子在hadoop-example ...

  6. Python 多进程 multiprocessing.Pool类详解

    Python 多进程 multiprocessing.Pool类详解 https://blog.csdn.net/SeeTheWorld518/article/details/49639651

  7. acid-事务的原子性、一致性、隔离性、持久性

    博客分类: oracle-dba   原子性  多个事情组成一个单元,要么同时成功或失败,不能只运行其中一个 一致性  事务处理要将数据库从一种状态转变为另一种状态. 一旦提交了修改数据,那么其它人读 ...

  8. JuJu团队1月9号工作汇报

    JuJu团队1月9号工作汇报 JuJu   Scrum 团队成员 今日工作 剩余任务 困难 飞飞 将示例程序打包成exe 将crossentrophy和softmax连接起来 无 婷婷 -- 完善ma ...

  9. Deep Image Retrieval: Learning global representations for image search In ECCV, 2016学习笔记

    - 论文地址:https://arxiv.org/abs/1604.01325 contribution is twofold: (i) we leverage a ranking framework ...

  10. sqli-labs level 2

    来到第第二关 首先在后面添加一个 单引号看下报错信息 发现这里多多了一个引号  尝试去掉单引号看下回显结果   :    and 1=2 可以发现这里不需要添加单引号进行闭合,可以直接控制,所以接下来 ...