java学习——消息队列MQ

上一篇传送门:点我

目前只学习了RabbitMQ,后续学习了其他MQ后会继续补充。

MQ有了解过吗?说说什么是MQ?

MQ是Message Queue的缩写,也就是消息队列的意思。它是一种应用程序对应用程序的通信方法,使得应用程序能够通过读写出入队列的消息来进行通信,而无需使用专用的连接来链接它们。消息队列中间件是分布式系统中重要的组件,主要解决应用解耦,异步消息,流量削峰等问题,实现高性能,高可用,可伸缩和最终一致性架构。在消息队列中,有生产者消费者两个角色。生产者负责发送数据到消息队列,而消费者则从消息队列中取出数据进行处理。这种方式实现了生产者与消费者之间的解耦,使得它们可以独立地运行和扩展。

消息队列的优缺点有哪些?

优点:
1.应用解耦:消息队列允许生产者和消费者之间松耦合。生产者只需要将消息发送到队列,而不需要关心消费者何时或如何处理这些消息。
2.异步处理:消息队列允许异步处理消息,这意味着接收者可以在自己方便的时候处理消息,而不是立即响应。这可以提高系统的吞吐量和响应时间。
3.流量削峰:在高并发场景下,消息队列可以起到缓冲作用,平滑突发流量,保护后端系统免受冲击。

缺点:
1.可用性降低:如果消息队列服务成为单点故障,整个系统可能会受到影响。因此,需要实施高可用性和容错策略,一般解决方法是给MQ架集群。
2.复杂性提高:引入消息队列会增加系统的复杂性。因为需要配置和管理消息队列服务,同时还需要处理可能的消息丢失、重复或顺序错乱等问题。
3.一致性问题:在分布式系统中使用消息队列时,如果消息队列发生了消息的丢失与重复,则可能会遇到数据一致性的问题。

说说消息队列的应用场景

消息队列的应用场景主要分为以下三种:
1.异步处理:应用在实时性要求不高的一些场景,例如用户注册发送验证码、下单通知发送优惠券等。这些场景下,服务方只需要把协商好的消息发送到消息队列,剩下的由消费者的消息服务去处理,不需要等待消费者的返回结果就可以直接返回给客户端,返回给业务层面;
2.应用解耦:可以把一些相关的但是耦合度不高的一些系统关联起来,比如订单系统与优惠券积分系统有关联度,但是没有那么紧密,每个系统之间只需要把一些约定好的消息发送到MQ,另外的系统直接去消费就可以了,它可以允许各类系统间采用不同的一些框架和语言来实现,从而大大增加了整个系统的灵活度;
3.流量削峰:应用在大流量入口的一些短时间的业务,短时间内业务需求处理不完的一些服务,例如双十一秒杀、演唱会抢票等。为了权衡高可用把大量的一些并行任务发送给MQ。根据MQ的存储和分发功能平稳的去处理后续的一些业务,从而起到大流量缓冲的作用。

开发过程中有哪些MQ可以选择?如何技术选型?

目前市面上常见的消息队列中间件主要有RabbitMQ、ActiveMQ、RocketMQ、Kafka。这几种消息队列各有优缺点,具体如下:

在这里插入图片描述
由上可以看出,ActiveMQ相较于其它三种消息队列,可用性差,并且吞吐量、消息延迟、可靠性都一般,除了一些小型项目或是追求经济高效的特定需求,ActiveMQ不是消息队列的第一选择,所以现在ActiveMQ不是主流的消息队列了
而由于RabbitMQ是基于Erlang语言开发的,所以如果需要对现有消息队列去做进一步的开发,不推荐使用RabbitMQ(如果只是拿来做简单应用开发就没区别)。
从吞吐量来看,比较好的是RocketMQ和Kafka,其中最好的是Kafka(单机的并发吞吐能力能够达到百万量级),所以如果要追求极致的吞吐能力去处理一些海量数据传输的大数据业务的时候,Kafka会是更好的选择。
而吞吐量高也会带来一定的牺牲,RocketMQ和Kafka的消息延迟(毫秒级)相比RabbitMQ(微秒级)要久很多,如果要追求消息的低延迟就可以选择RabbitMQ。
从可靠性的角度来看,Kafka由于追求极致的并发吞吐量,所以消息可靠性一般,如果要考虑消息的高可靠性,可以选择RabbitMQ或RocketMQ。

