大数据-Kafka(三)

                                    大数据-Kafka(三)

目录

                                    大数据-Kafka(三)

kafka的文件存储机制

为什么Kafka速度那么快

kafka内核原理

producer消息发送原理

producer核心参数

broker核心参数

consumer消费原理

consumer消费者Rebalance策略

consumer核心参数


kafka的文件存储机制

同一个topic下有多个不同的partition,每个partition为一个目录,partition命名的规则是topic的名称加上一个序号,序号从0开始。

每一个partition目录下的文件被平均切割成大小相等(默认一个文件是1G,可以手动去设置)的数据文件,每一个数据文件都被称为一个段(segment file),但每个段消息数量不一定相等,这种特性能够使得老的segment可以被快速清除。默认保留7天的数据。每次满1G后,在写入到一个新的文件中。

另外每个partition只需要支持顺序读写就可以。如上图所示:
首先00000000000000000000.log是最早产生的文件,该文件达到1G后又产生了新的00000000000002025849.log文件,新的数据会写入到这个新的文件里面。

这个文件到达1G后,数据又会写入到下一个文件中。也就是说它只会往文件的末尾追加数据,这就是顺序写的过程,生产者只会对每一个partition做数据的追加(写操作)。

一个partition中的数据是间隔有序的,不连续的;也就是说消费kafka中的消息不能做到全局有序。

Segment文件

  • Segment file是什么?

生产者生产的消息按照一定的分区策略被发送到topic中partition中,partition在磁盘上就是一个目录,该目录名是topic的名称加上一个序号,在这个partition目录下,有两类文件,一类是以log为后缀的文件,一类是以index为后缀的文件,每一个log文件和一个index文件相对应,这一对文件就是一个segment file,也就是一个段。

其中的log文件就是数据文件,里面存放的就是消息,而index文件是索引文件,索引文件记录了元数据信息。log文件达到1个G后滚动重新生成新的log文件。

  • Segment文件特点

segment文件命名的规则:partition全局的第一个segment从0(20个0)开始,后续的每一个segment文件名是上一个segment文件中最后一条消息的offset值。

那么这样命名有什么好处呢?

假如我们有一个消费者已经消费到了368776(offset值为368776),那么现在我们要继续消费的话,怎么做呢?

看下图,分2个步骤;
第1步

从所有文件log文件的的文件名中找到对应的log文件,第368776条数据位于上图中的“00000000000000368769.log”这个文件中,这一步涉及到一个常用的算法叫做“二分查找法”(假如我现在给你一个offset值让你去找,你首先是将所有的log的文件名进行排序,然后通过二分查找法进行查找,很快就能定位到某一个文件,紧接着拿着这个offset值到其索引文件中找这条数据究竟存在哪里);
第2步

到index文件中去找第368776条数据所在的位置。

  • 索引文件(index文件)中存储这大量的元数据,而数据文件(log文件)中存储这大量的消息。
  • 索引文件(index文件)中的元数据指向对应的数据文件(log文件)中消息的物理偏移地址。

kafka如何快速查询数据

上图的左半部分是索引文件,里面存储的是一对一对的key-value,其中key是消息在数据文件(对应的log文件)中的编号,比如“1,3,6,8……”,分别表示在log文件中的第1条消息、第3条消息、第6条消息、第8条消息……,那么为什么在index文件中这些编号不是连续的呢?

这是因为index文件中并没有为数据文件中的每条消息都建立索引,而是采用了稀疏存储的方式,每隔一定字节的数据建立一条索引。这样避免了索引文件占用过多的空间,从而可以将索引文件保留在内存中。但缺点是没有建立索引的Message也不能一次定位到其在数据文件的位置,从而需要做一次顺序扫描,但是这次顺序扫描的范围就很小了。

其中以索引文件中元数据8,1686为例,其中8代表在右边log数据文件中从上到下第8个消息(在全局partiton表示第368777个消息),其中1686表示该消息的物理偏移地址(位置)为1686。要是读取offset=368777的消息,从00000000000000368769.log文件中的1325的位置进行读取,那么怎么知道何时读完本条消息,否则就读到下一条消息的内容了?

