中间件-消息队列

消息队列基础知识

什么是消息队列

本处提到的消息队列是指各个服务以及系统组件/模块之间的通信,属于一种中间件 。参与消息传递的双方称为生产者消费者 ,生产者负责发送消息,消费者负责处理消息。

消息队列作用

  1. 通过异步处理,提高系统性能(减少响应所需时间)
  2. 削峰/限流
  3. 降低系统耦合性

消息队列如何降低耦合性

消息队列使用发布-订阅模式工作,消息发送者(生产者)发布消息,一个或多个消息接受者(消费者)订阅消息。 从上图可以看到消息发送者(生产者)和消息接受者(消费者)之间没有直接耦合,消息发送者将消息发送至分布式消息队列即结束对消息的处理,消息接受者从分布式消息队列获取该消息后进行后续处理,并不需要知道该消息从何而来。对新增业务,只要对该类消息感兴趣,即可订阅该消息,对原有系统和业务没有任何影响,从而实现网站业务的可扩展性设计。

消息队列带来的问题

  • 系统可用性下降
  • 系统复杂度提高
  • 一致性问题

JMS Java消息服务

JMS(JAVA Message Service)API是一个消息服务的标准或者说是规范,允许应用程序组件基于JavaEE平台创建、发送、接收和读取消息。

JMS的两种消息模型

  • 点到点(P2P)模型

    使用队列(Queue)作为消息通信载体;满足生产者与消费者模式,一条消息只能被一个消费者使用,未被消费的消息在队列中保留直到被消费或超时。

  • 发布/订阅(Pub/Sub)模型

    使用主题(Topic)作为消息通信载体,类似于广播模式;发布者发布一条消息,该消息通过主题传递给所有的订阅者。

RPC与消息队列区别

  • 用途:RPC是用于解决两个服务之间的远程通信问题,用于调用远程计算机上某个服务的方法;消息队列主要用来降低系统耦合性、实现任务异步、进行流量削峰。
  • 通信方式:RPC是双向直接网络通讯,消息队列是单向引入中间载体的网络通讯。
  • 架构:消息队列是需要把消息存储起来,RPC则没有相关需求。
  • 请求处理的时效性:通过RPC发出的调配用一般会被处理,放在消息队列中的消息不一定会被处理。

RabbitMQ

RabbitMQ 如何保证信息不丢失

  • 开启生产者确认机制,确保生产者的消息能到达队列
  • 开启持久化功能,确保消息未消费前在队列中不会丢失
  • 开启消费者确认机制为auto,由spring确认消息处理成功后完成ack
  • 开启消费者失败重试机制,多次失败后将消息投递到异常交换机,交由人工处理

RabbitMQ消息重复消费问题怎么解决

  1. 设置一个唯一的标识符,处理消息时,先到数据库查询一下,如果不存在就正常处理,如果存在就不用再消费
  2. 幂等方案:利用redis分布式锁、数据库的锁等

RabbitMQ中的死信交换机?(RabbitMQ延迟队列了解过吗?)

当一个消息在一个队列中变为死信后,可以被重新发送到另一个交换机中,这个交换机就是死信交换机。导致死信的几种原因有:

  • 消息被拒(Basic.Reject / Basic.Nack)且requeue = false
  • 消息TTL过期
  • 队列满了,无法再添加。

什么是延迟队列?RabbitMQ如何实现延迟队列?

延迟队列指的是存储对应的延迟消息,消息被发送以后,并不想让消费者立刻拿到消息,而是等待特定时间后,消费者才能拿到这个消息进行消费。

实现方式:

  1. 利用RabbitMQ的死信交换机和消息存活时间TTL来实现
  2. 安装死信插件(具体没用过)

RabbitMQ如果有100万消息堆积在MQ中,如何解决(消息堆积怎么解决)?

当生产者发送消息的速度超过了消费者处理消息的速度,就会导致队列中的消息堆积,直到存储消息达到上限。之后发送的消息就会变为死信,肯会被抛弃,这就是消息堆积。

解决消息堆积有三种思路

  • 增加更多消费者
  • 消费者使用线程池,多线程处理消息
  • 使用惰性队列,扩大堆积上线

惰性队列

  • 在声明队列的时候设置属性x-queue-mode为lazy,即惰性队列
  • 基于磁盘存储,消息上限高
  • 性能比较稳定,但基于磁盘存储,受限于磁盘IO,时效性会降低。

RabbitMQ的高可用机制

在生产环境中,使用集群来保证高可用性

普通集群

又称标准集群,具备以下特征:

  • 会在集群的各个节点减共享部分数据,包括:交换机、队列元信息。不包含队列中的信息。
  • 当访问集群某个节点时,如果队列不在该节点,会从数据所在节点传递到当前节点在返回
  • 队列所在节点宕机,队列中的消息就会消失

镜像集群

本质是主从模式,具备下面的特征

  • 交换机、队列、队列中的消息 会在各个mq的镜像节点之间同步备份
  • 创建队列的节点被称为该队列的主节点,备份到的其他节点叫做该队列的镜像节点
  • 一个队列的主节点可能是另一个队列的镜像节点
  • 所有操作都是主节点完成,然后同步给镜像节点
  • 主节点宕机后,镜像节点会替代成为新的主节点

仲裁队列

  • 与镜像队列一样,都是主从模式,支持主从数据同步
  • 使用简单,没有复杂配置,只需在声明队列的时候指定使用仲裁队列
  • 主从同步基于Raft协议,强一致性

Kafka

Kafka如何保证消息不丢失

生产者发送消息到Brocker丢失

  • 设置异步发送

消息在Brocker丢失

Kafka如何保证消费顺序性

kafka默认存储和消费信息,是不能保证顺序性的。因为一个topic数据可能存储在不同的分区中,每个分区都有一个按照顺序存储的偏移量。如果消费者关联了多个分区,不能保证顺序性。

但是通过把消息存储到一个分区下可以解决。方法有两种:1)发送消息时指定分区号。2)发送消息时,按照相同的业务设置相同的key。因为默认情况下,分区也是通过key的hashcode值来选择分区的。hash值如果一样的话,分区一定一样。

相关推荐
whaledown14 天前
Kafka 与 Java 消息队列入门:用订单场景理解核心机制
java·kafka·消息队列·springboot
阿昌喜欢吃黄桃14 天前
RocketMq事务消息原理
java·中间件·消息队列·rocketmq·mq
半夜修仙15 天前
延迟队列的介绍及常见问题
java·数据库·中间件·rabbitmq
手握风云-15 天前
一条消息的旅程:RabbitMQ 学习与实践(一)
中间件·rabbitmq
RH23121116 天前
2026.6.8Linux
java·数据库·中间件
理人综艺好会17 天前
双Token机制在实际项目中的应用与实践
中间件·token
番茄去哪了17 天前
神领物流面试题(一)
java·大数据·中间件
念何架构之路17 天前
消息中间件
中间件
都说名字长不会被发现17 天前
Spring Boot Starter 中间件账号密码加密方案设计与实现
java·spring boot·后端·中间件
瀚高PG实验室18 天前
java中间件无法连接数据库
java·数据库·中间件·瀚高数据库