kafka-整理-02-生产者

生产者分区策略

用于管理生产者在生产数据的时候,数据是存储在哪个分区的策略;

分区规则:在往生产者send数据的时候

  1. 【指定分区法】:可以指定分区,直接指明分区partition的值;
  2. 【key取模法】:当没有指定分区(也就是没有设置partition的值),但是发送消息的key我们是有的,这个时候会将key值的hash值和topic的分区数量(也就是有几个partition)进行取模,得到partiton的值;
  3. 最后一种情况:【轮询法】:既没有指定分区,也没有key,这个时候,在第一次调用的时候,随机生成一个数(后续自增),将这个值和topic中partition的数量,进行取模,也就是轮询所有的partition,按照顺序依次分发数据;

生产者如何保证数据的可靠性

1:什么是数据可靠性?
就是在发送数据的时候,能将数据发送给对应的partition中;
2:怎么判断kafka有没有接收到数据呢?
就是需要一个返回值(ack机制),
如果没有收到,就会重新发送;

	具体过程:
	在发送数据的时候,生产者发送数据会给partition中的leader,
	【也就是说生产者是跟leader进行交互的,跟follower不交互】
	
	leader写成功后,这个时候还不会发ack给生产者,
	leader会同步数据给其中一个follower,
	
	确保至少有一个follwer收到消息后(同步完成),
	leader再发送ack,
	
	为什么要等leader同步至少一个floweer呢?
	因为这样做至少能保证,如果leader挂了,起码还有一个flower有全部的数据可供回复,选举新的leader啥的;

这里又有一个问题了,常见的副本同步策略有哪些?

副本同步策略?

常见的副本同步策略其实有两种:
一种是:半数以上完成同步,就发送ack;
一种是:全部完成同步,再发送ack;

这两个优缺点?

半数:
优点:延迟低,因为我只需要同步一办的副本,就返回了;
缺点:机器多,假设在选举新的leader时候,可以容忍n台节点故障,因为你要半数,所以我这边至少需要2n+1台机器,才能满足你半数的要求;

全部:
优点:假设选举新的leader的时候,你可以容忍n台节点挂掉,那么我只需要n+1个副本就可以了,因为你全部同步,我只要保留一台存活,比你n多一台就好,就能进行数据同步;
缺点:延迟高。因为要全部同步完后才ack;

kafka的副本同步策略

1:kafka发送ack需要等leader同步数据给flower后,才会ack,那么需要leader同步给几个flower呢?
目前的方案:【kafka采用的是全部同步】

为了容忍n台节点的故障,
半数:需要2n+1个副本,
全部:只需要n+1个副本,
而kafka每个分区都有大量的数据(kafka分区都会有数据),
半数,因为副本节点多,会造成大量的数据冗余;

虽然,全部,可能延迟高,但是网络延迟对kafka的影响比较小;

【全部副本都同步】有一个最大的问题,若是我在同步的过程中,有一个副本延迟很高(但是还没有挂),那么我不是永远或者需要很久才能发送ack了吗?因为你需要全部副本同步后,才发送ack的;

所以kafak在采用【全部同步副本后才ack】机制的时候,对这个机制进行了优化

kafka优化后的副本同步机制【ISR-叫同步副本队列-其实就是-集合列表】

【ISR—同步副本队列—in-sync-replica-set】
其实很好理解,就是我设置一个数值,只要在同步副本的时候达到我这个数值,就可以ack了;

isr:保存了和leader同步的follower集合;
当ISR中的follower完成数据同步之后,leader会给生产者发送ack。
如果follower长时间没有向leader同步数据,那么这个follower就会VB诶提出ISR集合列表中。

那这个阈值怎么配置呢?

replica.lag.time.max.ms: 10000 最大同步延迟时间(默认10秒)
若是同步时间在这个时间内,就可以加到ISR中;
若是同步时间超过这个时间,就需要从ISR中提出;

当leader挂掉之后,就会从ISR集合列表中进行选举;

ack应答机制

对于某些不重要的数据,其实是不需要ack的,生产者发给kafka后,直接返回就可以了,可以允许少量的数据丢失;
所以也没必要ISR中的所有队列都接收成功后,才ack;

所以kafka提供了【三种可靠性】的级别:
【反正就是我觉得我这个数据可靠性不高】

生产者配置:
acks参数配置:

0:当配置为0的时候,表示生产者不等待broker的ack,就是broker一接收到数据就立马返回,此时可能broker还没有写入磁盘,当borker故障的时候,可能会丢数据,但是效率高啊,最低级别的延迟,相当于没有延迟;
(也就是我们理解的异步)