message物理结构

关键字解释说明
8 byte offset在parition(分区)内的每条消息都有一个有序的id号,这个id号被称为偏移(offset),它可以唯一确定每条消息在parition(分区)内的位置。即offset表示partiion的第多少message
4 byte message sizemessage大小
4 byte CRC32用crc32校验message
1 byte “magic"表示本次发布Kafka服务程序协议版本号
1 byte “attributes"表示为独立版本、或标识压缩类型、或编码类型。
4 byte key length表示key的长度,当key为-1时,K byte key字段不填
K byte key可选
value bytes payload表示实际消息数据。

这个就需要涉及到消息的物理结构了,消息都具有固定的物理结构,包括:offset(8 Bytes)、消息体的大小(4 Bytes)、crc32(4 Bytes)、magic(1 Byte)、attributes(1 Byte)、key length(4 Bytes)、key(K Bytes)、payload(N Bytes)等等字段,可以确定一条消息的大小,即读取到哪里截止。

kafka高效文件存储设计特点

  • Kafka把topic中一个parition大文件分成多个小文件段,通过多个小文件段,就容易定期清除或删除已经消费完文件,减少磁盘占用。
  • 通过索引信息可以快速定位message。
  • 通过index元数据全部映射到memory,可以避免segment file的IO磁盘操作。
  • 通过索引文件稀疏存储,可以大幅降低index文件元数据占用空间大小。

为什么Kafka速度那么快

Kafka是大数据领域无处不在的消息中间件,目前广泛使用在企业内部的实时数据管道,并帮助企业构建自己的流计算应用程序。

Kafka虽然是基于磁盘做的数据存储,但却具有高性能、高吞吐、低延时的特点,其吞吐量动辄几万、几十上百万,这其中的原由值得我们一探究竟。

顺序读写

  • 磁盘顺序读写性能要高于内存的随机读写

众所周知Kafka是将消息记录持久化到本地磁盘中的,一般人会认为磁盘读写性能差,可能会对Kafka性能如何保证提出质疑。实际上不管是内存还是磁盘,快或慢关键在于寻址的方式,磁盘分为顺序读写与随机读写,内存也一样分为顺序读写与随机读写。基于磁盘的随机读写确实很慢,但磁盘的顺序读写性能却很高,一般而言要高出磁盘随机读写三个数量级,一些情况下磁盘顺序读写性能甚至要高于内存随机读写。

磁盘的顺序读写是磁盘使用模式中最有规律的,并且操作系统也对这种模式做了大量优化,Kafka就是使用了磁盘顺序读写来提升的性能。Kafka的message是不断追加到本地磁盘文件末尾的,而不是随机的写入,这使得Kafka写入吞吐量得到了显著提升。

  • Page Cache(页缓存)

为了优化读写性能,Kafka利用了操作系统本身的Page Cache,就是利用操作系统自身的内存而不是JVM空间内存。这样做的好处有:

(1)避免Object消耗:如果是使用Java堆,Java对象的内存消耗比较大,通常是所存储数据的两倍甚至更多。
(2)避免GC问题:随着JVM中数据不断增多,垃圾回收将会变得复杂与缓慢,使用系统缓存就不会存在GC问题。

  • 零拷贝(sendfile)

零拷贝并不是不需要拷贝,而是减少不必要的拷贝次数。通常是说在IO读写过程中。

Kafka利用linux操作系统的 "零拷贝(zero-copy)" 机制在消费端做的优化。

首先来了解下数据从文件发送到socket网络连接中的常规传输路径。

