Rabbit-MQ

Rabbit-mq

0.不同mq对比

ActiveMQ Kafka RocketMQ RabbitMQ

1.Docker装RabbitMq

1.拉取镜像
docker pull rabbitmq

2.创建并启动rabbitmq容器
docker run -id --hostname rabbitmq_h --name rabbitmq_c -p 15672:15672 -p 5672:5672 rabbitmq

3.进入容器交互界面
docker exec -it rabbitmq_c /bin/bash

4.下载网页端插件
rabbitmq-plugins enable rabbitmq_management

5.登录地址
http://虚拟机地址:15672

`可能会遇到的一些问题`
1.不关闭防火墙的话,可以开放15672端口访问
firewall-cmd --zone=public --add-port=15672/tcp --permanent //开放命令
firewall-cmd --reload //刷新防火墙

2.States in management UI are disabled on this node
即安装完之后不展示消息的图形化界面,通道(channel)无法进入
解决方案:
	'2.1' 进入容器内部
		  docker exec -it rabbitmq_c /bin/bash
	'2.2' 进入容器后进入到该目录下
		  cd /etc/rabbitmq/conf.d/
	'2.3' 执行命令
		  echo management_agent.disable_metrics_collector = false >
          management_agent.disable_metrics_collector.conf
    '2.4' 退出容器
    	  exit
	'2.5' 重启容器
		  docker restart 容器ID/容器名(rabbitmq_c)
	 然后再执行一遍上面的第3步
	 
登录默认账号密码为guest

2.RabbitMq简介

​ 以熟悉的电商场景为例,如果商品服务和订单服务是两个不同的微服务,在下单的过程中订单服务需要调用商品服务进行扣库存操作。按照传统的方式,下单过程要等到调用完毕之后才能返回下单成功,如果网络产生波动等原因使得商品服务扣库存延迟或者失败,会带来较差的用户体验,如果在高并发的场景下,这样的处理显然是不合适的,那怎么进行优化呢?这就需要消息队列登场了。

​ 消息队列提供一个异步通信机制,消息的发送者不必一直等待到消息被成功处理才返回,而是立即返回。消息中间件负责处理网络通信,如果网络连接不可用,消息被暂存于队列当中,当网络畅通的时候在将消息转发给相应的应用程序或者服务,当然前提是这些服务订阅了该队列。如果在商品服务和订单服务之间使用消息中间件,既可以提高并发量,又降低服务之间的耦合度。

​ RabbitMQ就是这样一款我们苦苦追寻的消息队列。RabbitMQ是一个开源的消息代理的队列服务器,用来通过普通协议在完全不同的应用之间共享数据。

​ RabbitMQ是使用Erlang语言来编写的,并且RabbitMQ是基于AMQP协议的。Erlang语言在数据交互方面性能优秀,有着和原生Socket一样的延迟,这也是RabbitMQ高性能的原因所在。可谓“人如其名”,RabbitMQ像兔子一样迅速。

2.1.RabbitMq优点

  • 开源、性能优秀,稳定性保障
  • 提供可靠性消息投递模式、返回模式
  • 与Spring AMQP完美整合,API丰富
  • 集群模式丰富,表达式配置,HA模式,镜像队列模型
  • 保证数据不丢失的前提做到高可靠性、可用性

2.2.RabbitMq应用场景

  • 异步处理。把消息放入消息中间件中,等到需要的时候再去处理。
  • 流量削峰。例如秒杀活动,在短时间内访问量急剧增加,使用消息队列,当消息队列满了就拒绝响应,跳转到错误页面,这样就可以使得系统不会因为超负载而崩溃。
  • 日志处理
  • 应用解耦。假设某个服务A需要给许多个服务(B、C、D)发送消息,当某个服务(例如B)不需要发送消息了,服务A需要改代码再次部署;当新加入一个服务(服务E)需要服务A的消息的时候,也需要改代码重新部署;另外服务A也要考虑其他服务挂掉,没有收到消息怎么办?要不要重新发送呢?是不是很麻烦,使用MQ发布订阅模式,服务A只生产消息发送到MQ,B、C、D从MQ中读取消息,需要A的消息就订阅,不需要了就取消订阅,服务A不再操心其他的事情,使用这种方式可以降低服务或者系统之间的耦合。

2.3.AMQP协议

​ 提到RabbitMQ,就不得不提AMQP协议。AMQP协议是具有现代特征的二进制协议。是一个提供统一消息服务的应用层标准高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。

AMQP协议模型有三部分组成:生产者、消费者和服务端。

AMQP协议中间的几个重要概念:

a.Broker

接收和分发消息的应用,RabbitMQ Server 就是 Message Broker

b.Virtual host

