RabbitMQ

配置环境

安装 erlang环境以及RabbitMQ

RabbitMQ端口号: 5672

去官网下载 https://www.rabbitmq.com

然后重启RabbitMQ服务 RabbitMQ安装教程

开放端口15672

这里,通过http://IP地址:15672 进行Web页面登录,输入账号密码(默认都是guest),完成页面访问。至此,全部安装结束。

导入依赖

<!-- 集成RabbitMQ -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

配置相关信息

RabbitMQ的端口号是什么?

5672 :这是rabbitMQ的端口号;

15672 :这是那个RabbitMQ的web页面的端口号;

spring.application.name=spirng-boot-rabbitmq
spring.rabbitmq.host=127.0.0.1 ##主机ip
spring.rabbitmq.port=5672
spring.rabbitmq.virtual-host=MmHost
spring.rabbitmq.username=root
spring.rabbitmq.password=root
spring:
rabbitmq:
username: root
password: root
addresses: 127.0.0.1:5672
cache:
connection:
#Cache connection mode, with default connections and multiple channels
mode: channel
#Multiple connections, multiple channels
# mode: connection
# rabbitmq
server:
port: 8080
spring:
#给项目来个名字
application:
name: rabbitmq-consumer
#配置rabbitMq 服务器
rabbitmq:
host: 127.0.0.1
port: 5672
username: root
password: root
#虚拟host 可以不设置,使用server默认host
virtual-host: MmHost

发送消息

@Component
public class SenderTest{
@Autowired
private RabbitTemplate rabbitTemplate;
@Test
public void Send() {
// 队列名称
String queueName = "ThisKey";
// 消息
String message = "Hello, Spring AMQP!";
// 发送消息
rabbitTemplate.convertAndSend(queueName, message);
}
}

rabbitTemplate.convertAndSend(key, message);

接收消息

@Component
public class SpringRabbitMQListener {
@RabbitListener(queues = "ThisKey")
public void listenSimpleQueueMsg(String msg){
System.out.println(msg);
}
}
@Component
//指定所监听的队列
@RabbitListener(queues = "ThisKey")
public class SpringRabbitMQListener {
//指定用来处理接收消息的方法
@RabbitHandler
public void listenSimpleQueueMsg(String msg){
System.out.println(msg);
}
}

注意:此处消息被消费后,对应的ThisKey中的消息就消失了。

原文链接 去的去看看

RabbitMQ-基础使用(Spring AMQP) - 简书 (jianshu.com)

如果使用其他交换机,则需要进行相关配置

可以看这篇文章:SpringBoot整合RabbitMQ

1、创建对应的配置文件

例如Direct交换机

import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; /**
* @Author : Mm
* @CreateTime : 2023/2/23
* @Description :
**/
@Configuration
public class DirectRabbitConfig { //队列 起名:TestDirectQueue
@Bean
public Queue TestDirectQueue() {
return new Queue("TestDirectQueue",true);
} //Direct交换机 起名:TestDirectExchange
@Bean
DirectExchange TestDirectExchange() {
return new DirectExchange("TestDirectExchange");
} //绑定 将队列和交换机绑定, 并设置用于匹配键:TestDirectRouting
@Bean
Binding bindingDirect() {
return BindingBuilder.bind(TestDirectQueue()).to(TestDirectExchange()).with("TestDirectRouting");
}
}

如何保证消息的可靠?

ack应答

消息应答

概念

消费者完成一个任务可能需要一段时间,如果其中一个消费者处理一个长的任务并仅只完成了部分突然它挂掉了,会导致消息丢失。RabbitMQ 一旦向消费者传递了一条消息,便立即将该消息标记为删除。在这种情况下,突然有个消费者挂掉了,我们将丢失正在处理的消息。以及后续发送给该消费这的消息,因为它无法接收到。

为了保证消息在发送过程中不丢失,rabbitmq 引入消息应答机制,消息应答就是:消费者在接收到消息并且处理该消息之后,告诉 rabbitmq 它已经处理了,rabbitmq 可以把该消息删除了。

各种消息模型实例

五种交换机类型

Direct Exchange

直连型交换机,根据消息携带的路由键将消息投递给对应队列。

大致流程,有一个队列绑定到一个直连交换机上,同时赋予一个路由键 routing key 。

