消息队列内容

问题有哪些?

(1)消息队列为什么会出现?

(2)消息队列能用来干什么?

(3)使用消息队列存在的问题?

(4)如何解决重复消费的问题?

(5)如何解决消息的顺序消费问题?

(6)如何解决分布式事务的问题?

(7)如何解决消息堆积的问题?

1、什么是消息队列?

消息队列是一个存放消息的容器,消息队列是分布式系统中重要的组件之一,使用消息队列主要是为了通过异步处理提高系统性能流量削峰降低系统的耦合性

2、 为什么使用消息队列?

① 通过异步处理提高系统性能(减少响应所需时间)。
② 削峰/限流。
③ 降低系统耦合性。

3、使用消息队列存在的问题

系统可用性降低: 系统可用性在某种程度上降低,为什么这样说呢?在加入MQ之前,你不用考虑消息丢失或者说MQ挂掉等等的情况,但是,引入MQ之后你就需要去考虑了!(需要考虑消息是否丢失或挂掉)
系统复杂性提高: 加入MQ之后,你需要保证消息没有被重复消费、处理消息丢失的情况、保证消息传递的顺序性等等问题!(需要保证消息不被重复消费、丢失、传递的顺序前后一致等问题)
一致性问题: 我上面讲了消息队列可以实现异步,消息队列带来的异步确实可以提高系统响应速度。但是,万一消息的真正消费者并没有正确消费消息怎么办?这样就会导致数据不一致的情况了!(数据保存到MQ中,消息可能未被消费者正确消费,导致数据不一致)

4、JMS和AMQP

JMS(Java Message Service,java消息服务)是java的消息服务,JMS的客户端之间可以通过JMS服务进行异步的消息传输。它使分布式通信耦合度更低,消息服务更加可靠以及异步性。
ActiveMQ就是基于JMS规范实现的。

JMS两种消息模型:       ①点对点(P2P)模型            ②发布/订阅(Pub/Sub)模型

AMQP,一个提供统一消息服务的应用层标准 高级消息队列协议(二进制应用层协议),是应用层协议的一个开放标准,为面向消息的中间件设计,兼容JMSRabbitMQ就是基于AMQP协议实现的。

5、常见的消息队列对比

消息队列内容_第1张图片

 总结:
①ActiveMQ的 性能比较差 ,版本迭代很慢,不推荐使用。
②RabbitMQ在吞吐量方面虽然稍逊于Kafka和RocketMQ,但是由于它基于 erlang开发,所以 并发能力很强,性能极其好,延时很低,达到微秒级 。如果业务场景对并发量要求不是太高(十万级、百万级),那这四种消息队列中,RabbitMQ一定是你的首选。如果是大数据领域的 实时计算、日志采集等场景,用Kafka 。
③RocketMQ阿里出品,Java系开源项目,但接口这块不是按照标准JMS规范走的,有些系统要迁移需要修改大量代码。
④Kafka仅仅提供较少的核心功能,却可以实现 超高的吞吐量,ms级的延迟 ,极高的可用性以及可靠性,而且 分布式 可以任意扩展。同时kafka最好是支撑较少的topic数量即可,保证其超高吞吐量。kafka唯一的一点劣势是有可能消息重复消费,那么对数据准确性会造成极其轻微的影响,在大数据领域中以及日志采集中,这点轻微影响可以忽略这个特性,天然适合大数据实时计算以及日志收集。

RabbitMQ内容:

1、什么是死信队列?如何导致的?
DLX,全称为 Dead-Letter-Exchange,死信交换器,死信邮箱。当消息在一个队列中变成死信 (dead message) 之后,它能被重新发送到另一个交换器中,这个交换器就是DLX,绑定DLX的队列就称之为死信队列 。

导致死信的几种原因:
①消息被拒(Basic.Reject /Basic.Nack) 且 requeue = false。
②消息TTL过期。
③队列满了,无法再添加。

2、什么是延迟队列?RabbitMQ怎么实现延迟队列?
延迟队列 指的是存储对应的延迟消息,消息被发送以后,并不想让消费者立刻拿到消息,而是等待特定时间后,消费者才能拿到这个消息进行消费。(发送到队列后,消费者不能立马消费,得等待一定时间才能消费,该队列即为延迟队列)