说说RabbitMQ的基本架构设计

RabbitMQ的基本架构由以下几个部分组成:
1.生产者(Producer):生产者是消息的发送方,负责产生并发生消息到RabbitMQ。生产者通常将消息发生给交换机(Exchange),从而使其消费者没有强关联。
2.交换机(Exchange):交换机是消息的分发中心,负责将接收到的消息路由到一个或多个消息队列。它定义了消息的传递规则,可以根据规则将消息发送到一个或多个队列中。

  • 直连交换机(Direct Exchange):将消息路由到与消息中的路由键(Routing Key)完全匹配的队列;
  • 主题交换机(Topic Exchange):根据通配符匹配路由键(Routing Key),将消息路由到一个或多个队列;
  • 扇出交换机(Fanout Exchange):将消息广播到所有与交换机绑定的队列,忽略路由键;
  • 头部交换机(Headers Exchange):根据消息头中的属性进行匹配,将消息路由到与消息头匹配的队列。

3.队列(Queue):队列是消息的存储区,用于存储生产者发送的消息。消息最终会被消费者从队列中取出并处理。每个队列都有一个名称,并且可以绑定到一个或多个交换机。
4.消费者(Consumer):消费者是消息的接收方,负责从队列中获取消息并进行处理。消费者通过订阅队列来接收消息。
5.绑定(binding):绑定是交换机和队列之间的关联关系。生产者将消息发送到交换机,而队列通过绑定与交换机相连,从而接收消息。
6.虚拟主机(Virtual Host):虚拟主机是RabbitMQ的基本工作单元,每个虚拟主机都拥有自己独立的用户、权限、交换机、队列等资源,完全隔离于其他虚拟主机。
7.连接(Connection):连接是指生产者、消费者与RabbitMQ之间的网络连接。每个连接都可以包含多个信道(Channel),每个信道是一个独立的会话通道,可以进行独立的消息传递。
8.消息(Message):消息是生产者和消费者之间传递的数据单元。消息通常会包含消息体和可选的属性,如路由键等。

在这里插入图片描述

说说RabbitMQ的交换机类型

1.Direct Exchange(直连交换机)
此类型交换机通过RoutingKey路由键将交换机和队列进行绑定,消息被发送到exchange时,需要根据消息的RoutingKey来进行匹配,只将消息发送到完全匹配此RoutingKey的队列。
2.Fanout Exchange(扇出交换机)
此类型交换机会将消息分发给所有绑定了此交换机的队列,此时RoutingKey无效。在Fanout类型交换机下发送一条消息,无论RoutingKey是什么,所有队列均可收到消息。
3.Topic Exchange(主题交换机)
此类型交换机与Direct类似,也是需要通过RoutingKey路由键进行匹配分发,区别在于Topic可以进行模糊匹配,而Direct是完全匹配。
1.在Topic中,将RoutingKey通过“.”来划分为多个部分;
2.“*”:代表一个部分;
3.“#”:代表0个或多个部分(如果绑定的路由键为“#”时,则接受所有消息,因为路由键所有都匹配)
4.Header Exchange(头部交换机)
Headers Exchange匹配AMQP消息的header而不是路由键,此外headers交换机和direct交换机完全一致,但由于它的性能差,目前几乎用不到了。
在此类交换机中,消费方指定的headers中必须包含一个“x-match”的键。该键的值有两个:
1.x-match = all:表示所有的键值对都匹配才能接收到消息
2.x-match = any:表示只要有键值对匹配就能接受到消息

说说RabbitMQ的持久化机制

RabbitMQ的持久化是一个重要的功能,它确保了即使在RabbitMQ服务器意外关闭或重启的情况下,消息仍然能够得到保存和恢复。RabbitMQ的持久化包括三个方面:交换器的持久化、队列的持久化和消息的持久化
交换器的持久化是通过在声明交换器时指定Durability参数为durable实现的。如果交换器不设置持久化,那么在RabbitMQ服务重启之后,相关的交换器元数据会丢失,但消息不会丢失,只是不能将消息发送到这个交换器中。
队列的持久化也是通过在声明队列时指定Durability参数为durable实现的。如果队列不设置持久化,在RabbitMQ服务重启之后,相关队列的元数据和消息数据都会丢失。设置队列持久化可以确保队列本身的元数据不会因异常情况而丢失,但并不能保证内部所存储的消息不会丢失。为了确保消息不会丢失,需要将消息设置为持久化。
消息的持久化可以通过消息的投递模式来实现。将消息设置为持久化可以确保消息在RabbitMQ服务器意外关闭或重启后能够得到恢复。然而,将所有消息都设置为持久化会严重影响RabbitMQ服务器的性能,因为写入磁盘的速度比写入内存的速度慢得多。因此,在选择是否要将消息持久化时,需要在可靠性和吞吐量之间做一个权衡