然后当一个消息携带着路由值为X,这个消息通过生产者发送给交换机时,交换机就会根据这个路由值X去寻找绑定值也是X的队列。

Fanout Exchange

扇型交换机,这个交换机没有路由键概念,就算你绑了路由键也是无视的。 这个交换机在接收到消息后,会直接转发到绑定到它上面的所有队列。

Topic Exchange

主题交换机,这个交换机其实跟直连交换机流程差不多,但是它的特点就是在它的路由键和绑定键之间是有规则的。

其他两种:WorkQueue(通过监听队列名称)

基本消息队列BasicQueue即为上方的代码,此处不再重复。

- 1、WorkQueue(通过监听队列名称)

WorkQueue.png

WorkQueueBasicQueue不同之处,就是WorkQueue支持一对多发布消息(不是一个消息发给多个消费者,一个消息只会被一个消费者消费),多个消费者可以提高消息消费速度,当然相同之处也是消息消费后就会从Queue中消失(后续的几种模型都是如此)。

① 模拟消息堆积

    // 队列名称
String queueName = "simple.queue";
// 消息
String message = "Message_";
for (int i = 1; i <= 50; i++) {
// 发送消息
rabbitTemplate.convertAndSend(queueName, message + i);
Thread.sleep(20);
}

② 接收消息

此处设置两个线程处理速度不同。

@RabbitListener(queues = "simple.queue")
public void listenWorkQueue1(String msg) throws InterruptedException {
System.out.println("消费者1接收到消息:【" + msg + "】" + LocalTime.now());
Thread.sleep(20);
} @RabbitListener(queues = "simple.queue")
public void listenWorkQueue2(String msg) throws InterruptedException {
System.err.println("消费者2........接收到消息:【" + msg + "】" + LocalTime.now());
Thread.sleep(200);
}

处理结果是2个消费者会均分消息。可以修改消费方的配置,以按照实际处理能力分配,如下:

spring:
rabbitmq:
listener:
simple:
prefetch: 1 # 每次只能获取一条消息,处理完成才能获取下一个消息

- 2、Fanout (扇形交换机)

Fanout.png

① 编写Fanout配置类

创建FanoutExchange,绑定队列Queue和交换机Exchange。

@Configuration
public class FanoutConfig {
/**
* 声明交换机
* @return Fanout类型交换机
*/
@Bean
public FanoutExchange fanoutExchange(){
return new FanoutExchange("stone.fanout");
}
/**
* 第1个队列
*/
@Bean
public Queue fanoutQueue1(){
return new Queue("fanout.queue1");
}
/**
* 绑定队列和交换机
*/
@Bean
public Binding bindingQueue1(Queue fanoutQueue1, FanoutExchange fanoutExchange){
return BindingBuilder.bind(fanoutQueue1).to(fanoutExchange);
}
/**
* 第2个队列
*/
@Bean
public Queue fanoutQueue2(){
return new Queue("fanout.queue2");
}
/**
* 绑定队列和交换机
*/
@Bean
public Binding bindingQueue2(Queue fanoutQueue2, FanoutExchange fanoutExchange){
return BindingBuilder.bind(fanoutQueue2).to(fanoutExchange);
}
}

② 发送消息

    // 队列名称
String exchangeName = "stone.fanout";
// 消息
String message = "Hello, Fanout!";
rabbitTemplate.convertAndSend(exchangeName, "", message);

③ 接收消息

    @RabbitListener(queues = "fanout.queue1")
public void listen1FanoutQueueMsg(String msg){
System.out.println("Listener1 get :" + msg);
}
@RabbitListener(queues = "fanout.queue2")
public void listen2FanoutQueueMsg(String msg){
System.out.println("Listener2 get :" + msg);
}

不同于WorkQueueFanout Exchange广播模型下,绑定该交换机的消费者可以获取到对应的消息(即一条消息可以通过交换机被多个消费者消费)。

- 3、Direct(直连交换机)

Direct.png

① 基于注解声明队列和交换机

@RabbitListener的使用

bindings = @QueueBinding()配置绑定关系;

value = @Queue(name = "direct.queue1")配置队列;

exchange = @Exchange(name = "stone.direct", type = ExchangeTypes.DIRECT)配置交换机;

