00:00
然后接下来我们来看整个卡夫卡内部的卡夫卡的一些内部实现原理吧,呃,整个的卡夫卡就是它整体的卡卡的一个架构,就是这当图描述的一个样子啊,左边呢是生产者,然后中间呢是我们的一个博洛集群啊,那右边呢,就是一个消费者啊消费者啊,多个消费者呢,属于一个消费者组啊,同时呢,它的原数据由keepper去啊维护啊,那接下来其实我们就来看啊,以一个topic为例的话,那它内部在broke我们的集群内部的话啊,它会分成这样子,就是每三个broke集群里面的话,如果我们这个topic a它是一个三个分区,然后两个副本的话。整个整个的过程就是构成了他总共有呃六个帕提圣啊那帕提。啊,A的提零对的啊对的,第一个点在这个第一个上面的副本是在三上面,然后丁是一呢,对应的leader呢,它就是在BLOCK1,然后副本呢,对应的在零上面,然后第三个呢,丁是二,对应的leader在三上面啊,那对应的呢在二上面啊整个呢,其实就是这样一个交叉,它所有的副部呢,是分散在我们的整个集群里面。
01:22
啊,那我们生产这边生产消息的话,对应的消息生产过来会呃,选择某选择一种负载均衡的方式,然后分发给我啊,路由到我们的具体的每某个帕提式里面,然后提式里面呢,会将消息存储在我们的C里面啊,那整个就是简单这样一个过程啊。那在这整个在这一节里面的话,我们呢,会啊,重点来从三个方面来介绍啊,那第一第一个的话就是我们以介绍卡夫卡它单机呃单实力环境下的一些内容,同时呢,在啊介绍下它单实力环境。内容之后呢,再来去介绍它的集训环境的一些内容,最后做一个总结,当时利益环境里面的话,我们主要是会介绍啊,主要是会介绍到它的一个啊卡夫卡的主体模型啊,就是它主体的一个整体的模型架构是怎样,第二个的话就会介介绍一下卡夫卡的啊消息的一个存储,以及他消息的一个检索啊,那第三部分呢,会介绍他卡不卡消息的一个清理啊,第四部分呢,会介绍他卡不卡啊的一个消费消息的一个消费模型啊,这就是主要的这一部分内容。
02:34
啊,那我们来看主体的一个核心流程,其实看这张图的话,基本上啊,我们重点就关注的是消息队列内部的一个啊实现,那我们以一个三个分区啊,单个副本为例的一个topic来举例的话,那其实就它总共有三个分区啊,那也就是提士零的012啊在每一个帕提里面呢,它的数据呢,是按照sig特啊这每一个帕提式呢,是一个逻辑上的队列啊,它里面实际物理存储的时候呢,是按照S格特来分段去存储数据的,所以就是它的地是零呢啊就可以分成段零段一段二段三这样的很多很多很多个段,每一个段里面的话。
03:13
其实它都有数据文件和所有文件构成,那数据文件的话,主要就存储的是我们原始生产者发过来的消息啊,然后将消息呢,通过TR到V的方式呢,按照固定的格式存储到这个啊日志文件里面,那接下来存储到日志文件里面之后呢,那就是查找消息的时候怎么办呢?就通过我们的点ex所引文件来去查找啊点ex文件,所以查找的时候呢,啊,就我们首先呢,是通过我们的啊查找inex,然后再去找我们的对应的log,那点time inex这个文件呢,主要就存的是时间戳我们的消息之间的一个关系啊,然后整个那每一个段,它逻辑上是一个队列的话啊,就是我们的帕丁圣其实是一个逻辑队列,那每一个段呢,他其实是。
04:00
有先后的一个时间关系,同时这些段之间呢,他们也是有序的,在命名上面呢,他们都是以每一条消息啊,就是每一个消息有一个编号,所以每一个段在存储的时候,它的命名呢,都是以这个段保存的当前第一条消息的一个编号作为它的命名啊,就是这样一个顺序,所以它整个的这个段呢,整个的这些段拼在一起,就是一个有序的一个啊,逻机上面的队列构成了爬行式。啊,然后接下来我们来看,那在提在他内部的每一个C里面的数据是如何组织的呢?其实前面提到的他。像卡不卡,它它的话主要就是啊数据存储在磁盘上啊,所以呢,就根据前面介绍,它主要充分利用一个数据IO追加写,保证它的一个写性能啊,同时呢,文文件呢,采用的是分段存储,那每个消息呢,它有一个编号,它称为一个off,同时保存一些索引文件啊这边呢,其实就是我们前面对应的三种文件,那我们来以第一个来看一下话,Part提啊,您来看一下的话,其实它里面的这个log里面呢,就对于每个log。
05:10
呃,Log log里面的话,那每一个里面其实就是按照这样的方式去存一个数据啊,这是这它的存的一个数据文件,然后呢,这是从索引这个呢,是从的一个时间的一些索引信息啊,那其实在他查找消息的时候呢。我们来看啊,其实它的一个点击那点那个点logo文件,我们就这儿就没有再展示,然后我们来看它的索引里面存的啥,他索引里面存的就是这条消息啊,存在这一个日志文件,就是同样相同文件名点log的这个文件里面的这个位置啊,就是这条消息写在这个位置,然后同时呢,那对于时间戳的,对于时TIME1这个文件呢,它说的就是在这个时间戳写了第这编号是这个这个的一个消息啊就是这样一个过程,所以在查找的时候呢,那首先它的查找过程就是啊,比如说以查找一个啊编号是查找查的一个消息来说的话,它首先会定位这条消息呢,存储在哪个哪一段里面,就是首先定位到段,那怎么定位段呢?其实就根据这个每一个每一个所有的消息段不是都会有它所有的文件命名都是。
06:23
按照那个office来去有序的嘛,所以在查的时候就二层查找,很快能定位到某一个段啊,定阅到这一个段之后呢,那首先去找这一个段里面存的索引信息啊,定位到这条消息保存在这个索引啊,就是根据这个偏移量去找,那这条消息写在这个索引文件的,索引文件的位置是在啊,写它对应的一个写在日志文件的位置是什么?就是根据他的opposite读取到它对应的position,那读取到之后呢,再去对应的一个数据文件里面去读取真值的数据,就是这样一个过程,所以这层层在这里面查找的时候,其实也是一个二分查找啊,不过这里值得注意的是,在卡夫卡内部,其实它的一个啊索引文件存储的时候啊,它其实是按照一个啊吸收索引去存储。
07:09
啊怎么理解呢?就是说它不是一从一这样一个一一个是它将,而是它每隔几条啊消息会从一个这样一个,从一个这样一个index啊这样的好处呢,就是能够更好的去能够减少这个啊索引的一个文件大小啊同时呢,也起到一够节约存储的一个啊,就是更加的能够节约这样一个空间的作用吧,啊同时呢,其实节约了这个空间,也就意味着同样的一个索引文件可以从更多的一个索引信息啊,也能够更好利用磁盘的一个啊磁盘阅读能力。啊,那这就是一个它的一个数据查找的过程,那我们接下来再来看,那对于卡夫卡而言,它的数据是否需要删除呢?啊,我们来想想这样一个问题啊,其实答案是肯定的,数据是需需要删除啊,因为如果数据不删除的话,那最终虽然你存在磁盘上面,但是最终的话,我们的磁盘也会随之也会啊空间一直会被占满,最终呢,造成一个服务的性能和性能和可用性的一个降低,那删除的时候就存在一个问题,那他怎么进行删除呢?啊,其实他在这个删除的过程中呢,主要是基于啊一些固定的原则吧,比如说啊他。
08:30
每个每个是有一个时间除的时候都是S这个作为一个去进行删除的,就是每删除一次都是删除一个段,所以它删除的时候呢,啊,可以基于每一个日志文件中记录最大的时间戳,就是最旧的数据做一个删除,那第二个呢,基于设置的一个设定就是足够我可以保存多少个段,然后呢,超过这个段的个数之后呢,将前面的数据做一个删除,这其实就是卡不卡里面数据清理的一个一部分逻辑。
09:04
啊,那接下来我们再来看啊,在卡不卡里面,那怎么样去啊,它的消费是怎么,消费模型是怎么样子的,其实借助我们前面的这张图来看啊,就是啊它支持呢,就是生产,生产完消息之后呢,下游呢可以啊从从队列里面去消费消息,那通常他在这边做的时候呢,就是啊有他自己的一个group消费者组,然后每一个消费者组里面又包含多个消费者啊这里面呢,其实就是多个帕听胜他的分他的一个啊消费者这边的一个。负载均衡呢,就是啊,一个帕提胜只能为一个消费者组里面的一个消费者去消费,但是呢,这边的一个消费者,他其实可以去消费多个帕丁胜的数据啊,主要就是保证啊,为了避免就是我们帕丁胜之间的一个相互之间多个多个啊,消费者如果消费同一个话,提升的话,就是为了防止出现这种啊资源相互竞争啊,降低降低性能的一个原因啊,同时他也遵循的就是。
10:11
啊,多个一条消息在多个组之间是广播的,同时在组,这同一个组内部呢,是单播的,就是同一个组内部一条消息只会被一个消费者消费啊,所以他在帕提式维度呢,是可以做到一个数据的一个顺序啊消费。啊,那其实介绍完卡夫卡的一个它的单实例环境下的一些内容之后,我们再来看那卡夫卡里面它的集群下面的一些内容。啊,在卡夫卡集群里面的话,我们其实重点关注以下四部四部分内容啊,第一部分内容的话就是卡夫卡的一个。数据的一个复制啊,那第二部分的话就是介绍卡夫卡集群啊,当发生某个某些节点发生故障之后,它的一个故障转移的一个过程,第三个的话就是它集群之间数据的一个一致性啊,第四部分呢,就是介绍它集群之间数据的一个分片。
11:06
啊,我们来看那卡普卡里面它简单的一个数据复制呢,大概是这样子,就是生产者生产一条消息之后呢,啊,这条消息会被啊集中,我们假设这条消息呢,它是录由到了帕提圣林啊帕提士衣上面,那帕提士一呢,它首先会交给这个leader去,这条消息呢,是由leader来去处负责去跟生产者啊交互的,那生产者呃拿到这条消息后呢,他接下来就会去啊分发给其他的两个,两个收到这条息之后呢,他们存下来,然后再响应给啊那这时候的话,其实啊接下来呢就就可以啊去响我们的一个生产者,那这个地方其实就会涉及到一个,那leader什么时候去响应我们的一个生产者的这一个啊时机啊,其实这边呢,就是卡卡里面它的一个核实ACK的一个时机啊,接下来呢,其实啊,我们先假设他已经ACK之后呢,那这条消息就达到了一个一致,接下来呢,他就会提。
12:07
交,那提交之后呢,消费啊,这条消息就可以被我们的一个消费者去啊,消费者去消费到了啊,这就是整个一个数据复制的一个常规的一个流程,那在这个过程中,我们来看一下啊,它的一个卡不卡的一个A的一个过程,就是这个AK,如果说它有几种取值,第一种的话,就是AK等于零啊这个等于零的呢,就是说啊,这些消息发给之后呢,啊,那就不需要就直接立即响应生产,可能这时候呢,拎DA都没有存下来啊。这是一种就是直接生产者直接直接发之后呢,那就响应啊,第二的话就是A等于一,那A等于一的话,就是它等待这个leader写成功之后呢,再响应生产者啊,这是AC等于一,AC等于负一或者等于二的时候呢,它表示的就是等待Li和isr这个集合里面的follow都写成功之后才响应这个生产者啊,在这种集这种情况下面的话,它的消息的一个可靠性是最高的啊,接下来呢,我们来看一下。
13:14
那在卡卡里面这三种取值下面的时候呢,其实他们的特点啊,AC等于零的时候,其实数据就是是一个异步复制和存储啊,这种情况下其实它的速度是最快的,吞吐量也是最高,但是呢,它的一个消息的可靠性是最差的,同时呢,它丢失数据的风险呢是最高啊。当A等于一的时候呢,是存储完之后就响应生产啊,这个时候呢,保保存有完的一个数据啊,同时它的速度快,量较高,但是呢,它的可靠性还是比较差啊,因为这种时候情况下也会有丢失数据的风险,因为如果Li还没有将这个消消息同步给其他的节点之后呢,那挂掉之后这条消息就会存在一个丢失,A等于负一的时候呢,其实就是和isr里面的啊,所以都同步成功啊,然后响应生产者啊,这种情况下的话,其实它因为同步的节点会比较多嘛,所以就会导致它的一个同步呢啊比前面两种比起来相对会较慢,但是呢,它的消息的一个可靠性更高,因为同一条数据在啊多个photo节点上面会有保留啊,这种情况下面,它丢失数据的风险最低啊,但是呢,极端情况下呢,这个isr列表为空的时候呢,其实也有概率会丢失这样一个数据啊,当然可以通过一些参数来进行设置。
14:36
适合优化。啊,接下来我们来看,那在正常流程里面啊如呃,大部分情况下是没有问题的,那如果说是在啊正常流程之外,我们来看,如果说当我们的节点发生故障之后,那卡夫卡是怎么处理的呢?啊,这里面我们首先来分两种情况来看。第一种的话就是啊,到卡夫卡里面这个。
15:03
某一个的一个leader节点挂掉之后,它的一个故障的一个情况,以及第二种就是啊,某一个它的一个photo挂掉之后的一个情况,我们先来看leader挂掉的情况啊,针对leader挂掉的这种情况,下面的话,其实他主要做两部两件事情,第一件的话就是首先从这个I首先选择一位啊,这个选择一位,呃,它有可以。它有不同的策略啊,就是最呃一种呢,就是从is里面选,另外一种呢,就是从OS里面去选啊,那我们来看is里面选的过程中呢,其实它只要去它的选择标准呢,就是去选出数据最新或者是最完整的这个节点,因为本质上来保证这个数据是啊,丢失的风险是最少的。啊,选出这样一个新的leader之后呢,那他为了保证集群这节点之间数据的一个一致性,同时对外消费的一个一致性的话,它本身他也要需要做第二部分工作,那就是每个节点呢,都有一个自己的一个呃,Leo,以及呢,它定义的一个高水位,那其他在这个情况下,它需要将其他节点的日志呢,都截取到一个HW,就是高位这个位置,然后呢,再从去同步这个。
16:18
而节点挂上之后掉之后呢,其实就处理就简单多了,因为处理故障之后呢,那其实如果它在IR集合里面,那就需要将它从isr集合里面移掉啊,接下来的话啊,等待这个节点会呃重新启动的时候呢啊,再根据它的一个上次记录的高水位的位置呢,截取比这个高的数据,然后再从点同步啊之后的数据同步改上之后呢啊卡卡就会将它加入到一个is集合里面去啊这是它两种情况,那其实前面提到的I1和高水位这两个是什么含义呢?我们以右边这张图来啊来阐述。一个就是一个副本,其实就是一个,就是之定围内的话,它就会加入到一个isr里面啊,那L1是什么?就是每一个节点上面,它其实都有一个,它日志的一个啊,最最大的一个偏移量啊,就是它存储度最大偏移量,那这个呢,其实就称为一个L1,就是log n of,那每个消息维护的最新的一个偏移量啊,也就是最新的编号,那高水位又是什么呢?高水位其实是啊,它是在isr所有列表里面呢啊,这些所有在isr列表里面的节点的L1的最小啊,我们以这三个例子来为例的话,可以看到它的最小值其实就是六啊,这其实就是一个啊啊HW就是整个里面所的一。
17:56
那这边呢,其实就将啊通过这个高水位呢,其实就将日志划分出了两段,第一段的话就是我们所称的一个commit的,就是已经被啊IR同步到的所有的一个消息啊,那这些消息呢,是可以被消费者去消费的,那第二部分呢,就叫做一个message,其实这一部分消息呢,是没有被呃isr集合里面的所有节点都同步到的,所以这一部分消息呢,对于呃消费者而言,其实是不可见的。
18:25
啊,其实这个地方其实就很似于我们卡面的是卡的一就是那个。这些。啊,接下来我们再来看那卡不卡里面他们是怎么,他是怎么保证数据的一个精准消费的呢?啊这个地方其实其实怎么来理解这个啊,就是一个消息呢,其实有几种方式我们来看啊,当这个A等于零,前面提到A等于零的时候呢,它其实能保证生产呢,最多是生产的这一条消息就是最多发送一次啊,这是最多发送一次,而当A等于这个负一的时候呢,其实它是啊,可以保证生产者发的消息呢,不会最大可能都不会丢,但是呢,这也就意味着他呢是生产者可能会。
19:17
至少会发,最少会发送一次消息,那在这个情况下面的话。我们要达到消费者金属消费一次的话,那也就意味着啊,在最多最最少一次的这种情况下面,可能会存在消费者呢,重复消费一条消息的情况,所以在卡夫卡里面,它其实解决这个金属消费一次的时候呢,它是采用啊,就是最少一次加上一个密等性啊,这个密等性呢,是在0.11之后引入的一个特性啊,就实现了一个。精准消费,它的精消费呢,其实主要就是就是通过呢,就是啊每给每一个produce呢,分配了一个啊ID,然后呢,往同一个往同一个里面去发送消息的时候,都会在这样一个,然后呢内部呢会对啊这个D以及PID和这个C呢,做一个VD进行缓存,然后呢做一个去重,其实本质上就是将这些消息如果已经被啊如果已经被消费消费过的话,其实就不会再推理下游的消费者了啊就是这样一个逻辑,其实他内部保保证了消费的一消息的一个一致性啊,就是消息的一个金属消费。
20:33
啊,最后呢,我们来看一下那卡罗卡它是怎么提升它的一个通吐量和并发度的,其实它里面呢,是数据按照分片来去分的,就是对外层其实暴露的是一个topic,但是它一个topic可以它会分成多个,每一个呢又会有他自己的副本,所以呢,它整体的一个结构就是按照这边的就是。这样一个特点啊,那在这样的一个特点里面的话,其实就存在着我们前面提到的生产者的一个啊,负载均衡就是一条消息呢,我生产生产的一条消息最终其实是只会发给一个队列,那到底发给哪个队列呢?就是他这边就会有一些分区的策略啊。
21:14
核心原则就是一条消息发给一个马提神,那主要的分分区策略呢,有龙熊分区以及随机以及或者是按照K进行哈希啊,还有呢,业务方也可以根据自定义方式来去做啊,第二种的话就是那消消费者的一个分局策略,因为这因为内部分成的多个帕提式之后,那外部的时候来访问的时候呢,啊,外部又是一个一个生产一个消费者所里面会对于多个消费者,那在这种情况下,它是一个多对多的一种啊多对多的关系,那怎么来去进行一个消费者分居的一个处理呢?其实我们来我们就来看一下这一块啊,我们来看一下,那其实它的分区呢,就是有龙熊啊分区,以及按照睿置范围就是平均的这种分区吧,啊,其实就这两种,本质上就是啊,主要就是一个原则是一个分区只能被一个消费者组中的一个消费者去消费,但是一个消费者呢。
22:14
他他可以消费多个爬梯上的数据。我们再来对啊,前面卡不卡的内容呢,做一个总结,其实卡不卡里面呢,其实我们前面介绍的从单机的它的存储模型,它的数据的分片啊,以及它内部的一个数据的检索查询和清理啊,做了介绍啊,然后呢,在集群环境,我们又介绍它的数据的一个复制,以及它数据的复制过程中啊,如果节点挂掉之后故障的一个转移,以及最后呢,介绍了它的。啊,其他的一些像高水位以及L1等等概念,那最后我们来再来提一下,为什么卡夫卡这么快呢?其实卡夫卡快啊,其实主要有几个维度吧,第一个啊,从这个吉凶层面来看的话,它的数据呢是分片分区的,所以呢它其实是其实是提高了一个啊必行度,所以呢它的性能比较高。
23:11
但同时呢,它在单机情况下也很快啊,那单机情况下它的快呢,主要是啊,一方面呢,它是数据写磁盘写性能很高,那第二个的话就是在在当我们的消费者去呃消息队列拉取数据的时候,如果这条消息已经落到磁盘上面的时候呢,它其实内部在啊做了一个数据的里拷贝,就是减少了上下文开销和啊上下文切外和拷贝的一个次数。然后直接从。主要采用的就是file以及这样的一些拷的方法啊的一些性能的开,那第四的话就是它的一个批处理的一些能力啊,它在接口层面跟实现层面呢,就是对外的时候呢,可以支持一个啊将多条消息呢合并在一起,然后发送合并在一起进行一个网络的传输,同时呢,这其实提高了一个减少了网络的开销,提升了一个IO的性能。
24:11
啊,接下来这边呢,是一些整个的一些资料。
我来说两句