比如:读取文件,再用socket发送出去
传统方式实现:
先读取、再发送,实际经过1~4四次copy。
buffer = File.read 
Socket.send(buffer)

  • 第一步:操作系统从磁盘读取数据到内核空间(kernel space)的Page Cache缓冲区
  • 第二步:应用程序读取内核缓冲区的数据copy到用户空间(user space)的缓冲区
  • 第三步:应用程序将用户空间缓冲区的数据copy回内核空间到socket缓冲区
  • 第四步:操作系统将数据从socket缓冲区copy到网卡,由网卡进行网络传输

此时我们会发现用户态“空空如也”。数据没有来到用户态,而是直接在核心态就进行了传输,但这样依然还是有多次复制。首先数据被读取到read buffer中,然后发到socket buffer,最后才发到网卡。虽然减少了用户态和核心态的切换,但依然存在多次数据复制。

如果可以进一步减少数据复制的次数,甚至没有数据复制是不是就会做到最快呢?

DMA

DMA,全称叫Direct Memory Access,一种可让某些硬件子系统去直接访问系统主内存,而不用依赖CPU的计算机系统的功能。听着是不是很厉害,跳过CPU,直接访问主内存。传统的内存访问都需要通过CPU的调度来完成。如下图:

DMA,则可以绕过CPU,硬件自己去直接访问系统主内存。如下图:

回到本文中的文件传输,有了DMA后,就可以实现绝对的零拷贝了,因为网卡是直接去访问系统主内存的。如下图:

 

Kafka采用顺序读写、Page Cache、零拷贝以及分区分段等这些设计,再加上在索引方面做的优化,另外Kafka数据读写也是批量的而不是单条的,使得Kafka具有了高性能、高吞吐、低延时的特点。这样Kafka提供大容量的磁盘存储也变成了一种优点。

Java的NIO提供了FileChannle,它的transferTo、transferFrom方法就是Zero Copy。

kafka内核原理

ISR机制

光是依靠多副本机制能保证Kafka的高可用性,但是能保证数据不丢失吗?

不行,因为如果leader宕机,但是leader的数据还没同步到follower上去,此时即使选举了follower作为新的leader,当时刚才的数据已经丢失了。

ISR是:in-sync replica,就是跟leader partition保持同步的follower partition的数量,只有处于ISR列表中的follower才可以在leader宕机之后被选举为新的leader,因为在这个ISR列表里代表他的数据跟leader是同步的。

如果要保证写入kafka的数据不丢失,首先需要保证ISR中至少有一个follower,其次就是在一条数据写入了leader partition之后,要求必须复制给ISR中所有的follower partition,才能说代表这条数据已提交,绝对不会丢失,这是Kafka给出的承诺。

HW&LEO原理

  • LEO

last end offset,日志末端偏移量,标识当前日志文件中下一条待写入的消息的offset。举一个例子,若LEO=10,那么表示在该副本日志上已经保存了10条消息,位移范围是[0,9]。

  • HW

Highwatermark,俗称高水位,它标识了一个特定的消息偏移量(offset),消费者只能拉取到这个offset之前的消息。任何一个副本对象的HW值一定不大于其LEO值。

小于或等于HW值的所有消息被认为是“已提交的”或“已备份的”。HW它的作用主要是用来判断副本的备份进度。

下图表示一个日志文件,这个日志文件中只有9条消息,第一条消息的offset(LogStartOffset)为0,最有一条消息的offset为8,offset为9的消息使用虚线表示的,代表下一条待写入的消息。日志文件的 HW 为6,表示消费者只能拉取offset在 0 到 5 之间的消息,offset为6的消息对消费者而言是不可见的。

leader持有的HW即为分区的HW,同时leader所在broker还保存了所有follower副本的leo

(1)关系:leader的leo >= follower的leo >= leader保存的follower的leo >= leader的hw >= follower的hw

(2)原理:上面关系反应出各个值的更新逻辑的先后 

LEO的更新机制

注意:follower副本的LEO保存在2个地方。

(1)follower副本所在的broker缓存里。

(2)leader所在broker的缓存里,也就是leader所在broker的缓存上保存了该分区所有副本的LEO。

  • follower更新LEO

