【01】RabbitMQ快速上手以及核心概念详解

1、MQ概述

1、什么是MQ?

  • MQ:消息队列(MessageQueue),下面学习的RabbitMQ是一种典型的MQ产品。
  • MQ的概念可以分为两部分来理解,首先是,Message(消息):在不同应用程序之间传递的数据。接着是,Queue(队列):是一种FIFO先进先出的数据结构。
  • 将消息以队列的形式存储起来,并在不同的应用程序之间进行传递,这就是MssageQueue。
  • RabbitMQ的更多信息请去官网获取。

2、MQ的作用

  • MQ产品最直接的作用就是,将同步的事件,驱动为 异步的消息驱动。
  • 在SpringBoot内部就集成了这种消息驱动的机制,但是,生产者和消费者都只能在一个进程中使用,如果需要垮行调用,这就需要一个独立的中间服务来发布和接收这些消息,这个中间服务就是MQ中间件。
  • 比如:在一个大型电商项目中,订单服务完成下单,就可以发布下单事件,而下游的消费者,就可以消费这个下单事件,进行一些补充的业务。
  • 在这个业务过程中,MQ中间件会起到以下作用:
    • 解耦:生产者和消费者都只跟中间件进行交互,而不需要直接进行交互。这意味着,在生产者发送消息时,不需要考虑是否存在消费者或者存在多个消费者,反之亦然。 甚至,即便生产者和消费者是不同语言开发的,两者只要能够与中间件MQ进行正常的交互,那么它们之间就可以通过MQ进行消息的传递。(减少服务与服务之间的影响,提高系统整体的稳定性以及可拓展性
    • 异步:消息并不是从生产者发出后就立即交给消费者进行处理,而是在MQ中间件暂存下来。等到消费者启动后,再自行去MQ上处理。这就避免了生产者发送消息与消费者处理消息的时间冲突。(提高系统的响应速度、吞吐量
    • 削峰:有了MQ做消息暂存,那么当生产者发送消息的速度与消费者处理消息的速度不一致时,MQ就能起到削峰填谷的作用。(以稳定的系统资源来应对突发的流量冲击
  • MQ的缺点:
    • 系统可用性降低
      • 系统引入的外部依赖增多,系统的稳定性就会变差。一旦MQ宕机,对业务会产生影响,这就需要考虑如何保证MQ的高可用性。
    • 系统复杂度提高
      • 引入MQ后系统的复杂度会大大提高。以前服务之间可以进行同步的服务调用,引入MQ之后就会变成异步调用,数据的链路就会变得更复杂,并且还会带来一些其他问题,例如:如何保证消息不会被丢失、不会被重复消费等等。
    • 消息一致性问题
      • A系统处理完业务,通过MQ发送给B和C系统进行后续的业务处理。如果B系统处理完成,C系统处理失败怎么办?这就需要考虑如何保证消息数据处理的一致性。

3、主流MQ产品的比较

  • 在MQ长期发展过程中,诞生了很多MQ产品,但是有很多MQ产品都已经逐渐被淘汰了。比如早期的 ZeroMQ、ActiveMQ等。目前最常用的MQ产品包括:kafka、RabbitMQ、RocketMQ,下面对这三个产品做个简单的比较以及理解他们的适用场景:

2、RabbitMQ快速上手

2.1 RabbitMQ产品介绍

  • RabbitMQ的历史可以追随到2005年,他是一个非常老牌的MQ产品,使用非常广泛。同时期的很多MQ产品都已经逐渐被业界淘汰了,比如2003年诞生的ActiveMQ,2012年诞生的ZeroMQ,但是RabbitMQ却依然稳稳占据一席之地,足可见他的经典。官网地址

2.2 安装RabbitMQ

2.2.1 前置环境
  • RabbitMQ是基于Erlang语言开发的,所以,按照RabbitMQ之前需要安装Erlang语言的环境。需要注意的是:RabbitMQ与Erlang语言之间是有版本对应关系的。目前,3.13版本的RabbitMQ需要Erlang语言版本在26.0到26.x之间。
  • 需要先从官网下载操作系统对应的RabbitMQ安装包以及Erlang语言的安装包。
2.2.2 安装RabbitMQ服务
  • RabbitMQ服务有多种安装方式。在学习阶段,建议使用CentOS手动进行安装,这样更能接触产品的细节。之后使用其他操作系统或者使用Docker等技术安装时,才会更顺利。

  • 需要注意的是当前版本(3.13)的RabbitMQ建议CentOS版本最好升级到CentOS9版本。至少不能低于CentOS8

  • Erlang语言包的安装,建议使用RabbitMQ提供的zero dependency版本,可点击此处下载对应版本的安装包。

    [root@localhost mq]# rpm -ivh erlang-25.1-1.el8.x86_64.rpm 
    警告:erlang-25.1-1.el8.x86_64.rpm: 头V4 RSA/SHA256 Signature, 密钥 ID cc4bbe5b: NOKEY
    Verifying...                          ################################# [100%]
    准备中...                          ################################# [100%]
    正在升级/安装...
       1:erlang-25.1-1.el8                ################################# [100%]
    [root@localhost mq]# erl -version
    Erlang (SMP,ASYNC_THREADS) (BEAM) emulator version 13.1
    
  • 接下来是安装RabbitMQ,这里采用RPM安装包的方式,可点击此处下载对应版本的安装包。这里我们下载的是无依赖版本:rabbitmq-server-3.12.12-1.el8.noarch.rpm

    [root@localhost mq]# rpm -ivh rabbitmq-server-3.12.12-1.el8.noarch.rpm 
    警告:rabbitmq-server-3.12.12-1.el8.noarch.rpm: 头V4 RSA/SHA512 Signature, 密钥 ID 6026dfca: NOKEY
    Verifying...                          ################################# [100%]
    准备中...                          ################################# [100%]
    正在升级/安装...
       1:rabbitmq-server-3.12.12-1.el8    ################################# [100%]
    [/usr/lib/tmpfiles.d/rabbitmq-server.conf:1] Line references path below legacy directory /var/run/, updating /var/run/rabbitmq → /run/rabbitmq; please update the tmpfiles.d/ drop-in file accordingly.
    
  • 安装完成之后,可以使用几个常用指令来维护RabbitMQ的服务状态。

    --1)启动Rabbitmq服务。启动应用之前要先启动服务。
    service rabbitmq-server start 
    
    --2)重启RabbitMQ服务
    systemctl restart rabbitmq-server
    
    --3)后台启动RabbitMQ应用 
    rabbitmq-server -deched  
    
    --4)启动Rabbitmq客户端
    rabbitmqctl start_app  
    
    --5)关闭Rabbitmq 
    rabbitmqctl stop  
    
    --6)查看RabbitMQ的服务状态,如果出现 Status为 Runtime 表示启动成功
    rabbitmqctl status
    或
    systemctl status rabbitmq-server
    
  • 默认情况下,RabbitMQ只是一个后台服务,不便于管理。而RabbitMQ提供了管理插件,可以使用图形化的方式管理RabbitMQ。

    -- 安装管理插件
    [root@localhost mq]# rabbitmq-plugins enable rabbitmq_management
    Enabling plugins on node rabbit@xq:
    rabbitmq_management
    The following plugins have been configured:
      rabbitmq_management
      rabbitmq_management_agent
      rabbitmq_web_dispatch
    Applying plugin configuration to rabbit@xq...
    The following plugins have been enabled:
      rabbitmq_management
      rabbitmq_management_agent
      rabbitmq_web_dispatch
    
    started 3 plugins.
    
    -- 重启服务后生效
    [root@localhost mq]# service rabbitmq-server start
    Redirecting to /bin/systemctl start rabbitmq-server.service
    [root@localhost mq]# rabbitmq start_app
    
    -- 查看防火墙状态、关闭防火墙、防止防火墙开机自启
    service firewalld status
    service firewalld stop
    systemctl disable firewalld
    
  • 插件激活后,就可以访问RabbitMQ的Web界面的控制台了,默认端口:15672

  • RabbitMQ提供了默认的用户名guest,密码guest。但是默认情况下,只允许本地登录,远程访问是无法登录的。这时,通常都会创建一个管理员账号单独对RabbitMQ进行管理。

    [root@localhost mq]# rabbitmqctl add_user admin admin
    Adding user "admin" ...
    Done. Don't forget to grant the user permissions to some virtual hosts! See 'rabbitmqctl help set_permissions' to learn more.
    [root@localhost mq]# rabbitmqctl set_permissions -p / admin "." "." ".*"
    Setting permissions for user "admin" in vhost "/" ...
    [root@localhost mq]# rabbitmqctl set_user_tags admin administrator
    Setting tags for user "admin" to [administrator] ...
    
  • 这样,就可以使用 admin / admin 用户登录Web控制台了。