出于多租户和安全因素设计的,把AMQP的基本组件划分到一个虚拟的分组中,类似于网络中的 namespace概念。当多个不同的用户使用同一个RabbitMQ server提供的服务时,可以划分出
多个virtual host,每个用户在自己的virtual host创建 exchange/queue 等

c.Connection

publisher/consumer 和 broker 之间的 TCP 连接

d.Channel

如果每一次访问RabbitMQ都建立一个Connection,在消息量大的时候建立TCP
Connection的开销将是巨大的,效率也较低。Channel是在connection内部建立的逻辑连接,如果应用程序支持多线程,通常每个thread创建单独的channel进行通讯,AMQP method 包含了 channel id 帮助客户端和 message broker 识别 channel,所以 channel 之间是完全隔离的。Channel 作为轻量级的Connection 极大减少了操作系统建立 TCP connection

e.Exchange

message到达broker的第一站,根据分发规则,匹配查询表中的routingkey,分发消息到queue 中去。常用的类型有:direct (point-to-point), topic (publish-subscribe) and fanout (multicast)

f.Queue

消息最终被送到这里等待 consumer 取走

g.Binding

exchange和queue之间的虚拟连接binding中可以包含routingkey,Binding信息被保

存到exchange中的查询表中,用于message的分发依据

image-20230404103846038

​ AMQP模型图

3.RabbitMq概念

定义:RabbitMQ 是一个消息中间件:它接受并转发消息。你可以把它当做一个快递站点,当你要发送一个包裹时,你把你的包裹放到快递站,快递员最终会把你的快递送到收件人那里,按照这种逻辑 RabbitMQ 是一个快递站,一个快递员帮你传递快件。RabbitMQ 与快递站的主要区别在于,它不处理快件而是接收,

存储和转发消息数据。

3.1.四大核心概念

a.生产者

​ 生产者是产生数据发送消息的程序

b.交换机

​ 交换机是RabbitMQ非常重要的一个部件,一方面它接收来自生产者的消息,另一方面它将消息

推送到队列中。交换机必须确切知道如何处理它接收到的消息,是将这些消息推送到特定队列还是推

送到多个队列,亦或者是把消息丢弃,这个得有交换机类型决定

c.消息队列

​ 消息队列是 RabbitMQ 内部使用的一种数据结构,尽管消息流经 RabbitMQ 和应用程序,但它们只

能存储在队列中。队列仅受主机的内存和磁盘限制的约束,本质上是一个大的消息缓冲区。许多生产者可

以将消息发送到一个队列,许多消费者可以尝试从一个队列接收数据。这就是我们使用队列的方式

d.消费者

​ 消费与接收具有相似的含义。消费者大多时候是一个等待接收消息的程序。请注意生产者,消费

者和消息中间件很多时候并不在同一机器上。同一个应用程序既可以是生产者又是可以是消费者。

3.2.RabbitMq6种常见的工作模型

image-20230226110046868

3.2.1.基本消息模型

image-20230404104425892

RabbitMQ是一个消息代理:它接受和转发消息。 你可以把它想象成一个邮局:当你把邮件放在邮箱里时,你可以确定邮差先生最终会把邮件发送给你的收件人。 在这个比喻中,RabbitMQ是邮政信箱,邮局和邮递员。
RabbitMQ与邮局的主要区别是它不处理纸张,而是接受,存储和转发数据消息的二进制数据块。

P(producer/ publisher):生产者,一个发送消息的用户应用程序。

C(consumer):消费者,消费和接收有类似的意思,消费者是一个主要用来等待接收消息的用户应用程序

队列(红色区域):rabbitmq内部类似于邮箱的一个概念。虽然消息流经rabbitmq和你的应用程序,但是它们只能存储在队列中。队列只受主机的内存和磁盘限制,实质上是一个大的消息缓冲区。许多生产者可以发送消息到一个队列,许多消费者可以尝试从一个队列接收数据。

总结:生产者将消息发送到队列,消费者从队列中获取消息,队列是存储消息的缓冲区。

3.2.2.工作消息模型(work)

image-20230404104406868

工作队列,又称任务队列。主要思想就是避免执行资源密集型任务时,必须等待它执行完成。相反我们稍后完成任务,我们将任务封装为消息并将其发送到队列。在后台运行的工作进程将获取任务并最终执行作业。当你运行许多工人时,任务将在他们之间共享,但是一个消息只能被一个消费者获取。
总结:让多个消费者绑定到一个队列,共同消费队列中的消息。队列中的消息一旦消费,就会消失,因此任务是不会被重复执行的(默认是轮询)

public class Provider {

    private static final String QUEUE = "zyf";

    private static final String MESSAGE = "I love you zyf";