key = {"talkshow", "musicshow"}配置订阅。监听的key进行匹配,

rabbitTemplate.convertAndSend(exchangeName, "xxx", message);中的xxx第二个参数进行匹配

注意:type = ExchangeTypes.DIRECT是默认类型,可以不做配置。

    @RabbitListener(bindings = @QueueBinding(
value = @Queue(name = "direct.queue1"),
exchange = @Exchange(name = "stone.direct", type = ExchangeTypes.DIRECT),
key = {"talkshow", "musicshow"}
))
public void listenDirectQueue1(String msg){
System.out.println("DirectQueue1 :" + msg);
} @RabbitListener(bindings = @QueueBinding(
value = @Queue(name = "direct.queue2"),
exchange = @Exchange(name = "stone.direct", type = ExchangeTypes.DIRECT),
key = {"talkshow", "news"}
))
public void listenDirectQueue2(String msg){
System.out.println("DirectQueue2 :" + msg);
}

② 发送消息

    // 交换机名称
String exchangeName = "itcast.direct";
// 消息
String messageNews = "乌俄冲突升级,昔日友邦冷眼旁观!";
// 发送消息
rabbitTemplate.convertAndSend(exchangeName, "news", messageNews);
// 消息
String messageTalks = "蜘蛛侠3英雄无归发布蓝光预告,主演再登SN宣传!";
// 发送消息
rabbitTemplate.convertAndSend(exchangeName, "talkshow", messageTalks);

此时:订阅news主题的队列direct.queue1可以消费messageNews,订阅talkshow主题的direct.queue1direct.queue2均可以消费messageTalks

- 4、Topic(主题交换机)

Topic.png

Topic类型的ExchangeDirect相比,都是可以根据RoutingKey把消息路由到不同的队列。只不过Topic类型Exchange可以让队列在绑定Routing key 的时候使用通配符。通配符规则:

#:匹配一个或多个词

*:匹配不多不少恰好1个词

① 发送消息

/**
* topicExchange
*/
@Test
public void testSendTopicExchange() {
// 交换机名称
String exchangeName = "itcast.topic";
// 消息
String message = "建设更高水平法治中国";
// 发送消息
rabbitTemplate.convertAndSend(exchangeName, "china.news", message);
}

② 接收消息

    @RabbitListener(bindings = @QueueBinding(
value = @Queue(name = "topic.queue1"),
exchange = @Exchange(name = "stone.topic", type = ExchangeTypes.TOPIC),
key = {"China.#"}
))
public void listenTopicQueue1(String msg){
System.out.println("TopicQueue1 :" + msg);
} @RabbitListener(bindings = @QueueBinding(
value = @Queue(name = "topic.queue2"),
exchange = @Exchange(name = "stone.topic", type = ExchangeTypes.TOPIC),
key = {"#.news"}
))
public void listenTopicQueue2(String msg){
System.out.println("TopicQueue2 :" + msg);
}

此时,由于消息Topic满足两个队列的订阅规则,所以两个队列都可以消费到消息。

RabbitMQ交换机类型(参数介绍)

amqp (advanced message queuing protocol 高级消息队列协议) 核心概念:

server /broker 消息服务器: 接收 / 存储消息, 维护交换机 / 队列等元信息数据

connection 连接: 客户端连接消息服务器

channel 网络信道: 一个 connection 可以有多个 channel

virutual host 虚拟主机: 逻辑隔离, 相当于 tomcat 的 webapps 下各个项目

exchange 交换机: 消息会首先发送到指定交换机, 交换机再根据交换机类型和路由键路由到指定队列

routing key 路由键: 交换机根据路由键路由到指定队列, 路由键可以是固定的名字或者是主题交换机的 pattern, 即 # 表示 0 个或多个单词, * 固定表示 1 个单词

message 消息: 包含消息属性 (头信息 / 优先级等) 和消息体

queue 队列 (消息会路由保存到某个队列中)

监听者 (相同队列下可以有多个监听者消费, 一般一个消息只会分发到某个监听者身上)

交换机类型

Direct 直连交换机 (一对一, 只能发送到对应绑定的单个队列, 不够灵活)

Topic 主题交换机 (支持一对多, 根据模式, 与路由键匹配的队列都会收到消息, 灵活, 推荐)

