Kafka相关知识点

目录

简介

Kafka术语介绍

broker

topic

partition

partition中的leader

partition中的follower

生产者producer

消费者comsumer

消费者组comsumer group

kafka生产流程

kafka基本架构及数据基本流向图

Topic详解

Partition说明

关于数据保存的策略

Consumer消费消息说明

kafka消息发送

数据传输的事务定义通常有以下三种级别:

消息发送的方式(保证消息的可靠性可以从这里入手)

高可用性配置

Kafka消息消费

kafka高可用设计解析

为何需要给partition设置副本

为什么Partition副本需要leader

如何将partition均匀的分布到kafka的集群中

kafka节点控制器选举

kafka分区leader选举

消费者组中的选举

Kafka事务看这里

使用时Kafka常用的配置

Topic和Partition

Producer

Consumer

关于kafka的各种问题


简介

Kafka是一个分布式、分区的、多副本的、多订阅者,基于zookeeper协调的分布式日志系统(也可以当做消息队列系统),常见可以用于web/nginx日志、访问日志,消息服务等等。

根据官网的介绍,ApacheKafka®是一个分布式流媒体平台,它主要有3种功能:

  1:发布和订阅消息流。这个功能类似于消息队列,这也是kafka归类为消息队列框架的原因

  2:以容错的方式保存消息流。kafka以文件的方式来存储消息流

  3:在消息发布的时候可以进行处理。

主要应用的场景有两个:

      1:构建可在系统或应用程序之间可靠获取数据的实时流数据管道。     消息队列系统

      2:构建转换或响应数据流的实时流应用程序。   日志收集系统

Kafka术语介绍

broker

Kafka 集群包含一个或多个kafka服务器,每个kafka服务器节点称为broker。在配置文件中broker.id可以配置每一个节点的唯一id。

broker存储topic的数据。如果某topic有N个partition,集群有N个broker,那么每个broker存储应该该topic的一个partition。

如果某topic有N个partition,集群有(N+M)个broker,那么其中有N个broker存储该topic的一个partition,剩下的M个broker不存储该topic的partition数据。

如果某topic有N个partition,集群中broker数目少于N个,那么一个broker存储该topic的一个或多个partition。在实际生产环境中,尽量避免这种情况的发生,这种情况容易导致Kafka集群数据不均衡。

topic

每条发布到Kafka集群的消息都有一个类别,这个类别被称为Topic。物理上不同Topic的消息分开存储,对于相同的topic,也可以根据需要分为多个partition存储,而一个partition物理上对应一个文件夹,而partition也会根据需要存储在不同的broker上,因此一个Topic的消息可能会保存于一个或多个broker的多个partition上,在消费消息的时候只需要指定对应的topic

partition

topic中的数据可以分为一个或多个partition存储。每个 Topic 可以划分多个分区(每个 Topic 至少有一个分区),同一 Topic 下的不同分区包含的消息是不同的每个消息在被添加到分区时,都会被分配一个 offset,它是消息在此分区中的唯一编号,Kafka 通过 offset 保证消息在分区内的顺序,offset 的顺序不跨分区,即 Kafka 只保证在同一个分区内的消息是有序的
每个partition在物理存储层面对应的是不同的文件夹,而这些文件夹中存放着多个log file(称为segment)。每个partition还可以根据配置生成多个副本,当然副本的数量自然也应该不大于kafka集群中broker的数量。当然kafka会为topic的每个partition在副本中选出一个leader,之后所有该partition的请求,实际操作的都是leader,然后再同步到其他的follower。当一个broker歇菜后,所有leader在该broker上的partition都会重新选举,选出一个leader。(这里不像分布式文件存储系统那样会自动进行复制保持副本数)

partition中的leader

每个partition可以配置有多个副本,其中有且仅有一个作为leader,leader是当前负责数据的读写的partition。

partition中的follower

对于partition的副本集,除去一个leader剩下的都是follower,follower主动从leader拉取数据保持数据同步。follower与leader保持数据同步。如果leader失效,则从follower中选举出一个新的leader。当follower与leader挂掉、卡住或者同步太慢,leader会把这个follower从“in sync replicas”(ISR)列表中删除,重新创建一个follower。
AR:简单来说,分区中的所有副本,即leader和follower统称为 AR。
ISR:所有与leader副本保持一定程度同步的副本(包括leader副本在内)组成ISR.
OSR:当follower副本落后太多或失效时,leader副本会把它从 ISR 集合中剔除