(1)follower的leo更新时间

每当follower副本写入一条消息时,leo值会被更新。

(2)leader端的follower副本的leo更新时间

当follower从leader处fetch消息时,leader获取follower的fetch请求中offset参数,更新保存在leader端follower的leo。

  • leader更新LEO

(1)leader本身的leo的更新时间:leader向log写消息时。

更新HW的机制

  • follower更新HW

follower更新HW发生在其更新完LEO后,即follower向log写完数据,它就会尝试更新HW值。具体算法就是比较当前LEO(已更新)与fetch响应中leader的HW值,取两者的小者作为新的HW值。

  • leader更新HW

leader更新HW的时机

(1)producer 向 leader 写消息时
(2)leader 处理 follower 的 fetch 请求时
(3)某副本成为leader时
(4)broker 崩溃导致副本被踢出ISR时

leader更新HW的方式

当尝试确定分区HW时,它会选出所有满足条件的副本,比较它们的LEO(当然也包括leader自己的LEO),并选择最小的LEO值作为HW值。

这里的满足条件主要是指副本要满足以下两个条件之一:

(1)处于ISR中

(2)副本LEO落后于leader LEO的时长不大于replica.lag.time.max.ms参数值(默认值是10秒),或者落后Leader的条数超过预定值replica.lag.max.messages(默认值是4000)。

producer消息发送原理

  • ProducerInterceptors是一个拦截器,对发送的数据进行拦截。
  •  Serializer 对消息的key和value进行序列化。
  • 通过使用分区器作用在每一条消息上,实现数据分发进行入到topic不同的分区中 。
  • RecordAccumulator收集消息,实现批量发送。
  • Sender线程从RecordAccumulator获取消息。
  • 构建ClientRequest对象。
  • 将ClientRequest交给 NetWorkClient准备发送。
  • NetWorkClient 将请求放入到KafkaChannel的缓存。
  • 发送请求到kafka集群。
  • 调用回调函数,接受到响应。

producer核心参数

回顾之前的producer生产者代码

package com.kaikeba.producer;

import org.apache.kafka.clients.producer.*;

import java.util.Properties;
import java.util.concurrent.ExecutionException;

/**
 * 需求:开发kafka生产者代码
 */
public class KafkaProducerStudyDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //准备配置属性
        Properties props = new Properties();
        //kafka集群地址
        props.put("bootstrap.servers", "node01:9092,node02:9092,node03:9092");
        //acks它代表消息确认机制   // 1 0 -1 all
        props.put("acks", "all");
        //重试的次数
        props.put("retries", 0);
        //批处理数据的大小,每次写入多少数据到topic
        props.put("batch.size", 16384);
        //可以延长多久发送数据
        props.put("linger.ms", 1);
        //缓冲区的大小
        props.put("buffer.memory", 33554432);
        props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
        props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");

        //添加自定义分区函数
        props.put("partitioner.class","com.kaikeba.partitioner.MyPartitioner");

        Producer<String, String> producer = new KafkaProducer<String, String>(props);
        for (int i = 0; i < 100; i++) {

            // 这是异步发送的模式
            producer.send(new ProducerRecord<String, String>("test", Integer.toString(i), "hello-kafka-"+i), new Callback() {
                public void onCompletion(RecordMetadata metadata, Exception exception) {
                    if(exception == null) {
                        // 消息发送成功
                        System.out.println("消息发送成功");
                    } else {
                        // 消息发送失败,需要重新发送
                    }
                }

            });

            // 这是同步发送的模式
            //producer.send(record).get();
            // 你要一直等待人家后续一系列的步骤都做完,发送消息之后
            // 有了消息的回应返回给你,你这个方法才会退出来
        }
        producer.close();
    }

}

常见异常处理

  • 不管是异步还是同步,都可能让你处理异常,常见的异常如下:

