在聊Kafka高牢靠之前,先在评论区来波RNG NB好不好!

什么叫可靠性?

大家都晓得,零碎架构有三高:「高性能、高并发和高可用」,三者的重要性显而易见。

对于任意零碎,想要同时满足三高都是一件十分艰难的事件,大型业务零碎或者传统中间件都会搭建简单的架构来保障。

除以上三种模式之外,还有一个指标方向也很重要,那就是高牢靠,甚至你可能会将它和「高可用」混同起来。

事实上两者并不一样,高可用会更偏差于整体服务的可用性,避免零碎宕机等等。而高牢靠是指数据的可靠性保障嘛,你能够了解”高牢靠“相比于零碎三高会是一个更细一点的概念。

那么什么是数据的高牢靠呢,总结一下就是零碎要提供牢靠的数据撑持,不能产生失落、反复等谬误景象。

所以每个开源中间件在公布版本时都会通过文档申明本人是超牢靠的,就像520那天每一位暖男说的那样。

咱明天的配角kafka就是这么一个例子。

一些重要概念

因为有一段时间没讲音讯队列了嘛,为了帮忙你更好了解文章,咱们来先温习一下kafka的根底概念:

  • record:音讯,音讯队列根底通信单位
  • topic:主题,目标就是将音讯进行分类,不同业务类型的音讯通常会被散发到不同的主题
  • partition:分区,每个主题能够创立多个分区,每个分区都由一系列有序和不可变的音讯组成
  • replica:正本,每个分区都有一个至多个正本存在,它的次要作用是存储保留数据,以日志(Log)对象的模式体现。正本又分为leader正本和follower正本
  • offset:偏移量,每一个音讯在日志文件中的地位都对应一个按序递增的偏移量,你能够了解为相似数组的存储模式
  • producer:生产者,生产音讯的那一方
  • consumer:消费者,通常不同的业务都会有一到多个消费者组成消费者集群
  • broker:代理,一个Kafka集群由一个或多个Kafka实例形成,每一个Kafka实例就称为代理

如上图所示,一共存在主题1和主题2,主题1有两个分区,主题2只有一个分区,并且每个分区都存在一个leader正本和两个follower正本,它们散布在每个不同的代理节点上

partition里只有leader正本负责与生产者、消费者之间数据的交互,follower正本会定期从leader正本拉取数据以保障整个集群数据可用性。

如何保证数据高牢靠

Kafka是通过正本机制实现数据的存储的,所以就须要一些机制保证数据在跨集群的正本之间可能牢靠地传输。

1.正本同步汇合

业务数据封装成音讯在零碎中流转,因为各个组件都是散布在不同的服务器上的,所以主题和生产者、消费者之间的数据同步可能存在肯定的时间延迟,Kafka通过提早范畴划分了几个不同的汇合:

AR(Assigned Replicas)

指的是曾经调配数据的分区正本,通常指的是leader正本 + follower正本。

ISR(In Sync Replicas)

指的是和leader正本数据放弃同步的正本汇合。当follower正本数据和leader正本数据放弃同步,那么这些正本就处在ISR外面,ISR汇合会依据数据的同步状态动态变化。

OSR(Out Sync Replicas)

一旦follower正本的数据同步进度跟不上leader了,那么它就会被放进叫做OSR的汇合里。也就是这个汇合蕴含的是不处于同步状态的分区正本。

OK,那有什么规范判断它是同步还是不同步呢?

通过replica.lag.time.max.ms这个参数来设置数据同步时间差,它的默认值是10s。

一旦从分区正本和主分区正本的音讯相差10s以上,那么就认为音讯处于OSR不同步的状态。若follower处于OSR汇合里,那么在选取新的leader的时候就不会选举它作为新leader。

2.ACK应答机制

咱们刚刚说了kafka是通过ack来发送数据同步信号的,那信号发送频率又有几种设定呢?

  • ack = 0

生产者发送一次音讯就不再发送。不论是否发送胜利,若收回去的音讯处于通信的路上就失落,或者还未做磁盘长久化操作,那么音讯就可能失落。

它的益处就是性能很高,你想呀你发送音讯都不须要期待对方回复就继续发送下一批,那么音讯期待的工夫就节俭进去了。同一时间范畴内能比他人解决更多数据,毛病就是它的可靠性真的很低,数据真的是说丢就丢。

  • ack = 1

leader接管到音讯并且写入到本地磁盘后就认为音讯解决胜利。这种形式可靠性会比上一种好一些,当leader接管到音讯并且写入到本地磁盘后就认为音讯解决胜利,不管follower是否同步完这条音讯就会返回给producer。

然而如果此刻partition leader所在的broker宕机了,如果那么数据也可能会失落,所以follower正本的数据同步就很重要。

Kafka默认就采纳这种形式。

  • ack = -1

producer只有收到分区内所有正本的响应ACK才会认为音讯曾经push胜利。

这种形式尽管对于数据的牢靠保障做得很好,然而就是性能很差,影响吞吐量,所以个别也不会采取。

那么它就相对牢靠吗?也不肯定。最重要的还是取决于正本数据是否同步实现。若producer收到响应音讯前leader正本挂掉,那么producer会因未收到音讯反复发送音讯,那就可能造成数据反复。怎么解决呢?只有保障业务幂等就行。

咱们能够通过request.required.acks这个参数管制音讯的发送频率。

如果感觉文章不错,能够微信搜一搜「 敖丙 」第一工夫浏览,关注后回复【材料】有我筹备的一线大厂面试材料和简历模板

3.音讯语义

音讯集群整体是一个简单的零碎,所以过程中可能会因为各种起因导致消息传递出错,Kafka对于这些可能遇到的场景定义了对应的的音讯语义。