如何保证RabbitMQ的消息可靠性传输(保证消息不丢失)?

在RabbitMQ的整个消息投递过程中,有以下三种情况会存在消息丢失的问题:

1.生产者把消息发送到RabbitMQ Server的过程中丢失;
2.RabbitMQ Server收到消息后,在持久化之前宕机导致数据丢失;
3.消费端收到消息后还未来得及处理便宕机,导致RabbitMQ Server认为这个消息已经签收,这个消息就无法重复投递,导致消息无法消费的问题。

所以只需要解决这三个角度的问题,就能保证消息的可靠传输。
从生产者发送消息到Server端的角度来说,RabbitMQ提供了一个Confirm的消息确认机制,也就是说生产者发送的消息到Server端后,如果消息处理成功,Server端会返回客户端一个ack的消息,那么客户端可以根据消息的处理结果来决定是否要对消息进行重新发送,从而确保消息一定要到达到RabbitMQ Server端上;
从Server端的角度来说,可以开启消息的持久化机制,也就是收到消息后,将消息持久化到磁盘里面,设置消息的持久化一般有两个步骤:首先在创建Queue的时候设置为持久化,然后在发送消息的时候,把消息投递模式设置为持久化投递。虽然设置了持久化消息,但是也有可能会出现问题,比如消息刷新到磁盘上之前,RabbitMQ的Server端就发生宕机,这还是会导致消息丢失。为了确保万无一失,需要结合Confirm消息确认机制来一起使用;
从消费者的角度来看,可以把消息的ack机制中的自动确认修改为手动确认(将auto_ack参数设置为false),也就是说消费端只有手动调用消息确认方法,才表示这个消息已经被签收,这种方式可能会造成消息的重复消费,所以还需要考虑到幂等性的设计。

RabbitMQ中如何保证消息不被重复消费?

保证消息不被重复消费,实际上就是解决消息消费端幂等问题 (幂等性,指的是一条指令,任意多次执行所产生的影响均与一次执行的影响相同)。所以只要消费端具备了幂等性,消息重复消费的问题就解决了。
实现消息幂等性可以采用以下两种方案:
1.使用数据库的唯一约束实现幂等,比如对于MQ中的消息,设置一个唯一的消息id,如果消费端多次消费,就会触发数据库的唯一约束异常,从而实现消息的幂等性。
2.使用redis中的setNX指令,在MQ中,为了避免MQ重复消费导致数据被多次修改,消费端可以在接收到消息时,把消息通过setNX写入到redis里面,这样一来一旦消息被消费过,就不会再次被消费。

RabbitMQ中如何解决消息堆积问题?

在RabbitMQ中,出现消息堆积问题的场景一般有以下几种:
1.消息被消费方拒绝,一般来说这种情况是出现在程序或是逻辑有问题的时候。
解决方法:通过添加死信队列或是日志记录的方式避免消息重新入队
2.消费者消费消息的速度慢,从而导致消息的堵塞堆积。
解决方法:通过优化程序代码或建立消费者集群的方式增加消费者的消费能力。
3.队列容量不够,也可能导致消息堆积。
解决方法:增加队列的容量,以容纳更多的待处理消息。

RabbitMQ如何保证消息的顺序消费?

我们说的保证顺序消费,说的是消费者消费信息的顺序。虽然Server端队列中的消息是顺序的,但是由于多个消费者并发消费消息,所以获取消息的速度不一样,从而可能会导致消息的消费顺序出现问题。
想要解决顺序消费的问题,通常的解决办法就是一个队列只有一个消费者,这样就可以一个个消息按顺序处理,但缺点就是并发能力下降,无法并发消费消息,这是个取舍的问题。
也可以在发送消息时使用一些标识符或分区键将消息分区,并确保具有相同标识符的消息被发送到同一个队列。然后,可以使用多个消费者,每个消费者处理一个特定的分区,从而保证了消息在特定分区内的顺序性。

