消息队列中的8个连环炮

消息队列7连击

(1)第一问,你知道不知道你们系统里为什么要用消息队列这个东西?

答:
①首先是解耦作用
我们先看如果没有用mq会是什么情况呢?
在这里插入图片描述
接下来,我们需要用mq来改进上面的问题
在这里插入图片描述
②然后mq还有异步化的作用(减少各系统之间调用的时间消耗)
下面先来看一下如果没有mq会是什么情况?
在这里插入图片描述
很明显A系统串行调用其他各个系统来执行sql语句,很费时间,这样的话,用户体验就不好
用mq来解决这个问题吧
在这里插入图片描述
③mq还可以削峰
如果我们不用mq的话见下图
在这里插入图片描述
这样的话,mysql服务器很容易瘫痪宕机,
所以我们如果用mq的话,见下图
在这里插入图片描述
以上三点说的都是mq的优点,那么有优点肯定就有缺点啊,
缺点:第一点,万一mq宕机怎么办
第二点,就是数据一致性问题可能会出现

一致性问题:A系统处理完了直接返回成功了,人人都以为你这个请求就成功了;但是问题是,要是BCD三个系统那里,BD两个系统写库成功了,结果C系统写库失败了,咋整?你这数据就不一致了。见下图
在这里插入图片描述

(2)第二问,kafka、activemq、rabbitmq、rocketmq都有什么优点和缺点啊?

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
对四种mq的总结如下:
综上所述,各种对比之后,我个人倾向于是:

一般的业务系统要引入MQ,最早大家都用ActiveMQ,但是现在确实大家用的不多了,没经过大规模吞吐量场景的验证,社区也不是很活跃,所以大家还是算了吧,我个人不推荐用这个了;

后来大家开始用RabbitMQ,但是确实erlang语言阻止了大量的java工程师去深入研究和掌控他,对公司而言,几乎处于不可控的状态,但是确实人是开源的,比较稳定的支持,活跃度也高;

不过现在确实越来越多的公司,会去用RocketMQ,确实很不错,但是我提醒一下自己想好社区万一突然黄掉的风险,对自己公司技术实力有绝对自信的,我推荐用RocketMQ,否则回去老老实实用RabbitMQ吧,人是活跃开源社区,绝对不会黄

所以中小型公司,技术实力较为一般,技术挑战不是特别高,用RabbitMQ是不错的选择;大型公司,基础架构研发实力较强,用RocketMQ是很好的选择

如果是大数据领域的实时计算、日志采集等场景,用Kafka是业内标准的,绝对没问题,社区活跃度很高,绝对不会黄,何况几乎是全世界这个领域的事实性规范

(3).第三问,如何保证消息队列的高可用啊?

(1)RabbitMQ的高可用性
RabbitMQ是比较有代表性的,因为是基于主从做高可用性的,我们就以它为例子讲解第一种MQ的高可用性怎么实现。
rabbitmq有三种模式:单机模式,普通集群模式,镜像集群模式
单机模式:就是demo级别的,一般就是你本地启动了玩玩儿的,没人生产用单机模式
普通集群模式:意思就是在多台机器上启动多个rabbitmq实例,每个机器启动一个。但是你创建的queue,只会放在一个rabbtimq实例上,但是每个实例都同步queue的元数据。完了你消费的时候,实际上如果连接到了另外一个实例,那么那个实例会从queue所在实例上拉取数据过来。
这种方式确实很麻烦,也不怎么好,没做到所谓的分布式,就是个普通集群。因为这导致你要么消费者每次随机连接一个实例然后拉取数据,要么固定连接那个queue所在实例消费数据,前者有数据拉取的开销,后者导致单实例性能瓶颈。
而且如果那个放queue的实例宕机了,会导致接下来其他实例就无法从那个实例拉取,如果你开启了消息持久化,让rabbitmq落地存储消息的话,消息不一定会丢,得等这个实例恢复了,然后才可以继续从这个queue拉取数据。
镜像集群模式:这种模式,才是所谓的rabbitmq的高可用模式,跟普通集群模式不一样的是,你创建的queue,无论元数据还是queue里的消息都会存在于多个实例上,然后每次你写消息到queue的时候,都会自动把消息到多个实例的queue里进行消息同步。
这样的话,好处在于,你任何一个机器宕机了,没事儿,别的机器都可以用。坏处在于,第一,这个性能开销也太大了吧,消息同步所有机器,导致网络带宽压力和消耗很重!第二,这么玩儿,就没有扩展性可言了,如果某个queue负载很重,你加机器,新增的机器也包含了这个queue的所有数据,并没有办法线性扩展你的queue
那么怎么开启这个镜像集群模式呢?我这里简单说一下,避免面试人家问你你不知道,其实很简单rabbitmq有很好的管理控制台,就是在后台新增一个策略,这个策略是镜像集群模式的策略,指定的时候可以要求数据同步到所有节点的,也可以要求就同步到指定数量的节点,然后你再次创建queue的时候,应用这个策略,就会自动将数据同步到其他的节点上去了。
下面是普通集群模式的高可用实现,但是还是有缺陷
在这里插入图片描述
镜像集群模式如下:(rabbitmq不是分布式的:(什么意思呢?就是说不可能一个完整的信息包分摊存储在下图中的3个机器上,每个机器都存一部分))
在这里插入图片描述
(2)kafka的高可用性 kafka一个最基本的架构认识:多个broker组成,每个broker是一个节点;你创建一个topic,这个topic可以划分为多个partition,每个partition可以存在于不同的broker上,每个partition就放一部分数据。