Fanout 广播交换机 (所有与该交换机绑定的队列都会收到消息, 即忽略路由键)

headers 头交换机 (使用头信息匹配, 不使用路由键. 交换机会声明一个 key 是 x-match, 值是 all (全部匹配) 或者 any (任一匹配) (匹配会忽略所有 x- 开头的头信息) 传过来消息的头信息会与绑定头交换机的队列的头信息比较)

附:

主题交换机的模式语法:

  • 表示匹配 1 个单词, 例如 mall.* 可以匹配 mall.order 不能匹配 mall.order.cancel

表示匹配 0 个或多个单词, 例如 mall.# 可以匹配 mall.order.cancel

RabbitMQ的应用场景

  1. 延迟队列,延迟消息
  2. 服务与服务之间的解耦(例如一个服务进行mysql操作的时候需要另一个服务同时进行对应操作)
  3. 异步处理、流量削峰

1、异步处理

假设想象一下我们做一个商城项目,在用户支付模块中,可能会涉及到其它业务,比如:积分折扣、消费券、短信验证等功能。我们传统的执行步骤是逐步执行,也就是说当用户点击支付 ----> 积分折扣 ----> 消费券 ----> 短信验证 ----->支付完成,用户需要等待每个业务执行完毕才能支付成功!假设我们从点击支付 -----> 支付成功消耗时间为100/ms,后面我们每新增一个业务就会多耗时50/ms,上述的流程大概会耗时250/ms!如果说以后业务更多的话,那么用户支付订单的时间会越来越长,这样大大影响了用户的体验!参照下图理解

我们使用消息中间件进行异步处理,当用户下单支付同时我们创建消息队列进行异步的处理其它业务,在我们支付模块中最重要的是用户支付,我们可以将一些不重要的业务放入消息队列执行,这样可以大大添加我们程序运行的速度,用户支付模块中也大大减少了支付时间,为用户添加了更好的体验。其它模块与其思想一致,就比如说用户注册!

2、流量削峰

假设我们有一个订单系统,我们的订单系统最大承受访问量是每秒1万次,如果说某天访问量过大我们的系统承受不住了,会对服务器造成宕机,这样的话我们的系统就瘫痪了,为了解决该问题我们可以使用中间件对流量进行消峰

未加入中间件之前,用户直接访问的是订单系统

加入中间件之后,用户直接访问的是中间件,通过中间件对用户进行消峰,好处是可以避免系统的宕机瘫痪,坏处是系统速度变慢,但是总比不能使用好

3、应用解耦

我们以商城项目为例,订单系统耦合调用支付、库存、物流系统,如果某天其中一个系统出现了异常就会造成订单系统故障!使用中间件后订单系统通过队列去访问支付、库存、物流系统就不会造成上述的问题,因为订单系统执行完成才会发消息给队列,接下来的任务就交给队列完成,队列会监督各个系统完成,如果完不成队列会一直监督,直到完成为止!所以说使用中间件后不会造成一个子系统出现故障而造成整个系统故障