生产者producer

生产者即数据的发布者,生产者发送消息时需要指定topic和partition。该角色将消息发布到Kafka的topic中。broker接收到生产者发送的消息后,broker将该消息追加到当前用于追加数据的segment文件中。生产者发送的消息,存储到一个partition中,生产者也可以指定数据存储的partition。

消费者comsumer

消费者可以从broker中拉取数据。一个消费者可以消费多个topic中的数据,消费者消费消息只需要指定topic而不用指定partition,因此当一个消费者消费一个partition里的多个消息时,会造成消息乱序的,因此在我们生产消息的时候可以给不同partition的消息设置不同的key,相同类型的key属于同一个partition,在消费消息时先将消息按照key分别存入不同的queue,然后在消费queue里的消息,这样就可以保证消费消息是有序的。

消费者组comsumer group

每个Consumer属于一个特定的Consumer Group(可为每个Consumer指定group name,若不指定group name则属于默认的group)。

kafka生产流程

kafka基本架构及数据基本流向图

数据流向

上图中有两个生产者producer用于产生消息,产生的消息在存入kafka集群后,由集群分别发布给订阅的3个消费者组,每个消费者组中分别有1个或多个消费者,在kafka集群中有3个broker节点,每个节点中有topic_01和topic_02两种主题的消息,topic_01主题中又分为了两个partition,每个partition都共有3个副本集,topic_02主题有一个partition,该partition都也有3个副本集,其中一个是leader,其余两个是follower用于保证了良好的容灾。

Kafka消息队列由3个部分组成:

  1. 消息生产方Producer
  2. Kafka集群,集群由多台server组成,这些server被称为Kafka中的Broker,也就是消息代理
  3. 消息的消费方Consumer

Kafka的消息按照topic进行划分,一个topic就是一个queue(消息队列),实际应用中,不同的业务数据可以设置为不同的topic,一个topic可以有多个消费方,当生产方在某个topic发出一条消息后,所有订阅了这个topic的消费方都可以收到这条消息,为了提高并行能力,Kafka为每个topic维护了多个partition分区,每个分区可以看做一份追加类型的日志,每个分区中的消息保证ID唯一且有序,新消息不断追加在尾部,partition实际存储数据时,会按照大小进行分段,来保证总是对较小的文件进行写操作,提高性能方便管理。

partition分布于多个broker上,从上图可以看出topic被可以被分为了一个或多个partition。每个partition都会被复制成多份,存在于不同的broker上。这样可以保证主分区出现问题时进行容灾处理。每个broker可保存多个topic的多个partition,Kafka只保证一个分区内的消息有序,不能保证一个topic中不同的分区之间消息有序。为了保证较高的效率,所有消息的读写都是在主partition上完成的,其他的副本partition只会从主分区复制数据Kafka会为每个partition维护一个称为ISR,也就是已同步副本集的列表,如果某个主分区leader不可用了,Kafka就会从ISR集合中选择一个副本作为新的分区。

Kafka对消费方进行分组管理,来支持消息的一写多读。消费者可以从broker中读取数据。消费者可以消费多个topic中的数据。每个Consumer属于一个特定的Consumer Group(可为每个Consumer指定group name,若不指定group name则属于默认的group)。

Topic详解

kafka中主题是发布记录的类别或订阅源名称。可以简单的将同一个topic的消息理解为同一类消息。每个topic被分为指定数量的partition(区)提高kafka的吞吐量。每个partition实际上在磁盘上对应一个文件夹,这个文件夹中存放着该partition的所有消息和索引文件。kafka在接收到生产者发送的消息之后,会根据均衡策略将消息存储到不同的分区中。

每个partition在存储层面是append log文件。任何发布到此partition的消息都会被直接追加到log文件的尾部,每条消息在文件中的位置称为offset(偏移量),offset为一个long型数字,它是唯一标记一条消息。

每个消费者保留的唯一元数据是该消费者在日志中的偏移或位置。这种偏移由消费者控制:通常消费者在读取记录时会线性地提高其偏移量,但事实上,由于消费者控制位置,它可以按照自己喜欢的任何顺序消费记录。例如,消费者可以重置为较旧的偏移量以重新处理过去的数据,或者跳到最近的记录并从“现在”开始消费。

Kafka默认将offset保存在kafka(0.9之前是保存在zookeeper中)。具体的方法就是把offset提交,跟随具体消息一期保存在log文件中。可以从下图看出,具体log文件中存储的数据是什么样的。