2.3 RabbitMQ的基础使用

  • 登录控制台后,首页上方就能看到RabbitMQ的主要功能模块。其中Overview是概述,主要展示RabbitMQ服务的一些整体运行情况。接着 ConnectionsChannelsExchangesQueues 就是RabbitMQ的核心功能。最后,Admin 则是一些管理功能。
  • 例如:之前创建的 admin 的用户信息,在Admin的管理页面就能够看到:
  • 例如:在Admin的管理页面可以创建一个虚拟机,并配置admin用户拥有访问权限
  • 在RabbitMQ中,不同虚拟机之间的资源是完全隔离的。在资源充足的情况下,每个虚拟机可以当成一个独立的RabbitMQ服务来使用。
2.3.1 理解Queue
  • Exchange和Queue是RabbitMQ中用来传递消息的核心组件,下面进行简单体验一下:

    • 1、在Queues模块下,创建一个名称为testQueue1的经典队列
    • 2、创建完成之后,选择这个队列,就可以在页面上直接发送消息以及收到消息了。
  • 在RabbitMQ中的消息都是通过Queue队列传递的,这个Queue其实就是一个典型的FIFO的队列数据结构。我们当前的演示是通过控制台页面来通过Queue进行收发消息。未来,我们编写客户端时,就是绑定对应的Queue进行消息收发。