1)LeaderNotAvailableException:这个就是如果某台机器挂了,此时leader副本不可用,会导致你写入失败,要等待其他follower副本切换为leader副本之后,才能继续写入,此时可以重试发送即可。如果说你平时重启kafka的broker进程,肯定会导致leader切换,一定会导致你写入报错,是LeaderNotAvailableException

2)NotControllerException:这个也是同理,如果说Controller所在Broker挂了,那么此时会有问题,需要等待Controller重新选举,此时也是一样就是重试即可

3)NetworkException:网络异常,重试即可
我们之前配置了一个参数,retries,他会自动重试的,但是如果重试几次之后还是不行,就会提供Exception给我们来处理了。

  • retries

重新发送数据的次数,默认为0,表示不重试。

  • retry.backoff.ms

两次重试之间的时间间隔,默认为100ms。

提升消息吞吐量

  • buffer.memory

设置发送消息的缓冲区,默认值是33554432,就是32MB。

如果发送消息出去的速度小于写入消息进去的速度,就会导致缓冲区写满,此时生产消息就会阻塞住,所以说这里就应该多做一些压测,尽可能保证说这块缓冲区不会被写满导致生产行为被阻塞住。

  • compression.type

producer用于压缩数据的压缩类型。默认是none表示无压缩。可以指定gzip、snappy。

压缩最好用于批量处理,批量处理消息越多,压缩性能越好。

  • batch.size

producer将试图批处理消息记录,以减少请求次数。这将改善client与server之间的性能。

默认是16384Bytes,即16kB,也就是一个batch满了16kB就发送出去。

如果batch太小,会导致频繁网络请求,吞吐量下降;如果batch太大,会导致一条消息需要等待很久才能被发送出去,而且会让内存缓冲区有很大压力,过多数据缓冲在内存里。

  • linger.ms

这个值默认是0,就是消息必须立即被发送。

一般设置一个100毫秒之类的,这样的话就是说,这个消息被发送出去后进入一个batch,如果100毫秒内,这个batch满了16kB,自然就会发送出去。但是如果100毫秒内,batch没满,那么也必须把消息发送出去了,不能让消息的发送延迟时间太长,也避免给内存造成过大的一个压力。

请求超时

  • max.request.size

这个参数用来控制发送出去的消息的大小,默认是1048576字节,也就1mb

这个一般太小了,很多消息可能都会超过1mb的大小,所以需要自己优化调整,把他设置更大一些(企业一般设置成10M)。

  • request.timeout.ms

这个就是说发送一个请求出去之后,他有一个超时的时间限制,默认是30秒。

如果30秒都收不到响应,那么就会认为异常,会抛出一个TimeoutException来让我们进行处理。

ACK参数

acks参数,其实是控制发送出去的消息的持久化机制的。

  • acks=0

生产者只管发数据,不管消息是否写入成功到broker中,数据丢失的风险最高。

producer根本不管写入broker的消息到底成功没有,发送一条消息出去,立马就可以发送下一条消息,这是吞吐量最高的方式,但是可能消息都丢失了。你也不知道的,但是说实话,你如果真是那种实时数据流分析的业务和场景,就是仅仅分析一些数据报表,丢几条数据影响不大的。会让你的发送吞吐量会提升很多,你发送弄一个batch出去,不需要等待人家leader写成功,直接就可以发送下一个batch了,吞吐量很大的,哪怕是偶尔丢一点点数据,实时报表,折线图,饼图。

  • acks=1

只要leader写入成功,就认为消息成功了。

默认给这个其实就比较合适的,还是可能会导致数据丢失的,如果刚写入leader,leader就挂了,此时数据必然丢了,其他的follower没收到数据副本,变成leader。

  • acks=all 或者 acks=-1

这个leader写入成功以后,必须等待其他ISR中的副本都写入成功,才可以返回响应说这条消息写入成功了,此时你会收到一个回调通知.。这种方式数据最安全,但是性能最差。

  • 如果要想保证数据不丢失,得如下设置

(1)min.insync.replicas = 2
    ISR里必须有2个副本,一个leader和一个follower,最最起码的一个,不能只有一个leader存活,连一个follower都没有了。