这就是天然的分布式消息队列,就是说一个topic的数据,是分散放在多个机器上的,每个机器就放一部分数据。
在这里插入图片描述
上图重点:每台机器+机器上的broker进程,就可以认为是kafaka集群中的一个节点(上图左下角)

(4)第四问,如何保证消息不被重复消费啊(如何保证消息消费时的幂等性)?

首先看重复消费出现的情况
在这里插入图片描述
给你举个例子吧。假设你有个系统,消费一条往数据库里插入一条,要是你一个消息重复两次,你不就插入了两条,这数据不就错了?但是你要是消费到第二次的时候,自己判断一下已经消费过了,直接扔了,不就保留了一条数据?
幂等性的定义:一条数据重复出现两次,数据库里就只有一条数据,这就保证了系统的幂等性
针对幂等性问题其实还是得结合业务来思考,我这里给几个思路
①比如你拿个数据要写库,你先根据主键查一下,如果这数据都有了,你就别插入了,update一下好吧
②比如你是写redis,那没问题了,反正每次都是set,天然幂等性
③比如你不是上面两个场景,那做的稍微复杂一点,你需要让生产者发送每条数据的时候,里面加一个全局唯一的id,类似订单id之类的东西,然后你这里消费到了之后,先根据这个id去比如redis里查一下,之前消费过吗?如果没有消费过,你就处理,然后这个id写redis。如果消费过了,那你就别处理了,保证别重复处理相同的消息即可。
④还有比如基于数据库的唯一键来保证重复数据不会重复插入多条,我们之前线上系统就有这个问题,就是拿到数据的时候,每次重启可能会有重复,因为kafka消费者还没来得及提交offset,重复数据拿到了以后我们插入的时候,因为有唯一键约束了,所以重复数据只会插入报错,不会导致数据库中出现脏数据

(5)第五问,如何保证消息的可靠性传输(如何处理消息丢失的问题)?

先说rabbitmq丢数据的情况吧:
解析图:
在这里插入图片描述
1)第一种可能:生产者弄丢了数据
在这里插入图片描述
在这里插入图片描述
2)第二种可能:rabbitmq弄丢了数据
在这里插入图片描述
3)第三种可能:消费端弄丢了数据
在这里插入图片描述
接下来再说一下kafka丢数据的情况(除了上述可能的问题之外,还有一种可能的问题,是什么呢?那就是当生产者把消息发送给Kafka主节点,然后主节点就给生产者说“我收到消息了”,生产者也以为没问题了,但是这个时候主节点还没有来得及同步消息到从节点,这个时候如果主节点一宕机,那么就会产生数据丢失)
在这里插入图片描述
1)第一种可能:消费端弄丢了数据
在这里插入图片描述
2)第二种可能:kafka弄丢了数据
在这里插入图片描述
3)生产者会不会弄丢数据
在这里插入图片描述

(6)第六问,如何保证消息的顺序性?

先说rabbitmq中的顺序问题:
在这里插入图片描述
解决之道:rabbitmq:拆分多个queue,每个queue一个consumer,就是多一些queue而已,确实是麻烦点;或者就一个queue但是对应一个consumer,然后这个consumer内部用内存队列做排队,然后分发给底层不同的worker来处理
在这里插入图片描述
再说一下Kafka中消息的顺序问题:
在这里插入图片描述
解决之道:
在这里插入图片描述

(7)第七问,如何解决消息队列的延时以及过期失效问题?消息队列满了以后该怎么处理?有几百万消息持续积压几小时,说说怎么解决?

问题解析:
在这里插入图片描述
在这里插入图片描述
我们来看问题是如何解答的:
在这里插入图片描述
上图的思路解析:
一般这个时候,只能操作临时紧急扩容了,具体操作步骤和思路如下:
1)先修复consumer的问题,确保其恢复消费速度,然后将现有cnosumer都停掉
2)新建一个topic,partition是原来的10倍,临时建立好原先10倍或者20倍的queue数量
3)然后写一个临时的分发数据的consumer程序,这个程序部署上去消费积压的数据,消费之后不做耗时的处理,直接均匀轮询写入临时建立好的10倍数量的queue
4)接着临时征用10倍的机器来部署consumer,每一批consumer消费一个临时queue的数据
5)这种做法相当于是临时将queue资源和consumer资源扩大10倍,以正常的10倍速度来消费数据
6)等快速消费完积压数据之后,得恢复原先部署架构,重新用原先的consumer机器来消费消息
但是如果我们使用的是rabbitmq呢?(注意哦,rabbitmq可以设置过期时间)
在这里插入图片描述
如果是第三种情况呢(就是说mq快满了,来不及紧急扩容了(“紧急扩容”的含义见上文找黑体字))
在这里插入图片描述

(8)第八问,如果让你写一个消息队列,该如何进行架构设计啊?说一下你的思路

在这里插入图片描述
题目剖析:
在这里插入图片描述
在这里插入图片描述

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Java全栈研发大联盟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值