1:当设置为1的时候,生产者会等待boker的ack,partition的leader在写入磁盘成功后,返回ack,只等待leader写完;
缺点:若是此时还没有同步给任何一个follower,leader挂了,将会丢失数据;
有点:相比与上面,有第二低的延迟;因为只要leader写完就ack;

-1(all):当设置值为-1的时候,就是生产者会等待borker的ack,而且是等待leader和ISR中的follower全部落盘成功后才返回ack。
但是这个时候若是leader挂掉了,从ISR中新选取一个leader,这个时候是不会丢失数据的,
-1会丢失数据】:但是极限情况下【因为在极限情况下ISR中若是有3个,一个leader,2个follower,但是刚好两个follower同步很慢,被移出ISR了,这个时候,相当于ISR中只有leader一个了,相当于只同步leader(acks值为1的场景),若是这个leader挂了,那么就会丢数据】当然这是极限情况;
-1会重复数据】:若是刚好follower同步完成,还没有ack的时候,这个时候leader挂掉了,会进行leader选举,因为此时follower都写完了,而且生产者还没有接收到ack,这个时候生产者会再发送一次数据,那么这条数据就会被发给新选举的leader,相当于这个新的leader中有两条重复的数据;

数据一致性

ISR中存储和消费的一致性:

在ISR列表中:
leader中有10条数据,
有一个follower写了5条数据,一个follower写了6条数据,
若此时leader挂掉了,
需要进行leader选举,这两个follower都有可能被选为leader;

这个时候问题来了?
假如6条的follower被选举为leader了,选完之后,
发现原来的leader突然活了,这个时候数据就不一样了;

在这里插入图片描述

这里就需要有一个处理了:
LEO:log end offset (每个副本中的最后一个offset,log文件中最后一个offset,就是每个副本最大的offset)
HW:high watermark(所有副本中最小的LEO,消费者能见到的最大的offset,也就是说HW之前的数据才对消费者可见);

HW:也叫【高水备】,就是保证所有副本都同步到当前数据了;然后这些数据对消费者是可见的;

消费者可以看到这块的数据,所以,你的副本可以随便挂掉,任何副本都可以挂掉,因为所有副本都会有这部分数据;

但是会有数据丢失,
至于数据丢失用ack去解决好了,设置acks=-1好了;

HW是可以保证消费者在消费数据的时候,数据一致性;
就是保证了消费一致性;
因为HW的位置是所有副本可见的,就算你有一个副本的offset比我超前,然后你挂掉,
然后我短的这个副本被升级为leader,
这样生产者再次发送数据的时候,也是从HW的offset往后加的,
对于消费者而言,不会出现重复消费的场景,保证了数据的一致性;

https://www.zhihu.com/question/335274325/answer/758188050

follower故障:

follower发生故障后,会被临时提出ISR,等到follower恢复后,follower会读取本地磁盘记录的上次的HW,并将log文件高于HW的部分【截取掉】,从HW开始向leader进行同步,等待该follower的LEO大于等于该partition的HW,既follower追上leader后,就可以重新加入ISR了;

所以在重新选择leader的时候,给所有的副本发一个消息,要截取;下面的leader故障;

leader故障:

leader发生故障后,会从ISR中组中选出一个新的leader,后,为了保证多个副本之间的数据一致性,其余的follower会先将各自的log文件【高于HW的部分截掉】,然后从新的leader同步数据;

反正就是以最短的为准,哪个长的,就切掉;
只能保证副本之间的数据一致性问题,并不能保证数据不丢失或者不重复;

数据丢失和重复可以用ack来保证;

HW:本意是保证了消费者可见的最大offset的值,保证了消费者消费数据的一致性;
所以HW解决的是数据一致性问题(消费的一致性和存储的一致性),不能解决数据丢失或者重复问题;
ack是解决丢失和重复问题的;

幂等性

kafka生产者也有幂等性:

修改生产者参数:
enable.idompotence=true
这个就是原本我们在消费者中实现的幂等性(根据主键或者其他),kafka帮我们做了,并且在生产者就做了幂等;

开启了幂等的生产者在初始化的时候会被分配一个PID,
发往同一个partition的消息会附带 sequence number;

而broker会对(PID,partition,sequence number)做缓存,
当具有相同主键的消息提交时,broker值会持久化一条;

但是PID重启就会发生变化,同时不同的partition也具有不同的主键;

幂等性只能解决单个会话(生产者挂掉重新建立连接,就是另一个PID),单次分区里面的数据重复问题;

没办法做到分区间,跨会话的精准一次性写入;

但是能做到同一次会话(同一个生产者不重启的前提),同一个分区的精准一次性写入;

https://www.cnblogs.com/kaichenkai/p/11959392.html
https://blog.csdn.net/qq_38262266/article/details/107356824

おすすめ

転載: blog.csdn.net/u010953880/article/details/116901891