Partition说明

kafka中的partition分布在集群服务器上,每个partition根据配置生成响应数量的副本(副本数量需要小于broker的数量),用于实现容错。

topic具体partition都有对应的leader和follower,leader处理数据的读写,follower被动的同步数据,当leader挂掉后,其中的一个follower会成为新的leader。在kafka的集群中,partition的leader和follower会均衡的分布到不同的broker中,这样保证了集群的负载平衡。

关于数据保存的策略

  • log.retention.hours:kafka提供基于时间的策略删除消息数据,例如,log.retention.hous=48,则在发布记录后的两天内,它可供使用,之后将被丢弃以释放空间。
  • log.retention.bytes:kafka提供基于partition的大小删除旧消息数据的策略,例如,log.retention.bytes=1073741824,表示partition文件超过1GB时删除旧数据。

注意:如果配置了log.retention.hours和log.rentention.bytes两个参数,那么两个参数任意一个达到要求都会删除旧数据。每个partition是通过是以一堆segment文件存储的。log.segment.bytes可以控制每个segment文件的大小。

Consumer消费消息说明

消费者订阅topic是以消费者组订阅的,同一个消费者组里可能有多个消费者,但是同一个消费者组里的不同消费者不能同时消费一个partition的消息,也就是说,一个partition里的消息,只能被消费者组里的一个消费者获取,可以被多个消费者组订阅。

消费者

当一个消费者组中新增了一个消费者实例时,该实例将从组中其他消费者接管一些分区,当一个消费者组中一个实例死亡时,该实例接管的分区会重新分配给该消费者组中的其他实例。

Reblance机制介绍:

Reblance本质上是一种协议,规定了一个Consumer Group下的所有的Consumer如何达成一致来分配订阅Topic的每个Partition。比如某个group下有2个consumer,它订阅了一个具有10个分区的topic。正常情况下,Kafka平均会为每个consumer分配5个分区。

进行reblance的情况:

  • 有新的consumer加入
  • 旧的consumer挂了
  • coordinator挂了,集群选举出新的coordinator
  • topic的partition新加
  • consumer调用unsubscrible(),取消topic的订阅

kafka消息发送

数据传输的事务定义通常有以下三种级别:

  • At most once:最多一次,消息可能会丢失,但不会重复
  • At least once:最少一次,消息不会丢失,可能会重复
  • Exactly once:只且一次,消息不丢失不重复,只且消费一次(0.11中实现,仅限于下游也是kafka)

at most once: 消费者fetch消息,然后保存offset,然后处理消息;当client保存offset之后,但是在消息处理过程中出现了异常,导致部分消息未能继续处理.那么此后"未处理"的消息将不能被fetch到,这就是"at most once".

at least once: 消费者fetch消息,然后处理消息,然后保存offset.如果消息处理成功之后,但是在保存offset阶段发生异常导致保存操作未能执行成功,这就导致接下来再次fetch时可能获得上次已经处理过的消息,这就是"at least once"。这篇博文介绍了常见的重复消费的情况。其实在保存offset阶段,如果发生rebalance,导致已经消费消息但是offset保存失败,就会导致重复消费的情况。下面是解决消息重复的几种方案:
(1)唯一 ID 保存在外部介质中,每次消费时根据它判断是否已处理;
(2)如果在统计用,丢失几条关系不大,则无需理会;
(3)如果消费者来不及处理,可以这样优化:增加分区以提高并行能力;增加消费者线程;关闭自动提交 enable.auto.commit=false

exactly once: kafka中并没有严格的去实现(基于2阶段提交,事务),我们认为这种策略在kafka中是没有必要的.

通常情况下"at-least-once"是我们首选.(相比at most once而言,重复接收数据总比丢失数据要好).

消息发送的方式(保证消息的可靠性可以从这里入手)

Kafka Producer 消息发送有三种方式:直接发送不管结果、同步、异步

在Java中调用KafkaProducer类的send方法可以实现这三种方式:

KafkaProducer kafkaProducer = new KafkaProducer(producer_properties);
ProducerRecord producerRecord = new ProducerRecord("topic01", 1, "key", "value");
//直接发送,不管结果
kafkaProducer.send(producerRecord);
//同步发送,阻塞等待发送结果
kafkaProducer.send(producerRecord).get();
//异步发送,发送完成后执行回调函数
kafkaProducer.send(producerRecord, new Callback() {
    @Override
    public void onCompletion(RecordMetadata recordMetadata, Exception e) {
        if (e != null) {
            //在这里可以做消息发送失败的处理,比如重发或者把该条消息记录到失败记录中
            logger.error(e.getMessage(), e);
        } else {
            System.out.println("Coming in MyProducerCallback");
        }
    }
});