RabbitMQ 自身没有延迟队列的,那么如何实现延迟队列?
①通过RabbitMQ本身队列的特性来实现,需要使用RabbitMQ的 死信交换机(Exchange)和消息的存活时间TTL(Time To Live) 。
②在RabbitMQ3.5.7及以上的版本提供了一个 插件(rabbitmq-delayed-message-exchange)来实现延迟队列功能 。同时,插件依赖Erlang/OPT 18.0及以上。
也就是说,AMQP协议以及RabbitMQ本身没有直接支持延迟队列的功能,但是可以通过TTL和DLX模拟出延迟队列的功能。

3、什么是优先级队列?

RabbitMQ自V3.5.0有优先级队列实现, 优先级高的队列会先被消费 。
可以通过x-max-priority参数来实现优先级队列。不过,当消费速度大于生产速度且Broker没有堆积的情况下,优先级显得没有意义。

4、如何保证RabbitMq的顺序性?

4.1、错乱场景

错乱场景1 :一个queue,有多个consumer去消费,这样就会造成顺序的错误,consumerMQ里面读取数据是有序的,但是每个consumer的执行时间是不固定的,无法保证先读到消息的consumer一定先完成操作,这样就会出现消息并没有按照顺序执行,造成数据顺序错误。

错乱场景2 :一个queue对应一个consumer,但是consumer里面进行了多线程消费,这样也会造成消息消费顺序错误。

4.2、解决方案

解决方案一

拆分成多个queue,每个queue一个consumer,就是多一些queue而已,确实是麻烦点;这样也会造成吞吐量下降,可以在消费者内部采用多线程的方式取消费。

消息队列内容_第2张图片

 

解决方案二

或者就一个queue但是对应一个consumer,然后这个consumer内部用内存队列做排队,然后分发给底层不同的worker来处理

消息队列内容_第3张图片

5、如何保证消息的可靠性?

(1)消息有效期:默认情况下,如果在发送消息时,不设置消息过期时间,那么消息时永不过期的,即使消息没有被消费掉,消息而会一直存储在队列中。

(2)TTL:消息存活时间,即消息的有效期,给消息设置 TTL让消息存活一定的时间,如果消息存活时间超过了 TTL并且还没有被消息,那么消息就会变成死信,添加到死信队列。

在RabbitMQ中,有两种方式给消息设置TTL:

  • 方式一:在声明队列时,可以给队列设置消息的有效期,这样所有进入该队列的消息都会有一个相同的有效期
  • 方式二:在发送消息时,设置消息的有效期,这样不同的消息就具有不同的有效期
  • 如果两个都设置了,以时间短的为准

当给消息设置有效期后,如果消息过期没有被消费就会被从队列中删除,进入到死信队列,但是这两种方式对应的删除时机有点差异:

  • 方式一:当为消息队列设置过期时间时,消息过期了就会被删除,因为消息进入 RabbitMQ后是存在一个消息队列中,队列的头部是最早要过期的消息,所以 RabbitMQ只需要一个定时任务,从头部开始扫描是否有过期消息,有的话就直接删除
  • 方式二:当消息过期后并不会立马被删除,而是当消息要投递给消费者的时候才会被删除,因为第二种方式,每条消息的过期时间都不一样,想要知道哪条消息过期,必须要遍历队列中的所有消息才能实现,当消息比较多时这样就比较耗费性能,因此对于第二种方式,当消息要投递给消费者的时候才去删除

(3)进入死信队列的几类情况

  • 消息被拒绝(Basic.Reject/Basic.Nack) ,并且设置requeue参数为false
  • 消息过期
  • 队列达到最大长度

(4)发布确认+消息回退 的机制  https://blog.csdn.net/XZB119211/article/details/127008216

6、如何保证RabbitMq的高可用性?

RabbitMQ是比较有代表性的,因为是 基于主从(非分布式) 做高可用性的,我们就以RabbitMQ为例子讲解第一种MQ的高可用性怎么实现。RabbitMQ 有 三种模式:单机模式、普通集群模式、镜像集群模式 。

  • 单机模式
  • 普通集群模式:多台机器上启动多个RabbitMQ实例,每个机器启动一个。
  • 镜像集群模式:即RabbitMQ的高可用模式。跟普通集群模式不一样的是,在镜像集群模式下,你创建的queue,无论元数据还是queue里的 消息都会存在于多个实例上 ,就是说,每个RabbitMQ节点都有这个queue的一个完整镜像,包含 queue 的全部数据的意思。
     

你可能感兴趣的:(MQ消息队列,分布式)