当前位置:首页>幼教>正文

kafka学习笔记 幼师自学笔记20篇

2023-07-11 02:49:46 互联网 未知 幼教

kafka学习笔记 幼师自学笔记20篇

kafka学习笔记

参考两篇博主文章:

原文链接:https://blog.csdn.net/qq_37200262/article/details/125267714原文链接:https://blog.csdn.net/wudidahuanggua/article/details/127086186

1.kafka-消息传递模型

发布-订阅模型

消息发布到一个topic中,消费者订阅一个或者多个topic,消费者即可消费该topic中的所有数据。同一条数据可以倍多个消费者消费,数据消费后不会里面删除。

 与之对应的消息模型:点对点消息传递模型

消息持久化到一个队列中。将一个或多个消费者消费队列中的数据。但是消息只能被一个消费者消费,当消息被消费后就会从队列中删除。该模式即使有多个消费者同时消费数据,也能保证数据处理的顺序。

 2.kafka消息引擎的作用(好处或者意义)削峰填谷:缓冲上下游瞬时突发流量,使其更平滑。解耦:减少系统间不必要的交互。易扩展:消息集群扩展容易。顺序保证:Kafka保证一个Partition内的消息的有序性。3.kafka的组成

 

broker

Kafka集群包含一个或多个服务器,服务器节点称为broker。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的消息虽然保存于一个或多个broker上但用户只需指定消息的Topic即可生产或消费数据而不必关心数据存于何处)类似于数据库的表名

Partition

topic中的数据分割为一个或多个partition。每个topic至少有一个partition。每个partition中的数据使用多个segment文件存储。partition中的数据是有序的,不同partition间的数据丢失了数据的顺序。如果topic有多个partition,消费数据时就不能保证数据的顺序。在需要严格保证消息的消费顺序的场景下,需要将partition数目设为1。

Producer

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

Consumer

消费者可以从broker中读取数据。消费者可以消费多个topic中的数据。

ConsumerGroup

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

Leader

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

Follower

Follower跟随Leader,所有写请求都通过Leader路由,数据变更会广播给所有Follower,Follower与Leader保持数据同步。如果Leader失效,则从Follower中选举出一个新的Leader。当Follower与Leader挂掉、卡住或者同步太慢,leader会把这个follower从“insyncreplicas”(ISR)列表中删除,重新创建一个Follower。4.kafka消息存储消息磁盘顺序存储:每条消息必须放到指定的topic中。为了提高Kafka的吞吐率,物理上吧Topic分成一个或多个Partition,每个Partition在物理上对应一个文件夹,该文件夹下存储这个Partition的所有消息和索引文件。创建一个topic时,同时可以指定分区数目,分区数越多,其吞吐量也越大,但是需要的资源也越多,同时也会导致更高的不可用性,kafka在接收到生产者发送的消息之后,会根据均衡策略将消息存储到不同的分区中。因为每条消息都被append到该Partition中,属于顺序写磁盘,因此效率非常高。消息被永久保存(默认):Kafka的消息无论是否倍消费都会倍保存。消息的删除策略:基于时间、基于Partition的文件大小。读取哪一条消息由Consumer决定(offset):Kafka会为每一个ConsumerGroup保留一些metadata信息——当前消费的消息的position,也即offset。这个offset由Consumer控制。正常情况下Consumer会在消费完一条消息后递增该offset。当然,Consumer也可将offset设成一个较小的值,重新消费一些消息。Producer消息路由Producer发送消息到broker时,会根据Paritition机制选择将其存储到哪一个Partition。如果Partition机制设置合理,所有消息可以均匀分布到不同的Partition里,这样就实现了负载均衡。如果一个Topic对应一个文件,那这个文件所在的机器I/O将会成为这个Topic的性能瓶颈,而有了Partition后,不同的消息可以并行写入不同broker的不同Partition里,极大的提高了吞吐率。可以在$KAFKA_HOME/config/server.properties中通过配置项num.partitions来指定新建Topic的默认Partition数量,也可在创建Topic时通过参数指定,同时也可以在Topic创建之后通过Kafka提供的工具修改。在发送一条消息时,可以指定这条消息的key,Producer根据这个key和Partition机制来判断应该将这条消息发送到哪个Partition。Paritition机制可以通过指定Producer的paritition.class这一参数来指定,该class必须实现kafka.producer.Partitioner接口。ConsumerGroup

