从软件架构设计角度理解Kafka

发布于:2024-10-13 ⋅ 阅读:(66) ⋅ 点赞:(0)

网上对于消息中间件的介绍文章比较多,这里我们不再赘述,我们换个思路来理解消息中间件,从软件开发架构的角度来看下消息中间件是如何诞生和演进的。

一、概述

在这里插入图片描述
上图中P代表 Provider,C代表Consumer,下同。P和C是一个典型的生产消费者模式,也可以理解为客户和服务端。如果P生产效率为200qps(200/秒),而C的消费效率只有100qps,长此以往必将造成数据的积压,积压到一定程序应用就有可能崩溃了。

解决方案也先简单,架构方案的万能公式,通过中间层解决(当然了也可以再添加一个C形成一个消费集群,但这里我们暂时不讨论这种方案),如果加一层不行就再加一层。当然了如果能一层解决的最好不要再二层是不,这次的中间层就是消息中间件:Kafka。
在这里插入图片描述

二、消息中间件的由来

紧接上图描述,上面这种性能不对等的问题出现的一定会比kafka要早,那么当时是如何解决的呢?所以此处先忘掉kafka吧,让我们从头来看下kafka是如何沉淀出来的。
在这里插入图片描述
性能不对等,可以选择在C端加入一个中间管道-队列(Queue),即数据(消息Msg)先到达C端的队列中先缓冲一下,然后再传给消息程序正式处理(此处的数据在下文中就用消息来代替),这样就解决了Msg积压的问题也能保证所有的Msg全能被C消费。

看似性能不对等的问题解决了,但引入了另一个问题,就是Queue和C同属于同一个进程,如果C崩溃了话,未来得及消息的消息就全部丢失了,如下图所示:
在这里插入图片描述

三、消息中间件的设计演进

1、 Msg丢失问题

如何解决呢,方案也很简单,把Queue独立到单独进程中就可以了:
在这里插入图片描述
非常好,没啥问题了,消息不对等,数据丢失问题全解决了。回头看下初具消息中间件的样子了,但有一个问题就是在分布式生产环境下,上面的设计对于高性能、高可用、高扩展是一点没有提呀,如果Queue进程突然崩了,那这设计也真够糊弄人的。所以接下来还要考虑可用和稳定的问题

2、 高性能解决方案

这个问题很好理解呀,原来Queue的两端各是一个P和C,那么多增加几个就行了。
在这里插入图片描述
现在再看下,Queue现在可以同时连接多个P和C了,只要假设Queue足够NB,那么这个系统理论上就很无敌了,不过呢假设就是假设,先不说Queue性能有多好,就是无限的增加P之间的资源争抢也够Queue喝一壶的了,本来P1就要发1条消息,好吧还要等P2的10000条发完才能发,哭死了。如下图所示,好吗,白设计一圈了又回到了最原始的状态的。
在这里插入图片描述
分析上图,不就是Queue被争抢吗,那么多增加几个Queue不就行了,但这里的增加不是增加多个节点,而是把P1和P2发送的消息分离开,因为多增加节点还是解决不了问题,所以就有了下面的设计:

Topic设计

在这里插入图片描述
好吧,这样一区分,P1和P2的消息就分离开了,相互之间不再相互影响了,这里有了消息中间件的另一个概念:Topic:用于给不同类型消息定义一个标签。同样的P这边处理了,C端也存在资源争抢的问题呀,如下图:
在这里插入图片描述

Partition 设计

虽然P端的消息通过Topic隔离开了,但如果某个Topic消息过多,还是会产生同样的问题,现在上述的隔离方案又不能用了,怎么办呢?没啥好办法,还得隔离:
在这里插入图片描述
单队列再拆分吧,数据多了就分开放置,即采用Partition,这里就有了另一个概念。非常好,数据存储问题解决了。然后让C与Partition对应:
在这里插入图片描述
这样C也不会争抢资源了。至此,可以解决了大部分性能问题,但还是存在问题,即某个Patition中的消息过多,还是会存在C端性能问题

Consumer Group设计

既然有性能问题,那么就多加几个吧。
在这里插入图片描述
针对每个Patition对应一个消费组,每个组会从指定的队列位置消费消息,指定的位置在消息中间件中称为offset。

至此,好像性能问题没啥了,通过各种护展和分组解决的七七八八了,那么解决其它问题了哈。

3、高可用解决方案

上面我们对Queue的设计全是单机进行的,时间一长肯定会引发单点问题,这个是不可接受的。
在这里插入图片描述

Broker

解决吧,即然是单点,那就多加几个节点了。
在这里插入图片描述
如上图,我们把不同的Prtition放布到不同的节点上,这样可以减少一些单点问题。至少当机器A宕机了,只丢失了Partition1和Partition2的数据,还保留了一部分。没办法还得解决呀:

Replicas

增加副本吧,给机器A和B分别增加副本,使其数据保持一致,这样当机器A坏了,机器C顶上就行了,如果机器A和C同时坏了呢?那就增加了机器D,这样1主2副本同时坏的可能性不大了吧。
在这里插入图片描述
那么问题又来了,当机器A坏了,机器C咋顶上,谁来切换?总不能每次出问题了穿衣下地、打车去公司切吧,真要这样黄花菜都冻冰了。估计程序员也会凉凉了。所以还是自动吧。

Leader和Follower

怎么个自动法呢,好办,我们把主和副本机器分别标注一下角色,主称为Leader, 从称为Followr,然后呢再指定一个管理者Manager,然后让Manager与L和F互相通信,实时监控,这时当Leaer坏了,Manager就指定一个Follower为新的Leader,这样就成了一个自动切换程序了,程序员们也可以晚点凉凉了。
在这里插入图片描述
上面需要注意Leader和Follower不能位于同一个主机上呀,如果位于同一个机器上,那么Manager也无能为力了,所以要放在不一样的机器上。

我们已经做的很好了,但老天不做美,停机了,整个IDC机房都停电了。这回切也没用了,一锅端了
哎,还得解决呀。

manger 这种自动选举机制可集成zk这样的软件来处理。

4、 高扩展解决方案

如上,如果停机这东西无法处理,那么扯啥呢。解决吧,不就是丢数据吗,kafka数据在运行时数据是存放在内存中的。
在这里插入图片描述

那么存磁盘吧。
在这里插入图片描述
不错,当时存磁盘,来电了后重启服务从磁盘重新加载就行了。至于能不能全部恢复,那么就不再处理了吧(实际上可以做到0数据丢失)。到这差不多了。
可是,但可以是磁盘毕竟空间有限,你这成天往里存一会就爆了,内存是同样的道理

过期策略

没用的数据就删除了吧。
在这里插入图片描述
定几个超时策略吧,FIFO还是FILO自己按场景选择吧。

EN,差不多了,基本可用了吧。

四、 小结

一套组合拳下来,一个简单的队列,就完成了现在的MQ消息中间件了。起个名吧就中Kafka。
在这里插入图片描述

您学废了吗?