一、Producer参数说明

1、request.required.acks
Kafka producer的ack有3中机制,初始化producer时的producerconfig可以通过配置request.required.acks不同的值来实现。

0:这意味着生产者producer不等待来自broker同步完成的确认继续发送下一条(批)消息。此选项提供最低的延迟但最弱的耐久性保证(当服务器发生故障时某些数据会丢失,如leader已死,但producer并不知情,发出去的信息broker就收不到)。

1:这意味着producer在leader已成功收到的数据并得到确认后发送下一条message。此选项提供了更好的耐久性为客户等待服务器确认请求成功(被写入死亡leader但尚未复制将失去了唯一的消息)。

-1:这意味着producer在follower副本确认接收到数据后才算一次发送完成。 此选项提供最好的耐久性,我们保证没有信息将丢失,只要至少一个同步副本保持存活。

三种机制,性能依次递减 (producer吞吐量降低),数据健壮性则依次递增

2、producer.type

producer还分为同步和异步模式,由属性producer.type指定,默认是sync,即同步发送模式。

三、压测测试情况:

1、最开始的压测情况(线程池的等待队列长度为:10000,reqRequiredAcks为1,将kafka的producer.type为同步):TPS 14000左右 RT 14ms

kafka生产者 kettle kafka生产者配置详解_数据

2、线程池的等待队列长度为:10000,reqRequiredAcks为1,将kafka的producer.type设置为异步:TPS 30000左右 RT 16ms

kafka生产者 kettle kafka生产者配置详解_HDFS_02

3、线程池的等待队列长度为:10000,将kafka的producer.type设置为异步、reqRequiredAcks设置为0;TPS 30000左右 RT >16ms

kafka生产者 kettle kafka生产者配置详解_HDFS_03

4、将线程池的等待队列长度设置为:20000,将kafka的producer.type设置为异步、reqRequiredAcks设置为0;TPS 30000左右 RT 40ms

kafka生产者 kettle kafka生产者配置详解_HDFS_04

producer 的deliver guarantee 可以通过request.required.acks参数的设置来进行调整:
0 ,相当于异步发送,消息发送完毕即offset增加,继续生产;相当于At most once
1,leader收到leader replica 对一个消息的接受ack才增加offset,然后继续生产;
-1,leader收到所有replica 对一个消息的接受ack才增加offset,然后继续生产
例如设置为0时,当producer向broker发送消息时,producer消息发送完毕即offset增加,遇到的网络问题而造成通信中断,那么数据没有落到broker,同时producer也不会做补偿操作,因此导致生产方的消息丢失。

消费方:

1、(重复消费问题)consumer在从broker读取消息后,可以选择commit,该操作会在Zookeeper中存下该consumer在该partition下读取的消息的offset。该consumer下一次再读该partition时会从下一条开始读取。如未commit,下一次读取的开始位置会跟上一次commit之后的开始位置相同。当然可以将consumer设置为autocommit,即consumer一旦读到数据立即自动commit。如果只讨论这一读取消息的过程,那Kafka是确保了Exactly once。但实际上实际使用中consumer并非读取完数据就结束了,而是要进行进一步处理,而数据处理与commit的顺序在很大程度上决定了消息从broker和consumer的delivery guarantee semantic。
2、(数据丢失问题)读完消息先commit再处理消息。这种模式下,如果consumer在commit后还没来得及处理消息就crash了,下次重新开始工作后就无法读到刚刚已提交而未处理的消息,这就对应于At most once
读完消息先处理再commit。这种模式下,如果处理完了消息在commit之前consumer crash了,下次重新开始工作时还会处理刚刚未commit的消息,实际上该消息已经被处理过了。这就对应于At least once(默认)
3、如果一定要做到Exactly once,就需要协调offset和实际操作的输出。精典的做法是引入两阶段提交。如果能让offset和操作输入存在同一个地方,会更简洁和通用。这种方式可能更好,因为许多输出系统可能不支持两阶段提交。比如,consumer拿到数据后可能把数据放到HDFS,如果把最新的offset和数据本身一起写到HDFS,那就可以保证数据的输出和offset的更新要么都完成,要么都不完成,间接实现Exactly once。(目前就high level API而言,offset是存于Zookeeper中的,无法存于HDFS,而low level API的offset是由自己去维护的,可以将之存于HDFS中)

二、重复消费问题:

即上述 消费方第1种情况—consumer在从broker读取消息后等消费完再commit,如果consumer还没来得及消费或消费时crash,导致offset未提交,该consumer下一次读取的开始位置会跟上一次commit之后的开始位置相同,导致重复消费问题。
关于重复消费的问题,可以通过将每次消费的数据的唯一标识存入Redis中,每次消费前先判断该条消息是否在Redis中,如果有则不再消费,如果没有再消费,消费完再将该条记录的唯一标识存入Redis中,并设置失效时间,防止Redis数据过多、垃圾数据问题。