RabbitMQ中间件的更多相关文章

  1. 分享 rabbitMQ入门详解

    原文地址http://blog.csdn.net/cugb1004101218/article/details/21243927 目录(?)[-] rabbitMQ说明文档 rabbitMQ是什么 消 ...

  2. Net分布式系统之四:RabbitMQ消息队列应用

    消息通信组件Net分布式系统的核心中间件之一,应用与系统高并发,各个组件之间解耦的依赖的场景.本框架采用消息队列中间件主要应用于两方面:一是解决部分高并发的业务处理:二是通过消息队列传输系统日志.目前 ...

  3. rabbitmq技术

    Rabbitmq 初识rabbitmq RabbitMQ是流行的开源消息队列系统,用erlang语言开发.RabbitMQ是AMQP(高级消息队列协议)的标准实现.如果不熟悉AMQP,直接看Rabbi ...

  4. RabbitMQ 命令行

    用户命令 .添加用户 rabbitmqctl add_user username password .删除用户 rabbitmqctl delete_user username .修改密码 rabbi ...

  5. RabbitMQ消息队列应用

    RabbitMQ消息队列应用 消息通信组件Net分布式系统的核心中间件之一,应用与系统高并发,各个组件之间解耦的依赖的场景.本框架采用消息队列中间件主要应用于两方面:一是解决部分高并发的业务处理:二是 ...

  6. rabbitmq技术的一些感悟(一)

    Rabbitmq 初识rabbitmq RabbitMQ是流行的开源消息队列系统,用erlang语言开发.RabbitMQ是AMQP(高级消息队列协议)的标准实现.假设不熟悉AMQP,直接看Rabbi ...

  7. 消息队列的使用 RabbitMQ (二): Windows 环境下集群的实现

    一.RabbitMQ 集群的基本概念 一个 RabbitMQ 中间件(broker) 由一个或多个 erlang 节点组成,节点之间共享 用户名.虚拟目录.队列消息.运行参数 等, 这个 节点的集合被 ...

  8. RabbitMQ框架构建系列(二)——RabbitMQ基础知识介绍

    上一篇记录了一下AMQP协议,RabbitMQ是一个Erlang开发的AMQP协议的开源实现.这一篇简单的介绍一下RabbitMQ的基本原理. 一.RabbitMQ的特点 1.可靠性:RabbitMQ ...

  9. ubuntu14.04 rabbitmq安装与使用 --修改RabbitMQ数据存储位置

    参考:https://blog.csdn.net/tianjiewang/article/details/58383062 说明: ubuntu14.04   rabiitmq 默认 安装路径 /va ...

  10. 关于RabbitMQ以及RabbitMQ和Spring的整合

    转自:https://www.cnblogs.com/s648667069/p/6401463.html 基本概念 RabbitMQ是流行的开源消息队列系统,用erlang语言开发.RabbitMQ是 ...

随机推荐

  1. Golang 入门 : 符文

    字符串常用语表示一系列文本字符,而Go的符文(rune)则用于表示单个字符. 字符串字面量由双引号(")包围,但rune字面量由单引号(')包围. Go程序几乎可以使用地球上任何语言的任何字 ...

  2. JavaScript 图片弹窗

    html <!-- 触发弹窗 - 图片改为你的图片地址 --> <img loading="lazy" id="myImg" src=&quo ...

  3. 小程序和APP抓包的问题

    小程序和APP抓包的问题 很多同学都会遇到小程序和APP抓不到包的问题,抓不到https请求包,这边给大家提供一些解决方案. Yakit工具 首先需要的就是一个抓包神器yakit,这个工具非常好用强大 ...

  4. 关于SIFT,GIFT在旋转不变性上的对比实验

    目录 关于SIFT,GIFT在旋转不变性上的对比实验 回顾 准确率测试 总结 核心代码 关于SIFT,GIFT在旋转不变性上的对比实验 这篇文章不讨论SIFT,GIFT的实现原理,只从最终匹配结果的准 ...

  5. 【Spring】JdbcTemplate的使用方法

    概念和准备 什么是 JdbcTemplate Spring 框架对 JDBC 进行封装,使用 JdbcTemplate 方便实现对数据库操作 准备工作 引入相关 jar 包 在 spring 配置文件 ...

  6. Quartz.NET - 教程 12: Quartz 的其他特性

    译者注: 目录在这 Quartz.NET 3.x 教程 原文在这 Lesson 12: Miscellaneous Features of Quartz 插件 Quartz 提供了一个用于插入附加功能 ...

  7. 学习Kotlin语法(二)

    简介 经过上一章节,我们对Kotlin基础语法有了大致的了解,了解了什么是基本类型.集合.控制流程.函数.类.空安全,接下来我们将更近一步的去了解Kotlin的相关知识,本章节将详细的学习Kotlin ...

  8. springboot集成docker实现自动化构建镜像说明

    springboot集成docker实现自动化构建镜像说明 文档说明 该文档仅包括通过配置springboot.docker.jenkins.git.appollo等实现持续构建,持续发布的功能,不包 ...

  9. mybatis-plus之配置安全

    1. 环境 SpringBoot 2.6.x 2. 介绍 MyBatis-Plus 从3.3.2版本开始提供了数据安全保护功能,MyBatis-Plus 支持通过加密配置来增强数据库的安全性. 3. ...

  10. python,去掉“xa0”和“\r\n”

    爬小说网站,输出内容有时候会出现下图字符 首先,去掉"xa0" s = 'T-shirt\xa0\xa0短袖圆领衫,体恤衫\xa0' out = "".join ...