RabbitMQ如何给消息设置过期时间?

在RabbitMQ中存在2种方法设置消息的过期时间。第一种方法是通过对队列进行设置,这种设置后,该队列中所有的消息都存在相同的过期时间;第二种方法是通过对消息本身进行设置,那么每条消息的过期时间都不一样。如果同时使用这两种方法,那么以过期时间较小的哪个数值为准。当消息达到过期时间还没有被消费,那么该消息就成为了一个死信消息
队列设置:在队列中声明的时候使用x-message-ttl参数,单位为 毫秒。
单个消息设置:设置消息属性的expiration参数的值,单位为 毫秒。

说说RabbitMQ的死信队列

当队列中的消息被拒绝、或者消息过期会变成死信,死信可以被重新发布到另一个交换机,这个交换机是死信交换机(DLX,Dead Letter Exchange),与DLX绑定的队列被称为死信队列
出现死信的原因一般有以下几点:1.消息被消费方拒绝(消费方使用channel.basicNack或channel.basicReject,并且此时requeue属性被设置为false);2.消息超出过期时间超时;3.消息总量超过了队列的最大长度

说说RabbitMQ的延迟队列

延迟队列存储的是延迟消息。延迟消息是指,当消息被发布出去后,并不立即投递给消费者,而是在指定时间之后投递。例如:在订单系统中,订单有30秒的付款时间,在订单超时之后再投递给消费者处理超时订单。
RabbitMQ没有直接支持延迟队列,可以通过死信队列来实现。在死信队列中,可以为普通交换机绑定多个消息队列,假设绑定过期时间为5分钟,10分钟和30分钟三个消息队列,然后为每个消息队列设置DLX,为每个DLX关联一个死信队列。
当消息过期后,消息会被转存到对应的死信队列中,然后投递给指定的消费者消费。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/817515.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java算法之时间复杂度和空间复杂度的概念和计算

1. 算法效率 如何去衡量一个算法的好坏? 通常我们从时间效率和空间效率两个方面去分析算法的好坏。时间效率即时间复杂度,空间效率被称为空间复杂度。时间复杂度主要是衡量一个算法的运行速度,而空间复杂度主要衡量一个算法所需要的额外空间…

有道词典网页版接口分析与爬虫研究

说明:仅供学习使用,请勿用于非法用途,若有侵权,请联系博主删除 作者:zhu6201976 一、目标站点 有道词典网页版:网易有道 二、目标接口 url:https://dict.youdao.com/jsonapi_s?doctypejson&…

Linux系统搭建FastDFS文件服务结合内网穿透实现公网访问本地文件

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

C++-基础

C语言介绍 C 是一种通用编程语言,具有高性能、灵活性和广泛的应用领域。它是在 1979 年由 Bjarne Stroustrup 开发的,最初被称为“C with Classes”,随后在 1983 年正式更名为 C。C 基于 C 语言,同时引入了面向对象编程&#xff0…

使用冒泡排序模拟实现qsort函数

目录 冒泡排序qsort函数的使用1.使用qsort函数排序整型数据2.使用qsort函数排序结构数据 冒泡排序模拟实现qsort函数今日题目1. 字符串旋转结果2.杨氏矩阵3.猜凶手4.杨辉三角 总结 冒泡排序 冒泡排序的核心思想是:两两相邻的元素进行比较 代码如下: //⽅法1 void bubble_so…

【Linux】线程的控制

目录 POSIX线程库 常用的POSIX线程库接口声明: 注意事项 创建一个进程 pthread_create函数 参数 返回值 使用示例 线程ID和进程地址空间布局 线程ID 进程地址空间布局 示例图 获取一个进程的线程ID 函数原型 返回值 使用示例 注意事项 线程终止 p…

设计模式系列:责任链模式

简介 责任链模式是一种行为型设计模式,它允许你将请求沿着处理者链进行发送。每个处理者都可以对请求进行处理,或者将其传递给链上的下一个处理者。责任链模式主要应用于面向对象编程中,特别是当系统中的对象需要根据其属性来决定如何处理请…

嘴尚绝美味健康:探索美食背后的健康密码