使用ConsumerhighlevelAPI时,同一Topic的一条消息只能被同一个ConsumerGroup内的一个Consumer消费,但多个ConsumerGroup可同时消费这一消息。

 

这是Kafka用来实现一个Topic消息的广播(发给所有的Consumer)和单播(发给某一个Consumer)的手段。一个Topic可以对应多个ConsumerGroup。如果需要实现广播,只要每个Consumer有一个独立的Group就可以了。要实现单播只要所有的Consumer在同一个Group里。用ConsumerGroup还可以将Consumer进行自由的分组而不需要多次发送消息到不同的Topic。实际上,Kafka的设计理念之一就是同时提供离线处理和实时处理。根据这一特性,可以使用Storm这种实时流处理系统对消息进行实时在线处理,同时使用Hadoop这种批处理系统进行离线处理,还可以同时将数据实时备份到另一个数据中心,只需要保证这三个操作所使用的Consumer属于不同的ConsumerGroup即可。Kafkadeliveryguarantee

有这么几种可能的deliveryguarantee:

Atmostonce消息可能会丢,但绝不会重复传输Atleastone消息绝不会丢,但可能会重复传输Exactlyonce每条消息肯定会被传输一次且仅传输一次,很多时候这是用户所想要的。5.kafka保证消息不丢失和不重复消费5.1生产者推送消息时保证消息不丢失和不重复

为保证producer发送的数据,能可靠的发送到指定的topic,topic的每个partition收到producer发送的数据后,并等待该分区中全部的follower同步完成,该分区的leader才向producer发送ack(acknowledgement:确认收到),如果producer收到ack,就会进行下一轮的发送,否则重新发送数据。

而为了处理follower在同步数据时发生故障,导致leader一直等待下去的情况,新增了ISR的机制。

ISR介绍:Leader维护了一个动态的in-syncreplicaset(ISR:同步副本),意为和leader保持同步的follower集合。当ISR中的follower完成数据的同步之后,leader就会给producer发送ack。如果follower长时间未向leader同步数据,则该follower将被踢出ISR,该时间阈值由replica.lag.time.max.ms参数设定。而如果Leader发生故障,就会从ISR中选举出新的leader。ACK介绍:对于某些不太重要的数据,对数据的可靠性要求不是很高,能够容忍数据的少量丢失,所以没必要等ISR中的follower全部接收成功,才返回ack。所以 Kafka 为用户提供了三种可靠性级别,用户根据对可靠性和延迟的要求进行权衡,选择以下的配置。0:producer不等待broker(或者说是leader)的ack,这一操作提供了一个最低的延迟,broker一接收到还没有写入磁盘的数据就已经返回,当broker故障时有可能丢失数据;1:producer等待broker的ack,partition的leader落盘成功后返回ack,如果在follower同步成功之前leader故障,那么将会丢失数据;-1(all):producer等待broker的ack,partition的leader和ISR里的follower全部落盘成功后才返回ack。但是如果在follower同步完成后,broker发送ack之前,leader发生故障,那么会造成数据重复。(假如ISR中没有follower,就变成了ack=1的情况)三种语义:AtMostOnce 语义:消息可能会丢,但绝不会重复传输。将服务器ACK级别设置为0,可以保证生产者每条消息只会被发送一次。AtLeastOnce语义:消息绝不会丢,但可能会重复传输。将服务器的ACK级别设置为-1(all),可以保证Producer到Server之间不会丢失数据。ExactlyOnce语义:每条消息肯定会被传输一次且仅传输一次。AtLeastOnce+幂等性=ExactlyOnce。​​​幂等性:所谓的幂等性就是指Producer不论向Server发送多少次重复数据,Server端都只会持久化一条。要启用幂等性,只需要将Producer的参数中enable.idempotence设置为true即可(此时ack=-1)。Kafka的幂等性实现其实就是将原来下游需要做的去重放在了数据上游。原理:开启幂等性的Producer在初始化的时候会被分配一个PID,发往同一Partition的消息会附带SequenceNumber。而Broker端会对做缓存,当具有相同主键的消息提交时,Broker只会持久化一条。但是PID重启就会变化,同时不同的Partition也具有不同主键,所以幂等性无法保证跨分区、跨会话的ExactlyOnce。(也就是说它只解决单次会话、单个分区里的消息重复问题)过程总结

        总结以上,可以得知生产者在推送消息时,依靠的是ISR、ACK机制、以及三种语义来达到不同情况的消息准确性。

        所以总的过程应该是这样的:producer向指定的topic和partition发送数据,topic的每个partition收到producer发送的数据后,(下一步是等待ISR的follower同步完成,这一步会根据ack的参数配置[0,1,-1],确定具体的ack返回时机),该分区的leader向producer发送ack(acknowledgement:确认收到),如果producer收到ack,就会进行下一轮的发送,否则重新发送数据。

        而如果要保证生产者推送到服务器里的消息数据即不重复又不丢失,就要使用ExactlyOnce语义:将ack参数配置为-1,并开启幂等性(enable.idempotence=true)。