(2)acks = -1
    每次写成功一定是leader和follower都成功才可以算做成功,这样leader挂了,follower上是一定有这条数据,不会丢失。
    
(3)retries = Integer.MAX_VALUE
    无限重试,如果上述两个条件不满足,写入一直失败,就会无限次重试,保证说数据必须成功的发送给两个副本,如果做不到,就不停的重试。
    除非是面向金融级的场景,面向企业大客户,或者是广告计费,跟钱的计算相关的场景下,才会通过严格配置保证数据绝对不丢失。

重试乱序

  • max.in.flight.requests.per.connection

每个网络连接已经发送但还没有收到服务端响应的请求个数最大值。

消息重试是可能导致消息的乱序的,因为可能排在你后面的消息都发送出去了,你现在收到回调失败了才在重试,此时消息就会乱序,所以可以使用“max.in.flight.requests.per.connection”参数设置为1,这样可以保证producer必须把一个请求发送的数据发送成功了再发送后面的请求。避免数据出现乱序。

broker核心参数

server.properties配置文件核心参数

  • broker.id

每个broker都必须自己设置的一个唯一id

  • log.dirs

这个极为重要,kafka的所有数据就是写入这个目录下的磁盘文件中的,如果说机器上有多块物理硬盘,那么可以把多个目录挂载到不同的物理硬盘上,然后这里可以设置多个目录,这样kafka可以数据分散到多块物理硬盘,多个硬盘的磁头可以并行写,这样可以提升吞吐量。

  • zookeeper.connect

连接kafka底层的zookeeper集群的

  • Listeners

broker监听客户端发起请求的端口号,默认是9092。

  • unclean.leader.election.enable

默认是false,意思就是只能选举ISR列表里的follower成为新的leader,1.0版本后才设为false,之前都是true,允许非ISR列表的follower选举为新的leader

  • delete.topic.enable

默认true,允许删除topic

  • log.retention.hours

可以设置一下,要保留数据多少个小时(默认168小时),这个就是底层的磁盘文件,默认保留7天的数据,根据自己的需求来就行了。

consumer消费原理

Offset管理

每个consumer内存里数据结构保存对每个topic的每个分区的消费offset,定期会提交offset,老版本是写入zk,但是那样高并发请求zk是不合理的架构设计,zk是做分布式系统的协调的,轻量级的元数据存储,不能负责高并发读写,作为数据存储。所以后来就是提交offset发送给内部topic:consumer_offsets,提交过去的时候,key是group.id+topic+分区号,value就是当前offset的值,每隔一段时间,kafka内部会对这个topic进行compact。也就是每个group.id+topic+分区号就保留最新的那条数据即可。而且因为这个 consumer_offsets可能会接收高并发的请求,所以默认分区50个,这样如果你的kafka部署了一个大的集群,比如有50台机器,就可以用50台机器来抗offset提交的请求压力,就好很多。

Coordinator

  • Coordinator的作用

每个consumer group都会选择一个broker作为自己的coordinator,他是负责监控这个消费组里的各个消费者的心跳,以及判断是否宕机,然后开启rebalance。

根据内部的一个选择机制,会挑选一个对应的Broker,Kafka总会把你的各个消费组均匀分配给各个Broker作为coordinator来进行管理的。

consumer group中的每个consumer刚刚启动就会跟选举出来的这个consumer group对应的coordinator所在的broker进行通信,然后由coordinator分配分区给你的这个consumer来进行消费。coordinator会尽可能均匀的分配分区给各个consumer来消费。

  • 如何选择哪台是coordinator

首先对消费组的groupId进行hash,接着对consumer_offsets的分区数量取模,默认是50,可以通过offsets.topic.num.partitions来设置,找到你的这个consumer group的offset要提交到consumer_offsets的哪个分区。

