消息队列的作用,高可用,顺序消费的那些事(一)

文章目录:

  1. 消息队列如何选型,各自的优缺点?
  2. 如何保证其可用性
  3. 如何保证消息不丢失?
  4. 如何保证消息的消费不重复(EOS语义)?
  5. 如何保证消息的消费的顺序性?
  6. 如何解决集群故障后大量数据积压?
一、消息队列的优缺点

我们常常听见一些大佬说学习一个东西不仅要知其然,还要知自其所以然。我们项目中常常用到消息队列,那么为什么我们需要使用消息队列,用了它对系统带来了什么好处了?解决了什么问题,还是是为了用而用,架构师设计的架构就是这样?对于这一系列疑问我们应该一探究竟,才能理解使用消息队列的好处。

消息队列的优点

1. 解耦
在一个简单的业务系统中,假设我们需要通过O系统的接口来调用其他子系统。如下图所示:
在这里插入图片描述
刚开始,O系统的接口中需要持有其他两个子系统的引用,当过一段时间时,突然来了需求,需要调用C系统,那么可能需要修改代码如下:

public void method(){
	A a=new A();
	B b=new B();
	C c=new C();
}

又过了一段时间,需要加入D系统,代码修改如下:

public void method(){
	A a=new A();
	B b=new B();
	C c=new C();
	D d=new D();
}

又过了一段时间,B系统不需要调用了,代码修改如下:

public void method(){
	A a=new A();
	C c=new C();
	D d=new D();
}

又过了一段时间,,,,,(此刻程序员心里mmp)。那么有没有一种设计能够不需要那么频繁的修改业务代码,降低代码之间的耦合度呢?

这时我们就用到了消息队列,它的第一个优点就是解耦。在引入消息队列之后,系统的整个架构如下:
在这里插入图片描述
从上图我们可以看到,业务代码之间不需要直接耦合,而是间接的通过消息队列来通信,这样一来就降低系统的耦合度,一旦需要加入新子系统,我们只需要让新的系统订阅消息队列即可,而O系统只需要将消息发送到MQ中即可,之前的问题完美解决。

2.异步
假设我们的一个系统需要执行SQL,查询数据库,那么其基本流程图如下:
在这里插入图片描述
按照上图的描述,执行一条请求需要耗时50+100+100=250ms。如果调用的系统增加,请求时延很容易达到秒级别,这对于一个高并发系统是绝对不允许的。这时如果我们引入消息队列呢?
在这里插入图片描述
在引入消息队列后,我们只需要将消息写入消息队列即可返回给用户,请求时长为50+50=100ms,相比之前降低了2.5倍。这里就体现了消息队列的异步特性。(虽然这个例子有点勉强,但是并不影响我们理解其异步的优点)

3.削峰
一个系统在某大促期间,大量的请求全部去请求业务系统,比如某一个时间段的QPS达到1万。假设这里有A,B两个子系统,每个处理5000个。这可能就达到了单个服务器性能的极限(假设普通服务器)。当QPS达到2万的时候,很可能系统会挂掉,那么如何来解决呢?(这里我们暂不考虑横向扩展的状况)。
在这里插入图片描述
这时不管并发量有多大,对于两个子系统,只要尽其所能去处理请求,不至于使得机器宕机,服务不可用,等到高峰期过去很快就能处理完所有的请求。这也体现了消息队列的另一个优点削峰

在了解了消息队列的一些优点之后,下面介绍几款比较常用的MQ,看看他们的各自优缺点是什么。