可以看出异步发送即可保证吞吐率也可处理失败的消息。

Kafka Producer 消息发送有三种确认方式(配置参数 acks)生产者配置中"acks"指定了必须有多少个分区副本接收到了消息,生产者才会认为消息是发送成功的

通过配置acks不同的值来设置生产者ACK具体采用哪一种机制。生产者ACK共有下面三种机制:

acks=0:消息发送完毕即offset增加,生产者继续发送可以继续发送消息。这意味着生产者producer不等待来自broker同步完成的确认继续发送下一条(批)消息。此选项提供最低的延迟但最弱的耐久性保证(当服务器发生故障时某些数据会丢失,如leader已死,但producer并不知情,发出去的信息broker就收不到)。acks=0这种方式低延迟高吞吐,适用于对可靠性要求不高的场景。对应At most once。

acks=1:集群的leader收到了消息,生产者将会受到发送成功的一个响应,然后才可以发送下一条消息。如果消息无撞到达leader节点(比如leader节点崩愤,新的首领还没有被选举出来),生产者会收到一个错误响应,为了避免数据丢失,生产者会重发消息。不过,如果Leader刚刚接收到消息,Follower还没来得及同步过去,结果Leader所在的broker宕机了,此时也会导致这条消息丢失。acks=1这种方式能带来较高吞吐并且也提高了可靠性,是一种均衡方案。

acks=-1(all):所有参与复制的节点全部收到消息的时候,生产者才会收到来自服务器的一个响应,这种模式最安全可靠,但是吞吐量受限制,它可以保证不止一个服务器收到消息,就算某台服务器奔溃,那么整个集群还是会正产运转。对应At least once。

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

在acks的基础上吞吐量还取决于使用的是同步发送还是异步发送。当消息发送成功或失败后,同步发送是通过调用Future 对象的get()方法,让发送客户端等待服务器的响应,这样的做法显然会增加延迟问题(阻塞)(在网络上传输一个来回的延迟)。异步发送是客户端使用回调函数,延迟(阻塞)问题就可以得到缓解,不过吞吐量还是会受发送中消息数量的限制(比如,生产者在收到服务器响应之前可以发送多少个消息)。对应At least once。

高可用性配置

要保证数据写入到Kafka是安全的,高可用的,需要如下的配置:

  • topic的配置:offsets.topic.replication.factor>=3,即topic中每个partition的的副本数至少是3个;
  • broker的配置:leader的选举条件unclean.leader.election.enable=true(默认为false),此参数标识当ISR中没有副本时,是否可以选举OSR( Out-of-sync Replicas)中的副本(不推荐,会造成数据丢失)。
  • producer的配置:acks=-1,并且生产者发送消息必须同步发送,即需要调用send()方法返回的Future对象的get()方法

Kafka消息消费

Consumer按照group来消费消息,topic中每一条消息可以被多个Consumer group消费,Kafka确保每个partition在一个group中只能有一个consumer消费,Kafka通过GroupCoordinator来管理Consumer实例负责消哪个partition,默认支持Range和轮询分配。Kafka保存了每个topic的每个partition在不同group的消费偏移量offset,通过更新偏移量保证每条消息都被消费。注意:在同一个group中,用多线程消费数据时,一个线程就相当于一个consumer实例,当consumer的数量大于分区partition数量时,会出现部分consumer线程读取不到数据。

kafka高可用设计解析

为何需要给partition设置副本

  在Kafka在0.8以前的版本中,是没有Replication的,一旦某一个Broker宕机,则其上所有的Partition数据都不可被消费,这与Kafka数据持久性及Delivery Guarantee的设计目标相悖。同时Producer都不能再将数据存于这些Partition中。

        在没有Replication的情况下,一旦某机器宕机或者某个Broker停止工作则会造成整个系统的可用性降低。随着集群规模的增加,整个集群中出现该类异常的几率大大增加,因此对于生产系统而言Replication机制的引入非常重要。