    public static void main(String[] args) throws IOException, TimeoutException {
        Connection connection = MqUtil.getConnection();
        Channel channel = connection.createChannel();
        channel.queueDeclare(QUEUE, true, false, false, null);
        for (int i = 0; i < 10; i++) {
            channel.basicPublish("", QUEUE, null, (MESSAGE + i).getBytes());
        }
        MqUtil.closeMq(channel, connection);
    }
public class Consumer {
    public static void main(String[] args) throws IOException {
        Connection connection = MqUtil.getConnection();
        Channel channel = connection.createChannel();
        channel.queueDeclare("zyf",true,false,false,null);
        System.out.println("C1等待 ...");
        channel.basicConsume("zyf", false,
                (s, delivery) -> System.out.println("接收到的消息:" + new String(delivery.getBody())),
                s -> System.out.println(s + "消费者取消息消费接口回调逻辑"));
    }
}
3.2.3.发布订阅模式(3类)

定义:

1、1个生产者,多个消费者

2、每一个消费者都有自己的一个队列

3、生产者没有将消息直接发送到队列,而是发送到了交换机

4、每个队列都要绑定到交换机

5、生产者发送的消息,经过交换机到达队列,实现一个消息被多个消费者获取的目的

X(Exchanges):交换机一方面:接收生产者发送的消息。另一方面:知道如何处理消息,例如递交给某个特别队列、递交给所有队列、或是将消息丢弃。到底如何操作,取决于Exchange的类型。

Exchange类型有以下几种:

Fanout:广播,将消息交给所有绑定到交换机的队列
Direct:定向,把消息交给符合指定routing key 的队列
Topic:通配符,把消息交给符合routing pattern(路由模式) 的队列

1、直连交换机(Direct)

image-20230404104516383

在Direct模型下,队列与交换机的绑定,不能是任意绑定了,而是要指定一个RoutingKey(路由key),消息的发送方在向Exchange发送消息时,也必须指定消息的routing key

P:生产者,向Exchange发送消息,发送消息时,会指定一个routing key

X:Exchange(交换机),接收生产者的消息,然后把消息递交给 与routing key完全匹配的队列

C1:消费者,其所在队列指定了需要routing key 为 error 的消息

C2:消费者,其所在队列指定了需要routing key 为 info、error、warning 的消息

2、广播交换机(Fanout)

image-20230404104527332

Fanout,也称为广播。
在广播模式下,消息发送流程是这样的:

  • 1) 可以有多个消费者
  • 2) 每个消费者有自己的queue(队列)
  • 3) 每个队列都要绑定到Exchange(交换机)
  • 4) 生产者发送的消息,只能发送到交换机,交换机来决定要发给哪个队列,生产者无法决定。
  • 5) 交换机把消息发送给绑定过的所有队列
  • 6) 队列的消费者都能拿到消息。实现一条消息被多个消费者消费

3、主题交换机/通配符交换机(Topic)

image-20230404104540145

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

通配符规则:#:匹配一个或多个词*:匹配不多不少恰好 1 个词

3.3.RabbitMq的工作原理

image-20230226110332187

4.SpringBoot整合mq

# 整合springboot使用rabbitmq
<dependency>
    <groupId>com.rabbitmq</groupId>
    <artifactId>amqp-client</artifactId>
    <version>5.7.2</version>
</dependency>

# 引入依赖
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

创建工厂

// 创建连接mq的连接工厂对象
    ConnectionFactory connectionFactory = new ConnectionFactory();
    // 设置连接mq主机(ip是虚拟机地址)
    connectionFactory.setHost("192.168.79.134");
    // 设置端口号
    connectionFactory.setPort(5672);
    // 设置连接哪个虚拟主机
    connectionFactory.setVirtualHost("/ems");
    // 设置访问虚拟主机的用户名和密码
    connectionFactory.setUsername("ems");
    connectionFactory.setPassword("123");

    // 获取连接对象
    Connection connection = connectionFactory.newConnection();
    // 获取连接中的通道
    Channel channel = connection.createChannel();
    // 通道绑定对应消息队列
    /**
     *  param1:队列名称,如果队列不存在则自动创建
     *  param2:用来定义队列特性是否要持久化 true持久化 false不持久化
     *  param3:是否独占队列(不允许别的通道使用这个队列)
     *  param4:是否在消费完成后自动删除队列
     *  param5:额外参数
     */
    channel.queueDeclare("hello",false,false,false,null);

    // 发布消息(直连不走交换机)
    /**
     * param1:交换机名称
     * param2:队列名称
     * param3:消息传递额外设置
     * param4:消息的具体内容
     */
    channel.basicPublish("", "hello", null, "hellorabbitmq".getBytes());

    // 关闭通道,关闭连接
    channel.close();
    connection.close();
posted @   zhangyf1121  阅读(22)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示