比如说:groupId,"membership-consumer-group" -> hash值(数字)-> 对50取模 -> 就知道这个consumer group下的所有的消费者提交offset的时候是往哪个分区去提交offset,找到consumer_offsets的一个分区,consumer_offset的分区的副本数量默认来说1,只有一个leader,然后对这个分区找到对应的leader所在的broker,这个broker就是这个consumer group的coordinator了,consumer接着就会维护一个Socket连接跟这个Broker进行通信。

consumer消费者Rebalance策略

比如我们消费的一个topic主题有12个分区:p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11
假设我们的消费者组里面有三个消费者。

range范围策略

  • RangeAssignor(默认策略)

range策略就是按照partiton的序号范围
    p0~3             consumer1
    p4~7             consumer2
    p8~11            consumer3
默认就是这个策略。

round-robin轮训策略

  • RoundRobinAssignor

consumer1:    0,3,6,9
consumer2:    1,4,7,10
consumer3:    2,5,8,11

但是前面的这两个方案有个问题:
    假设consuemr1挂了:p0-5分配给consumer2,p6-11分配给consumer3
    这样的话,原本在consumer2上的的p6,p7分区就被分配到了 consumer3上。

sticky黏性策略

  • StickyAssignor

最新的一个sticky策略,就是说尽可能保证在rebalance的时候,让原本属于这个consumer的分区还是属于他们,然后把多余的分区再均匀分配过去,这样尽可能维持原来的分区分配的策略。

consumer1: 0-3
consumer2:  4-7
consumer3:  8-11 

假设consumer3挂了
consumer1:0-3,+8,9
consumer2: 4-7,+10,11

消费者分配策略

  • 由参数partition.assignment.strategy控制,默认是RangeAssignor表示范围策略。
//设置消费者分配策略:
properties.put(ConsumerConfig.PARTITION_ASSIGNMENT_STRATEGY_CONFIG, 
StickyAssignor.class.getName());

consumer核心参数

  • heartbeat.interval.ms

默认值:3000

consumer心跳时间,必须得保持心跳才能知道consumer是否故障了,然后如果故障之后,就会通过心跳下发rebalance的指令给其他的consumer通知他们进行rebalance的操作。

  • session.timeout.ms

默认值:10000    

kafka多长时间感知不到一个consumer就认为他故障了,默认是10秒

  • max.poll.interval.ms

默认值:300000

如果在两次poll操作之间,超过了这个时间,那么就会认为这个consume处理能力太弱了,会被踢出消费组,分区分配给别人去消费,一遍来说结合你自己的业务处理的性能来设置就可以了

  • fetch.max.bytes

默认值:1048576

获取一条消息最大的字节数,一般建议设置大一些。

  • max.poll.records

默认值:500条

一次poll返回消息的最大条数

  • connections.max.idle.ms

默认值:540000

consumer跟broker的socket连接如果空闲超过了一定的时间,此时就会自动回收连接,但是下次消费就要重新建立socket连接,这个建议设置为-1,不要去回收

  • auto.offset.reset

earliest

当各分区下有已提交的offset时,从提交的offset开始消费;无提交的offset时,从头开始消费          

latest

当各分区下有已提交的offset时,从提交的offset开始消费;无提交的offset时,从当前位置开始消费

none

topic各分区都存在已提交的offset时,从offset后开始消费;只要有一个分区不存在已提交的offset,则抛出异常
        
注:我们生产里面一般设置的是latest

  • enable.auto.commit

默认值:true

设置为自动提交offset

  • auto.commit.interval.ms

默认值:60 * 1000

每隔多久更新一下偏移量


如果消费者这端要保证数据被处理且只被处理一次:
屏蔽掉了下面这2种情况:
    (1)数据的重复处理
    (2)数据的丢失
    
一般来说:需要手动提交偏移量,需要保证数据处理成功与保存偏移量的操作在同一事务中就可以了。

此博文仅供学习参考,如有错误欢迎指正。

上一篇《大数据-Kafka(四)

下一篇《大数据-Kafka(六)

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值