为什么Partition副本需要leader

  引入Replication之后,同一个Partition可能会有多个Replica,而这时需要在这些Replication之间选出一个Leader,Producer和Consumer只与这个Leader交互,其它Replica作为Follower从Leader中复制数据。

  因为需要保证同一个Partition的多个Replica之间的数据一致性(其中一个宕机后其它Replica必须要能继续服务并且即不能造成数据重复也不能造成数据丢失)。如果没有一个Leader,所有Replica都可同时读/写数据,那就需要保证多个Replica之间互相(N×N条通路)同步数据,数据的一致性和有序性非常难保证,大大增加了Replication实现的复杂性,同时也增加了出现异常的几率。而引入Leader后,只有Leader负责数据读写,Follower只从Leader顺序Fetch数据(N条通路),系统更加简单且高效。

如何将partition均匀的分布到kafka的集群中

为了更好的做负载均衡,Kafka尽量将所有的Partition均匀分配到整个集群上。一个典型的部署方式是一个Topic的Partition数量大于Broker的数量。同时为了提高Kafka的容错能力,也需要将同一个Partition的Replica尽量分散到不同的机器。实际上,如果所有的Replica都在同一个Broker上,那一旦该Broker宕机,该Partition的所有Replica都无法工作,也就达不到HA的效果。同时,如果某个Broker宕机了,需要保证它上面的负载可以被均匀的分配到其它幸存的所有Broker上。

Kafka分配Replica的算法如下:

1.将所有Broker(假设共n个Broker)和待分配的Partition排序

2.将第i个Partition分配到第(i mod n)个Broker上

3.将第i个Partition的第j个Replica分配到第((i + j) mode n)个Broker上

kafka节点控制器选举

  1. 先获取 zk 的 /cotroller 节点的信息,获取 controller 的 broker id,如果该节点不存在(比如集群刚创建时),那么获取的 controller id 为-1;
  2. 如果 controller id 不为-1,即 controller 已经存在,直接结束流程;
  3. 如果 controller id 为-1,证明 controller 还不存在,这时候当前 broker 开始在 zk 注册 controller;
  4. 如果注册成功,那么当前 broker 就成为了 controller,这时候开始调用 onBecomingLeader() 方法,正式初始化 controller(注意: controller 节点是临时节点 ,如果当前 controller 与 zk 的 session 断开,那么 controller 的临时节点会消失,会触发 controller 的重新选举);
  5. 如果注册失败(刚好 controller 被其他 broker 创建了、抛出异常等),那么直接返回。

在这里 controller 算是成功被选举出来了,controller 选举过程实际上就是各个 broker 抢占式注册该节点,注册成功的便为 Controller。

kafka分区leader选举

Kafka通过leaderSelector完成leader的选举。

可能触发为partition选举leader的场景有: 新创建topic,broker启动,broker停止,controller选举,客户端触发,reblance等等 场景。在不同的场景下选举方法不尽相同。Kafka提供了几种leader选举方式,说明:

OfflinePartitionLeaderElectionStrategy

触发场景:
    * 当创建分区(创建主题或增加分区都有创建分区的动作)或分区上线(比如分区中原先的leader副本下线,此时分区需要选举一个新的leader上线来对外提供服务)的时候都需要执行leader的选举动作。
选举有两种情况:
    1.AR列表中找到第一个存活的副本,且这个副本在目前的ISR列表中,unclean.leader.election.enable=false。
    2.AR列表中找到第一个存活的副本,这个副本可以不在的ISR列表中而在OSR列表中,unclean.leader.election.enable=true。

ControlledShutdownPartitionLeaderElectionStrategy,当某节点被优雅的关闭时 (执行 ControlledShutdown) ,该节点的副本都会下线,于此对应的分区需要执行 Leader 选举。

触发场景:
    * kafka的broker进程退出,发送消息给controller,controller触发
选举:
    * 在ISR列表中的选出存活的replica,还要确保这个副本不处于正在被关闭的节点上。否则抛出异常

PreferredReplicaPartitionLeaderElectionStrategy

触发场景:
    * znode节点/admin/preferred_replica_election写入相关数据
    * partition-rebalance-thread线程进行触发reblance时
    * 新产生controller
选举 :
    1) AR中取出一个作为leader,如果与原有leader一样,抛出异常
    2) 新leader的replica的broker存活且replica在ISR中,选出,否则抛出异常

ReassignPartitionLeaderElectionStrategy

触发场景:
    * znode节点LeaderAndIsr发生变化
    * Broker启动时
    * zknode节点/admin/reassign_partitions变动
    * 新产生controller时