5.1.1follower与leader出故障,怎么保证数据的一致性

 

LEO:(LogEndOffset)每个副本的最后一个offset;HW:(HighWatermark)高水位,指的是消费者能见到的最大的offset,ISR队列中最小的LEO;

follower故障和leader故障:

follower故障:follower发生故障后会被临时踢出ISR,待该follower恢复后,follower会读取本地磁盘记录的上次的HW,并将log文件高于HW的部分截取掉,从HW开始向leader进行同步。等该follower的LEO大于等于该Partition的HW,即follower追上leader之后,就可以重新加入ISR了。leader故障:leader发生故障之后,会从ISR中选出一个新的leader,之后,为保证多个副本之间的数据一致性,其余的follower会先将各自的log文件高于HW的部分截掉,然后从新的leader同步数据。

注意:这只能保证副本之间的数据一致性,并不能保证数据不丢失或者不重复。ack是负责数据丢失的

5.2 消费者丢失消息和重复消费消息的情况

consumer采用pull(拉)模式从broker中读取数据。这个过程只涉及到了服务器和消费者两方,那消费者是怎么保证不丢失和不重复的获取消息呢?

关键在于consumer会维护一个offset,该offset实时记录着自己消费的位置。同时消费者能见到的最大的offset,是HW,是ISR队列中最小的LEO【这一点看1.3】,所以只要保证offset不出错,那消息就不会丢失或者重复消费。但是offset的维护并不是那么简单,它分为好几种方式。

offset的维护方式:

自动提交enable.auto.commit:是否开启自动提交offset功能,消费者只在启动的时候去访问offset的值,如果将该值配置为false,就要手动提交offset,否则offset就不会更新。auto.commit.interval.ms:自动提交offset的时间间隔手动提交commitSync(同步提交)commitAsync(异步提交)两者的相同点是:都会将本次poll的一批数据最高的偏移量提交;不同点是:commitSync阻塞当前线程,一直到提交成功,并且会自动失败重试(由不可控因素导致,也会出现提交失败);而commitAsync则没有失败重试机制,故有可能提交失败。无论是同步提交还是异步提交offset,都有可能会造成数据的漏消费或者重复消费。先提交offset后消费,有可能造成数据的漏消费;而先消费后提交offset,有可能会造成数据的重复消费。自定义存储offsetoffset的维护是相当繁琐的,因为需要考虑到很多东西,例如消费者的Rebalace。 5.3总结

对于消息重复:这个影响不是很严重,无论是生产者重复推送数据,还是消费者重复拉取数据,只要在消费端落库时,手动做去重就可以了。

对于消息丢失:

consumer端丢失消息的情形比较简单:如果在消息处理完成前就提交了offset,那么就有可能造成数据的丢失。由于Kafkaconsumer默认是自动提交位移的,所以在后台提交位移前一定要保证消息被正常处理了,因此不建议采用很重的处理逻辑,如果处理耗时很长,则建议把逻辑放到另一个线程中去做。为了避免数据丢失,可以采用手动提交offset:(1)enable.auto.commit=false关闭自动提交位移、(2)在消息被完整处理之后再手动提交位移生产者丢失消息是最复杂的情形了。生产者(Producer)使用send方法发送消息实际上是异步的操作,我们可以通过get()方法获取调用结果,但是这样也让它变为了同步操作,但是一般不推荐这么做!可以采用为其添加回调函数的形式。这个回调函数会在Producer收到ack时调用,此处就和acks参数配置[1、0、-1]密切相关了。如果消息发送失败的话,我们检查失败的原因之后重新发送即可!另外这里推荐为Producer的retries(重试次数)设置一个比较合理的值,一般是3,但是为了保证消息不丢失的话一般会设置比较大一点。设置完成之后,当出现网络问题之后能够自动重试消息发送,避免消息丢失。另外,建议还要设置重试间隔,因为间隔太小的话重试的效果就不明显了,网络波动一次,你3次一下子就重试完了。

相关文章