at most once

它代表音讯可能被消费者生产0次或者1次。若场景如下:

  • 音讯从partition分发给消费者集群
  • 消费者把本人收到的音讯通知集群,集群收到之后offset就会往后挪动
  • 消费者将数据入库做长久化

你肯定想到了。在第三步消费者将音讯入库时若因任何起因消费者A挂了,那么在将消费者切换到集群的消费者B后,数据还没入库呢。此时partition是浑然不知的呀,那么这就会造成一个问题:数据失落。

at least once

它代表partition散发的音讯至多被生产一次。其通信过程如下:

  • 音讯从partition分发给消费者集群
  • 消费者将数据入库做长久化
  • 消费者把本人收到的音讯通知集群,集群收到之后offset就会往后挪动

假如consumer group在数据入库之后,在将数据返回给partition的过程中消费者A挂了,那么partition会因为接管不到响应ACK而从新发送数据,此时消费者B可能再次将原先的音讯入库,这就造成了数据反复了。

在没有做任何幂等性爱护的状况下,像反复转账,重付叠加积分这种业务,那么后果可能是致命的。

exactly once

代表音讯正好能被生产一次,不失落,不反复。

在at least once的状况根底上,假如consumerA在返回ack给partition的过程中宕机了。那么consumerB不会跟着partition的offset走,它会先去数据库外面查看最新消息对应的偏移位,再依据这个偏移位返回Kafka集群从对应的偏移地位登程,这就能够防止音讯反复和音讯失落。

不晓得有多少小伙伴看到这里的,如果感觉目前为止写的还不错的,能够帮忙点个赞让,让我看看有多少好学的宝宝。

4.数据截断机制

咱们结尾说了真正解决数据的是leader正本,follower正本只负责数据的同步和保留,那如果因为leader宕机了二者数据不统一会怎么样呢?

在讲一致性保障过程之前还需理解两个Kafka用于示意正本数据同步的概念:

HW(High Watermark):中文翻译为高水位,用来体现正本间数据同步的绝对地位,consumer最多只能生产到HW所在的地位,通过HW咱们能够判断数据对正本是否可见。

LEO(Log End Offset):下一条待写入音讯的记录地位。

leader正本从生产者获取音讯,follower正本实时从leder同步数据,此时它们的同步数据是统一的都同步到2这个地位,并且下一个写入的音讯都是偏移位4:

假如因为意外leader产生宕机,follower即被选为新leader,尔后从生产者写入最新的偏移位4和5:

过了一段时间原leader通过修复复原服务,它就会发现自己和新leader的数据是不统一的:

为了保证数据一致性就必须强行让一方斗争。因为数据是一直在刷新的,所以旧leader此时的优先级会小于新leader,因而它会将本人的数据截断到与新leader雷同的HW和LEO地位,确保和新leader的数据肯定雷同,这就是Kafka数据截断机制。

5.数据清理机制

同其它中间件一样,Kafka的次要作用是通信,所以即便是将数据保留在磁盘上它还是会占用肯定空间。为了节约存储空间它会通过一些机制对过期数据进行清理。

日志删除

日志删除会间接删除日志分段,kafka会保护一个定时工作来周期性检查和删除「过期数据」

  • 基于工夫的日志删除

它在每一个日志段文件外面都保护一个最大工夫戳来确认以后配置的删除工夫,只有日志段写入新音讯该字段都会被更新。一个日志段被写满了之后就不会再接管新的音讯,它会去创立一个新的日志段文件往里面写数据。

每一个日志段文件被写满之后它的最大的工夫戳都是放弃不变的,Kafka只有通过以后工夫与最大工夫戳进行比拟就能够判断该日志段文件是否过期。

Kafka默认配置log.retention.hours = 168,也就是7天的日志保留工夫。

  • 基于容量大小的日志删除

这和以上是殊途同归的形式, 只不过这次从工夫换成了空间。

Kafka会通过每个日志段空间的大小计算一个总容量阈值,而后计算出以后的理论空间大小和总容量阈值的差值,如果这个差值大于单个日志段文件的大小那么就会删除掉最旧的那个日志段文件,反之则不做任何解决。

同理,这个阈值也能够通过log.retention.bytes参数来设置。

日志压缩

Kafka的音讯是由键值组成的,如果日志段里存在多条雷同key然而不同value的数据,那么它会选择性地革除旧数据,保留最近一条记录。

具体的压缩形式就是创立一个检查点文件,从日志起始地位开始遍历到最大完结地位,而后把每个音讯的key和key对应的offset保留在一个固定容量的SkimpyOffsetMap中。

这样后面的值就会被前面的笼罩掉,如果日志文件里存在雷同的key只有最新的那个会被保留。

总结

Kafka通过ACK应答机制保障了不同组件之间的通信效率,通过正本同步机制、数据截断和数据清理机制实现了对于数据的管理策略,保障整个零碎运行效率。

作为一款高性能又同时兼顾高可靠性的消息中间件来说,Kafka能吹的点切实太多。如果本篇文章对你有所帮忙,点击一下右下角的大拇指,下一次咱们来具体解说Kafka是如何实现正本间数据传递的。

你晓得的越多,不晓得的越多,各位的点赞评论都对我很重要,如果这篇文章有帮忙你多一点点理解Kafka的话,能够在评论区来一波“变得更强”。

也心愿你的bug和上面这张图一样, 退 退 退!咱们下次见。


文章继续更新,能够微信搜一搜「 敖丙 」第一工夫浏览,关注后回复【材料】有我筹备的一线大厂面试材料和简历模板,本文 GitHub https://github.com/JavaFamily 曾经收录,有大厂面试残缺考点,欢送Star。