选举:
    * 新设置的AR中,存在broker存活的replica且replica在ISR中则选出为leader,否则抛出异常

在所有的leader选举策略中,如果符合条件的replica有多个,如Seq[int],则使用的是Seq.head,取的是seq的第一个。

消费者组中的选举

类似broker中选了一个controller出来,消费也要从broker中选一个coordinator,用于分配partition。

组协调器GroupCoordinator需要为消费组内的消费者选举出一个消费组的coordinator,这个选举的算法也很简单,分两种情况分析:

  1. 如果消费组内还没有leader,那么第一个加入消费组的消费者即为消费组的leader。
  2. 如果某一时刻leader消费者由于某些原因退出了消费组,那么会重新选举一个新的leader,这个重新选举leader的过程又更“随意”了,在GroupCoordinator中消费者的信息是以HashMap的形式存储的,其中key为消费者的member_id,而value是消费者相关的元数据信息。leaderId表示leader消费者的member_id,它的取值为HashMap中的第一个键值对的key,这种选举的方式基本上和随机无异。总体上来说,消费组的leader选举过程是很随意的。

Kafka事务看这里

Kafka中的事务特性主要用于以下两种场景:

  • 生产者发送多条消息可以封装在一个事务中,形成一个原子操作。多条消息要么都发送成功,要么都发送失败。
  • read-process-write模式:将消息消费和生产封装在一个事务中,形成一个原子操作,即先消费消息,然后拿到消息后经过处理又写入kafka。在一个流式处理的应用中,常常一个服务需要从上游接收消息,然后经过处理后送达到下游,这就对应着消息的消费和生成。

当事务中仅仅存在Consumer消费消息的操作时,它和Consumer手动提交Offset并没有区别。因此单纯的消费消息并不是Kafka引入事务机制的原因,单纯的消费消息也没有必要存在于一个事务中。

使用时Kafka常用的配置

Topic和Partition

# 每个topic默认partition数量
num.partitions=1

#副本个数。除了开发测试外,其他情况都建议将该值设置为大于1的值以保证高可用
offsets.topic.replication.factor=1
transaction.state.log.replication.factor=1
transaction.state.log.min.isr=1

# 消息保留时间
log.retention.hours=168

# 所有日志的最大容量,超过后将删除旧的数据
#log.retention.bytes=1073741824

#消息超过保留时间或最大保存容量时,执行的清除策略,delete删除,compact压缩
log.cleanup.policy=compact

# 每个segement的大小.
log.segment.bytes=1073741824

# 检查日志的时间间隔以确定是否可以根据删除策略删除超出时间或容量的数据
log.retention.check.interval.ms=300000

Producer

异步发送:发送接口是异步的,可以同步发送,异步发送,也可以异步发送调用回调函数。
线程安全:Producer 是线程安全的,且可以往任何 Topic 发送消息。通常情况下,一个应用对应一个 Producer 就足够了。

#kafka集群ip和端口
bootstrap.servers

#消息发送后的确认机制,0:直接返回,1:leader节点确认,-1或者all:所有的副本确认
acks

#消息发送失败后,重试配置
request.timeout.ms 消息发送的超时时间
retries,重试次数,建议设置为 3。
retry.backoff.ms,重试间隔,建议设置为 1000

#批量发送
batch.size : 发送数据的时候,每批次数据的大小。
linger.ms : 每次批量发送的最大等待时间。若超过这个时间,就会忽略 batch.size 的限制,然后客户端立即把消息发往服务器

#Kafka批量发送时,会缓存消息并打包发送,如果缓存太多,则有可能造成 OOM(Out of Memory)。
buffer.memory : Kafka发送消息的总缓冲区大小,缓冲区满了以后会阻塞生产者线程,不让继续往Kafka写消息了。所有缓存消息的总体大小超过这个数值后,就会触发把消息发往服务器。此时会忽略 batch.size 和 linger.ms 的限制。这个参数的大小应该比batch.size大很多。
buffer.memory 是针对打个Producer的配置,默认数值是 32 MB,多个配置就会使用多个buffer.memory,对于单个 Producer 来说,可以保证足够的性能。 需要注意的是,如果您在同一个 JVM 中启动多个 Producer,那么每个 Producer 都有可能占用 32 MB 缓存空间,此时便有可能触发 OOM。
在生产时,一般没有必要启动多个 Producer;如果特殊情况需要,则需要考虑buffer.memory的大小,避免触发 OOM。