2.3.2 理解Exchange
  • 队列Queue可以发送消息,也可以收消息。那旁边的Exchange交换机的作用是啥?其实,它是用来辅助发送消息的。Exchange与Queue之间会建立一种绑定关系。通过不同的绑定,Exchange交换机中发送的消息就可以分发到不同的Queue上。
  • 进到Exchange菜单,可以看到针对每个虚拟机,RabbitMQ都预先创建了多个Exchange交换机。
  • 这里我们选择 /master 虚拟机上的 amq.direct 交换机,进入到交换机详情页,选择Bingings,并将 testQueue1 队列绑定到这个交换机上。
  • 绑定完成之后,可以在Exchange详情页以及Queue详情页看到绑定的结果。
  • 接下来就可以在Exchange的详情页里发送消息。然后在testQueue1 这个队列中就能消费到这条消息。
  • Exchange交换机并不实际存储消息,只是将发送到Exchange的消息转发到绑定的队列上。在具体使用时,通常只有消息生产者需要与Exchange打交道。而消费者,则并不需要与Exchange打交道,只要从Queue中消费消息就可以了。
  • 另外,Exchange既然可以绑定一个队列,当然也可以绑定多个队列。在实际使用中,Exchange与Queue之间可以建立不同类型的绑定关系,然后通过一些不同的策略,选择将消息转发到哪些Queue上。这时候,Messaage上几个没有用上的参数,像 Routing Key ,Headers,Properties这些参数就能派上用场了。
  • 在这个过程中,我们都是通过页面操作完成的消息发送与接收。在实际应用时,其实就是通过RabbitMQ提供的客户端API来完成这些功能。但是整个执行的过程,其实跟页面操作是相同的。