在快节奏的现代生活中,人们对美食的追求从未停止。然而,随着健康意识的提升,越来越多的人开始关注美食与健康的平衡。今天,我们就来一起探讨“嘴尚绝美味健康”这一话题,看看如何在享受美食的同时,保持身体…

JMeter入门教程 —— 事务!

简介: JMeter中事务的基本介绍 1.任务背景 JMeter中的事务是通过事务控制器实现的。,为了衡量服务器对某一个或一系列操作处理的响应时间,需要定义事务。下面我们详细介绍在JMeter中如何使用事务 2.任务目标 掌握基于JMeter性能测试脚本开…

speccpu2017安装与使用

国产化桌面下Speccpu2017安装与使用 1、 安装依赖库 安装speccpu2017前需要安装依赖包,通过终端命令对依赖包进行安装 sudo apt-get install gcc g gfortran (以上是已经安装好的) 注:若安装不上,需替换/etc/apt下的s…

Docker部署SpringBoot服务(Jar包映射部署)

介绍 项目在docker部署运行以后,每次需更新jar包时,都得重新制作镜像,再重新制作容器。流程及其繁琐,效率极低。 以下步骤是在不更新镜像和容器的前提下,直接更新jar完成项目更新的操作。 不更新镜像 1. 创建你存放…

几款高效在线文档编辑器推荐,编辑文档更轻松

在数字化时代,文档编辑工作变得越来越重要。无论是工作报告、学习笔记还是创意文稿,一个优秀的在线文档编辑器都能让你的工作事半功倍。现在市面上也有很多优秀的在线文档编辑器,比如WPS Office、腾讯文档、 Microsoft Word Online。今天&…

openGauss_5.0.1 企业版安装及问题记录(CentOS系统):主备模式服务器安装

目录 📚第一章 官方地址📗安装包下载地址📗文档指南 📚第二章 安装📗准备工作📗开始安装📕创建XML配置文件📕初始化安装环境📕执行安装📕验证 📚第…

【数据结构】第三节:单链表

前言 本篇要求掌握的C语言基础知识:指针、结构体 目录 前言 单链表 概念 对比链表和顺序表 创建链表 实现单链表 准备工作 打印链表 创建节点并初始化 尾插 二级指针的调用 尾插代码 头插 尾删 头删 查找(返回节点) 在指定位…

C#硬件接口开发------一文了解WMI

🎈个人主页:靓仔很忙i 💻B 站主页:👉B站👈 🎉欢迎 👍点赞✍评论⭐收藏 🤗收录专栏:C# 硬件接口开发 🤝希望本文对您有所裨益,如有不足…

优优嗨聚集团:如何优雅地解决个人债务问题,一步步走向财务自由

在快节奏的现代生活中,个人债务问题似乎已成为许多人不得不面对的挑战。正确处理个人债务,不仅关系到个人信用和财务状况,更是实现财务自由的重要一步。本文将为您提供一些实用的建议,帮助您优雅地解决个人债务问题,走…

设计模式之备忘录模式(下)

3)实现多次撤销 1.结构图 对负责人类MementoCaretaker进行了修改,在其中定义了一个ArrayList类型的集合对象来存储多个备忘录。 2.代码实现 import java.util.*;public class MementoCaretaker {//定义一个集合来存储多个备忘录private ArrayList mem…

学员分享丨十年架构师感悟:敢于“提出问题”

最近呢小誉收到了一位工作十年的学员投稿,这位学员是2011年从誉天学习HCIE课程并顺利拿证,先后在华为等大厂工作。他想把他这十年的工作经验分享给各位学弟学妹们。 这些经验并非来自于具体的技术实现,而是在架构设计和实施过程中所体会到的一…

Github 2024-04-09 Python开源项目日报 Top10

根据Github Trendings的统计,今日(2024-04-09统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Python项目10Vue项目1JavaScript项目1系统设计指南 创建周期:2507 天开发语言:Python协议类型:OtherStar数量:241693 个Fork数量:42010 次…

C++生成动态库,C++和C#以及Java在windows和linux调用

Windows生成dllC库 1、创建动态链接库项目 源文件编写函数 // dllmain.cpp : 定义 DLL 应用程序的入口点。 #include "pch.h"int sum(int a, int b) {return a b; }BOOL APIENTRY DllMain( HMODULE hModule,DWORD ul_reason_for_call,LPVOID lpReserved) {switch…