#生产者生成的所有数据的压缩类型。默认值为无(即不压缩)。有效值为none/gzip/snappy/lz4 。压缩涉及全部批次的数据,因此,批处理的效率也会影响压缩率(批处理越多意味着压缩效果越好)
compression.type

#这两个参数用来发送、接受数据的TCP连接的缓冲区。
send.buffer.bytes
receive.buffer.bytes

#单条条消息的最大大小,也就是说send的单条消息大小不能超过这个限制。这个限制只改一个地方是不行的producer, broker, consumer都要改才行. Default: 1048576.(1MB)
max.request.size

#尝试重新连接broker的时间间隔 Default: 50.
reconnect.backoff.ms
#每次再次连接失败会以指数增长,增长到的最大限度就是这个参数,为了避免连接风暴,连接重试的时间间隔会在一个范围内随机调整,上浮或下调20%,也就是说每次重连的时间间隔不一定就是这个值本身,而是上下浮动20%. 另外这里解释下连接风暴,当我们的kafka集群出现问题后,所有的producer和consumer都会尝试重连,重连的间隔就会达到这个参数所设置的最大值,比如大家都是每秒尝试重连,这时候如果集群回复了,那么在同一秒可能就会有大量的连接打到kafka集群上,这就造成了连接风暴,但是如果随机上下浮动就可能把重连时间给错开,不会造成同事的大量连接 Default: 1000.
reconnect.backoff.max.ms

#当buffer满了或者metadata获取不到(比如leader挂了),或者序列化没完成分区函数没计算完等等情况下的最大阻塞时间,默认60000ms (60秒)
max.block.ms
#生产者可以用来缓冲等待发送到服务器的记录的总内存字节。如果记录的发送速度超过了将其发送到服务器的速度,则生产者将阻塞max.block.ms ,此后它将引发异常。<p>此设置应大致对应于总内存生产者将使用但不是硬绑定,因为并非生产者使用的所有内存都用于缓冲。一些额外的内存将用于压缩(如果启用了压缩)以及维护进行中的请求

#key序列化函数. 默认值: None.
key.serializer
#值序列化函数默认值: None.
value.serializer 

Consumer

消费者消费的基本逻辑:

  1. Poll 数据
  2. 执行消费逻辑
  3. 再次 poll 数据
#每个消费者组可以包含多个消费实例,即可以启动多个消息队列 Kafka 版 Consumer,并把参数 group.id 设置成相同的值。属于同一个 Consumer Group 的消费实例会负载消费订阅的 Topic。
举例:Consumer Group A 订阅了 Topic A,并开启三个消费实例 C1、C2、C3,则发送到 Topic A 的每条消息最终只会传给 C1、C2、C3 的某一个。Kafka 默认会均匀地把消息传给各个消息实例,以做到消费负载均衡。
group.id

#消费者提交offset,消费者有两个相关参数:
enable.auto.commit:默认值为 true。
auto.commit.interval.ms: 默认值为 1000,也即 1s。
如果想自己控制offset提交 enable.auto.commit 设为 false,并调用 commit(offsets)函数自行控制位点提交。

#以下两种情况,会发生offset重置:
当服务端不存在曾经提交过的位点时(例如客户端第一次上线)。
当从非法位点拉取消息时(例如某个分区最大位点是10,但客户端却从11开始拉取消息)。
Java 客户端可以通过auto.offset.reset来配置重置策略,主要有三种策略:
"latest",从最大位点开始消费。
"earliest",从最小位点开始消费。
"none",不做任何操作,也即不重置。

#消费过程是由客户端主动去服务端拉取消息的,在拉取大消息时,需要注意控制拉取速度,注意修改配置:
max.poll.records,每次拉取的最多消息数,如果单条消息超过 1 MB,建议设置为 1。
fetch.max.bytes,每次拉取的最大总 byte 数,设置比单条消息的大小略大一点。如果是消费公网数据,建议设置成公网带宽的一半(注意这里的单位是bytes,公网带宽的单位是bits)
max.partition.fetch.bytes,每个 Partition 每次拉取的最大总 byte 数,设置比单条消息的大小略大一点。建议设置成fetch.max.bytes的三分之一或者四分之一。
拉取大消息的核心是一条一条拉的。

#消费者超时时间,消费者心跳超时可能会引起Rebalance,因此要设置一个合适的时间。适当提高该参数值,但不要超过30s,建议设置为25s。
heartbeat.interval.ms :心跳时间,此配置应该小于session.timeout.ms
session.timeout.ms:配置控制心跳的超时时间,可以由客户端自行设置。