2.3.3 理解Connection和Channel
  • 这两个功能实际上是跟客户端应用相关联的。一个Connection可以理解为一个客户端应用,而一个应用可以创建多个Channel,用来与RabbitMQ进行交互。
  • 下面简单搭建一个客户端应用来体验一下:
    • 1、创建一个Maven项目,在pom.xml文件中引入RabbitMQ客户端的依赖:
      	 <dependency>
                  <groupId>com.rabbitmq</groupId>
                  <artifactId>amqp-client</artifactId>
                  <version>5.21.0</version>
      	 </dependency>
      
    • 2、然后创建一个消费者实例,尝试从RabbitMQ上的testQueue1 这个队列上拉取消息。
      public class FirstConsumer {
      
          private static final String HOST_NAME = "192.168.121.134";
          private static final Integer HOST_PORT = 5672;
          private static final String USER_NAME = "admin";
          private static final String PASSWORD = "admin";
          private static final String QUEUE_NAME = "testQueue1";
          private static final String VIRTUAL_HOST = "/master";
      
      
          public static void main(String[] args) throws Exception{
              ConnectionFactory factory = new ConnectionFactory();
              factory.setHost(HOST_NAME);
              factory.setPort(HOST_PORT);
              factory.setUsername(USER_NAME);
              factory.setPassword(PASSWORD);
              factory.setVirtualHost(VIRTUAL_HOST);
              //建立连接
              Connection connection = factory.newConnection();
              //创建信道
              Channel channel = connection.createChannel();
              //声明队列(参数值:队列名,durable是否持久化;exclusive:是否独占;autoDelete:是否自动删除;arguments: 其他参数)
              //如果Broker上没有队列,则自动创建队列,但是,如果已经有这个队列了,那么队列的属性必须匹配,否则会报错
              channel.queueDeclare(QUEUE_NAME, true, false, false, null);
              //设置每个worker同时最多处理的消息个数
              channel.basicQos(1);
              //回调函数,用于定义处理消息的业务逻辑
              Consumer consumer = new DefaultConsumer(channel) {
                  @Override
                  public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                      System.out.println("========消息处理中======");
                      String routingKey = envelope.getRoutingKey();
                      System.out.println("routingKey:=>" + routingKey);
                      String contentType = properties.getContentType();
                      System.out.println("contentType:=>" + contentType);
                      long deliveryTag = envelope.getDeliveryTag();
                      System.out.println("deliveryTag:=>" + deliveryTag);
                      String message = new String(body, StandardCharsets.UTF_8);
                      System.out.println("content:=>" + message);
                  }
              };
              //从队列接收消息并处理
              channel.basicConsume(QUEUE_NAME,true,consumer);
          }
      }
      
    • 运行这个程序后,这时,我们可以去管理平台的页面上,往 testQueue1 队列发送一条消息,就能看到客户端会及时的处理这条消息。
  • 最后,可以在管理平台的Connection和Channels中看到这个消费者程序与RabbitMQ建立的连接和通道。
  • 这里可以看到Connection就是与客户端的一个连接。只要连接还通着,他的状态就是running。而Channel是RabbitMQ与客户端进行数据交互的一个通道,没有数据交互时,状态就是idle闲置。有数据交互时,就会变成running。

3、RabbitMQ的核心概念总结

  • 通过这些操作,我们可以了解到RabbitMQ的消息流转模型。
  • 这里有很多重要的概念:
    • <1> Queue 队列:这是RabbitMQ中最核心的概念。它是实际保存数据的最小单元。Queue结构天生就具有FIFO的顺序。消息最终要被发送到Queue当中,然后才能被消费者进行消费处理。
    • <2> Exchange 交换机:这是RabbitMQ中进行数据路由的重要组件。Exchange并不实际保存消息,而是与Queue之间建立绑定关系,然后,如果有消息发送到了Exchange,Exchange就会将消息转发到Queue对列中,从而被对应的消费者消费处理。
    • <3> virtual host 虚拟机:RabbitMQ出于服务器复用的想法,可以在一个RabbitMQ集群中划分出多个虚拟主机,每一个虚拟主机都有全套的基础服务组件,可以针对每个虚拟主机进行权限以及数据分配。不同虚拟主机之间是完全隔离的,如果不考虑资源分配的情况,一个虚拟主机就可以当成一个独立的RabbitMQ服务使用。
      同时,也意味着不同虚拟主机之间是无法进行通信的,尽管他们是部署在同一个RabbitMQ服务上。例如,你无法通过虚拟机A的Exchange交换机将消息转发到虚拟机B的Queue上。
    • <4> Connection 连接:客户端与RabbitMQ进行交互,首先就需要建立一个TPC连接,这个连接就是Connection。既然是通道,那就需要尽量注意在停止使用时要关闭,释放资源。
    • <5> Channel 信道:一旦客户端与RabbitMQ建立了连接,就会分配一个AMQP信道 Channel。每个信道都会被分配一个唯一的ID。也可以理解为是客户端与RabbitMQ实际进行数据交互的通道,我们后续的大多数的数据操作都是在信道 Channel 这个层面展开的。
      RabbitMQ为了减少性能开销,也会在一个Connection中建立多个Channel,这样便于客户端进行多线程连接,这些连接会复用同一个Connection的TCP通道,所以在实际业务中,对于Connection和Channel的分配也需要根据实际情况进行考量。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值