这是我参与「第五届青训营 」伴学笔记创作活动的第 15 天
重启
举个例子来说,如果我们对一个机器进行重启首先,我们会关闭一个Broker,此时如果该Broker上存在副本的Leader,那么该副本将发生leader切换,切换到其他节点上面并且在ISR中的Folower副]本,可以看到图中是切换到了第二个Broker上面而此时,因为数据在不断的写入,对于刚刚关闭重启的Broker来说,和新Leader之间一定会存在数据的滞后,此时这个Broker会追赶数据,重新加入到ISR当中。
当数据追赶完成之后,我们需要回切leader,这一步叫做prefer leader,这一步的目的是为了避免,在一个集群长期运行后,所有的leader都分布在少数节点上,导致数据的不均衡通过上面的一个流程分析,我们可以发现对于一个Broker的重启来说,需要进行数据复制,所以时间成本会比较大,比如一个节点重启需要10分钟,一个集群有1000个节点,如果该集群需要重启升级,则需要10000分钟,那差不多就是一个星期,这样的时间成本是非常大的。
有同学可能会说,老师可以不可以并发多台重启呀,问的好,不可以。为什么呢,在一个两副本的集群中,重启了两台机器,对某一分片来讲,可能两个分片都在这台机器上面,则会导致该集群处于不可用的状态。这是更不能接受的。
负载不均衡
这个场景当中,同一个Topic有4个分片,两副本,可以看到,对于分片1来说,数据量是明显比其他分片要大的,当我们机器IO达到瓶颈的时候,可能就需要把第一台Broker上面的Partition3迁移到其他负载小的Broker上面,接着往下看
但我们的数据复制又会引起Broker1的IO升高,所以问题就变成了,我为了去解决IO升高,但解决问题的过程又会带来更高的IO,所以就需要权衡IO设计出一个极其复杂的负载均衡策略
Kafka存在的问题
- 运维成本高
- 对于负载不均衡的场景,解决方案复杂
- 没有自己的缓存,完全依赖 Page Cache
- Controller 和 Coordinator和Broker 在同一进程中,大量 IO会造成其性能下降
BMQ
兼容 Kafka 协议,存算分离,云原生消息队列
BMQ架构图
Producer -> Consumer -> Proxy -> Broker-> HDFS -> Controller -> Coordinator -> Meta
着重强调一下Proxy 和Broker无状态,为下面运维比较做铺垫口这里简单个绍一下存算分离,适配Kafka协议,为什么不选择PuIsar的原因
BMQ文件结构
对于Kafka分片数据的写入,是通过先在Leader上面写好文件,然后同步到Follower上,所以对于同一个副本的所有Segment都在同一台机器上面。就会存在之前我们所说到的单分片过大导致负载不均衡的问题,但在BMQQ集群中,因为对于单个副本来讲,是随机分配到不同的节点上面的,因此不会存在Kafka的负载不均问题
Broker-Partition 状态机
其实对于写入的逻辑来说,我们还有一个状态机的机制,用来保证不会出现同一个分片在两个Broker上同时启动的情况,另外也能够保证一个分片的正常远行,首先,Controler做好分片的分配之后,如果在该Broker分配到了Broker,首先会start这个分片,然后进入Recover状态,这个状态主要有两个目的获取分片写入权利,也就是说,对于hdfs来讲,只会允许我一个分片进行写入,只有拿到这个权利的分片我才能写入,第二个目的是如果上次分片是一场中断的,没有进行save checkpoint,这里会重新进行一次save checkpoint,然后就进入了正常的写流程状态,创建文件,写入数据,到一定大小之后又开始建立新的文件进行写入。
Broker-写文件流程
数据校验: CRC,参数是否合法,校验完成后,会把数据放入Buffer中 通过一个异步的Write Thread线程将数据最终写入到底层的存储系统当中 这里有一个地方需要注意一下,就是对于业务的写入来说,可以配置返回方式,可以在写完缓存之后直接返回,另外我也可以数据真正写入存储系统后再返回,对于这两个来说前者损失了数据的可靠性,带来了吞吐性能的优势,因为只写入内存是比较快的,但如果在下一次hush前发生宕机了,这个时候数据就有可能丢失了,后者的话,因为数据已经写入了存系统,这个时候也不需要担心数据丢失,相应的来说吞吐就会小一些 我们再来看看Thread的具体逻援,首先会将Bufer中的数据取出来,调用底层写入逻援,在一定的时间周期上去flush,fush完成后开始建立Index,也就是offset和timestamp对于消息具体位置的映射关系 Index建立好以后,会save一次checkpoint,也就表示,checkpint后的数据是可以被消费的辣,我们想一下,如果没有checkpoint的情况下会发生什问题,如果flush完成之后宕机,index还没有建立,这个数据是不应该被消费的 最后当文件到达一定大小之后,需要建立一个新的segment文件来写入
Failover
我们之前说到了,建立一个新的文件,会机挑选与副本数量相当的数据节点进行写入,如果此时我们挑选节点中有一个出现了问题,导致不能正常写入了,我们应该怎么处理,是需要在这里等着这个节点恢复吗,当然不行,谁知道这个节点什么恢复,既然你不行,那就把你换了,可以重新找正第的节点创建新的文件进行写入,这样也就保证了我们写入的可用性
proxy
首先Consumer发送一个Fetch Request,然后会有一个Wait流程,那么他的左右是什么呢,想象一个Topic,如果一直没有数据写入,那么,此时consumer就会一直发送Fetch Request,如果Consumer数量过多,BMO的server端是扛不住这个请求的,因此,我们设置了一个等待机制,如果没有fetch到指定大小的数据,那么proxy会等待一定的时间,再返回给用户侧,这样也就降低了fetch请求的IO次教,经过我们的wait流程后,我们会到我们的Cache里面去找到是否有存在我们想要的数据,如果有直接返回,如果没有,再开始去存储系统当中寻找,首先会Open这个文件,然后通过Index找到数据所在的具体位置,从这个位置开始读取数据
BMQ高级特性
泳道,databus,mirror,Index,Parquet
RocketMQ
- RocketMQ 的基本概念(Queue,Tag)
- RocketMQ 的底层原理(架构模型、存储模型)
- RocketMQ 的高级特性(事务消息、重试和死信队列,延迟队列)
使用场景:例如,针对电商业务线,其业务涉及广泛,如注册、订单、库存、物流等,同时也会涉及许多业务峰值时刻,如秒杀活动、周年庆、定期特惠等