关于kafka的各种问题

  1. Kafka 怎么保证消息的可靠性?保证不丢失?
    1). 从Kafka自身消息发送方式选择同步异步发送针对发送失败做相应的处理,比如重发,记录下来,下次再发。
    2). ACKS配置可以做到消息不丢失
    3).经过上面两种方案基本可以保证发送的可靠性
  2. 如何保证消息不被重复消费(消息幂等性)?
    重复消费的根本原因是offset没提交成功。
    常用做法是:
    (1)发送消息时,传入 key 作为唯一流水号ID;
    (2)消费消息时,判断 key 是否已经消费过,如果已经消费过了,则忽略,如果没消费过,则消费一次
  3. 消费消息处理失败?
    通常可以采用重试,但是要注意的是重试一定要有次数限制,避免后续数据一致没消费而造成消息堆积,在一定次数重试仍然失败后,可以将失败的消息通过日志或文件的方式记录下来,后续处理。
  4. 消息堆积?
    原因:消息队列 Kafka 版的消息是客户端主动去服务端拉取的,一般来说,因为是批量拉取机制,服务端拉取都不会是消费的瓶颈。消息堆积一般是消费速度过慢或者消费线程阻塞造成的。查看堆栈信息进行排查。 Java 进程可以用 Jstack 打印消费者进程的堆栈信息。因此原因主要有两个:一是消费速度跟不上生产速度,此时应该提高消费速度。二是消费端产生了阻塞。
    办法:针对第一种情况,我们可以增加消费者(增加消费者的本质也是增加线程),要注意的是:一个partition对于同一个消费者组,只能有一个消费者,因此要注意消费者的数量不要大于partition的数量,否则会出现空闲的消费者。
    针对第二种情况,如果消费者的消费逻辑比较耗时,就容易造成消费阻塞,因此应尽量避免这种情况。
  5. 消息广播如何实现?定义多个消费者组。
  6. 如何保证Kafka消息的顺序性?
    kafka只保证partition内的消息有序,不能保证不同partition的消息有序。如果同一个topic但是不同的子类也存入的partition,这时候就只有在生产消息的时候,根据子类的不同生成不同类型的key,在消费端,根据key存入不同的阻塞队列,然后从阻塞队列去消费数据,就可以保证消费到的数据是有序的。
  7. 为了避免心跳超时,引发Rebalance?
    (1)session.timeout.ms:适当提高该参数值,但不要超过30s,建议设置为25s。
    (2)尽量提高客户端的消费速度。
  8. 消费端从服务端拉取不到消息或拉取消息缓慢
    原因:(1)消费流量达到网络带宽。(2)单个消息大小超过网络带宽。(3)Consumer 每次拉取的消息量超过网络带宽
    解决办法:(1)控制每次消费的总容量(2)生产时控制单个消息的大小(3)网络带宽 > fetch.max.bytes;网络带宽 > max.partition.fetch.bytes * 总订阅 Partition 数
  9. 消费者首次接入Kafka 出问题应该怎么检查?
    (1)网络连通(2)客户端版本(3)配置
  10. 使用客户端发送消息后,如何确定是否发送成功?这也是生产消息的可靠性变相提问,即保证消息的不丢失
  11. 如何保证高可用的?
    Kafka的集群模式,配置Patition副本
  12. 如何确保消息正确地发送至 Kafka? 如何确保消息接收方消费了消息?这个问题其实就是第一个问题的变相提问
  13. 如何保证Kafka消息的可靠传输?这个问题也是第一个消息的变相提问
  14. 关于Kafka集群部署的时候怎么一个leader假死后,新的leader已经被选出,那么刚刚恢复的假死的leader怎么处理?因为Kafka集群是基于zookeeper部署的,其实就是在问zookeeper怎么解决脑裂的问题?
    其实就是根据zookeeper的选举机制,过半机制,然后选举成功后加一个epoch时间戳。看这里
  15. 设计MQ思路
    1)首先这个 mq 得支持可伸缩性吧,就是需要的时候快速扩容,就可以增加吞吐量和容量,那怎么搞?分布式集群
    2)其次的考虑系统的稳定?集群模式(kafka+zookeeper)
    3)保证数据丢失率?参考问题1的方式

关于Kafka集群搭建:https://www.cnblogs.com/fengweiweicoder/p/10841637.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值