常用MQ的优缺点
特性ActiveMQRabbitMQRocketMQKafka
单机吞吐量万级,吞吐量比RocketMQ万级,吞吐量比RocketMQ和10万级,10万级 ,kafka最大的优点
.和Kafka要低了一个和Kafka要RocketMQ也是可以就是吞吐量高。
.一个数量级低了一个数量级支撑高吞吐的一种MQ用于实时计算,日志采集等场景
topic数量对吞吐量的影响topic可以达到几百,几千个的级别,吞吐量会有较小幅度的下降topic从几十个到几百个的时候,吞吐量会大幅度下降所以在同等机器下,
这是RocketMQ的一大优势,在同等机器下,可以支撑大量的topic同等机器下保证kafka的topic数量不要太多,如要支持高并发,可以增加机器资源
时效性ms微秒,延迟最低msms
可用性主从高可用架构主从高可用架构非常高,分布式架构非常高,分布式架构多副本机制,ISR机制
消息可靠性参数优化可以做到0丢失参数优化可以做到0丢失
功能支持性能完善基于erlang语言开发,性能好,延时低完善,性能好,分布式功能简单,常用语大数据场景
二、高可用性

对于一个系统,如何做到高可用很重要,尤其在分布式系统中。这里以RabbitMQ和Kafka为例,我们简单介绍其高可用。

RabbitMQ

对于RabbitMQ来说,主要有三种模式:单机模式,普通集群模式,镜像集群模式。

  1. 单机模式:这种模式很简单,就是一台机器处理所有消息。
  2. 普通集群模式:多台机器,当消费者拉取在一台机器中拉取数据的时候,如果不存在,那么就去其他机器中拉取,这种方式容易产生大量的网络传输,耗时比较严重。而且一台机器宕机,数据很可能会丢失。
  3. 镜像集群模式:多台机器,每台机器上的数据都一样,这种模式数据不会丢失,但是数据冗余,机器浪费比较严重,大数据场景下不适用。

Kafka

对于kafka来说,它主要通过多个broker,多副本机制以及ISR机制来保证其高可用性。其基本架构图如下:
在这里插入图片描述
对于kafka而言,每个topic会分为多个parition,每个partition会有多个副本,其中会选举出来一个leader,一旦一个副本所在的broker宕机,那么其他副本察觉到就会选举出新的leader,保证数据不丢失。

关于ISR机制的详细介绍可以参考之前的一篇文章【深入理解Kafka数据高并发写入、可靠性以及EOS语义

三、如何保证消息不丢失

对于一个消息队列,如何保证其处理的消息不丢失呢?首先我们就一个 系统来讨论一下其消息丢失的情况。
在这里插入图片描述
以上消息队列主要三个部分组成,生产者、消息队列,消费者。发生消息丢失的情况有以下三种:

  1. 在生产者端,发送消息给MQ,可能由于网络等原因丢失。
  2. 在MQ中,可能生产者刚发送来消息,没来得及持久化发生宕机,内存中的数据丢失。
  3. 在消费者端,拉取到MQ的消息之后,还没来得及处理消费者宕机。

针对以上三种情况,我们以kafka为例来看看其是怎样保证数据不丢失的。

Kafka中,product端通过ack机制来保证数据不丢失,其有一个重要的参数acks可以设置,保证数据不丢失,为了防止MQ中的数据在内存中丢失,我们来让其写入多个副本并且持久化来保证数据不丢失。

在消费端,kafka有自动提交机制,当一条消息被消费者接收到之后,就会发送自动提交消费者的offset给kafka,此时我们可以通过参数enable.auto.commit设置为false来取消自动提交,当消费者处理完消息之后我们手动提交。不过这里也有一个问题,就是当你处理完数据之后,还没来得及手动提交,服务挂了,下次就会重复消息,此时需要做幂等性处理(比如使用数据库的唯一键)。

在生产者写入broker中时,kafka来了防止在leader中数据还没来得及同步给follower就宕机导致数据丢失,我们可以通过参数replication.factor设置多副本,必须设置为大于1的值,还需要在kafka服务端通过参数min.insync.replicas保证ISR机制,即保证至少有一个follower与leader同步了数据才认为是发送成功。

好了,时间比较晚了,今天就介绍到这里,后面的文章中会继续今天遗留的话题继续讲解,欢迎关注,也欢迎批评指正。

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值