RabbitMQ的基本使用

RabbitMQ 与 AMQP 遵循相同的模型架构,其架构示例图如下

在这里插入图片描述

1.重要概念

1.Publisher:消息生产者,就是投递消息的程序。发布者 (或称为生产者) 负责生产消息并将其投递到指定的交换器上

2.Message:消息由消息头和消息体组成,消息头用于存储与消息相关的元数据:如目标交换器的名字 (exchange_name)路由键 (RountingKey)和其他可选配置 (properties) 信息。消息体为实际需要传递的数据

3.Exchange:交换器负责接收来自生产者的消息,并将消息路由到一个或者多个队列中,如果路由不到,则返回给生产者或者直接丢弃,这取决于交换器的 mandatory 属性

  • 当 mandatory 为 true 时:如果交换器无法根据自身类型和路由键找到一个符合条件的队列,则会将该消息返回给生产者
  • 当 mandatory 为 false 时:如果交换器无法根据自身类型和路由键找到一个符合条件的队列,则会直接丢弃该消息

4.BindingKey:交换器与队列通过 BindingKey 建立绑定关系

5.Routingkey:基于交换器类型的规则相匹配时,消息被路由到对应的队列中,生产者将消息发给交换器的时候,一般会指定一个 RountingKey,用来指定这个消息的路由规则,当 RountingKey 与 BindingKey

6.Queue:消息队列载体,每个消息都会被投入到一个或多个队列。用于存储路由过来的消息,多个消费者可以订阅同一个消息队列,此时队列会将收到的消息将以轮询 (round-robin)的方式分发给所有消费者,即每条消息只会发送给一个消费者,不会出现一条消息被多个消费者重复消费的情况

7.Consumer:消息消费者,就是接受消息的程序。消费者订阅感兴趣的队列,并负责消费存储在队列中的消息。为了保证消息能够从队列可靠地到达消费者,RabbitMQ 提供了消息确认机制 (messageacknowledgement),并通过 autoAck 参数来进行控制

  • 当 autoAck 为 true 时:此时消息发送出去 (写入TCP套接字) 后就认为消费成功,而不管消费者是否真正消费到这些消息。当 TCP 连接或 channel 因意外而关闭,或者消费者在消费过程之中意外宕机时,对应的消息就丢失。因此这种模式可以提高吞吐量,但会存在数据丢失的风险
  • 当 autoAck 为 false 时:需要用户在数据处理完成后进行手动确认,只有用户手动确认完成后,RabbitMQ 才认为这条消息已经被成功处理,这可以保证数据的可靠性投递,但会降低系统的吞吐量

8.Connection:用于传递消息的 TCP 连接

9.Channel:消息通道,在客户端的每个连接里,可建立多个channel,每个channel代表一个会话任务。RabbitMQ 采用类似 NIO (非阻塞式 IO ) 的设计,通过 Channel 来复用 TCP 连接,并确保每个 Channel的隔离性,就像是拥有独立的 Connection 连接。当数据流量不是很大时,采用连接复用技术可以避免创建过多的 TCP 连接而导致昂贵的性能开销

10.Virtual Host:虚拟主机,一个broker里可以开设多个vhost,用作不同用户的权限分离。RabbitMQ 通过虚拟主机来实现逻辑分组和资源隔离,一个虚拟主机就是一个小型的 RabbitMQ服务器,拥有独立的队列、交换器和绑定关系。用户可以按照不同业务场景建立不同的虚拟主机,虚拟主机之间是完全独立的,你无法将 vhost1 上的交换器与vhost2 上的队列进行绑定,这可以极大的保证业务之间的隔离性和数据安全,默认的虚拟主机名为 /

11.Broker:简单来说就是消息队列服务器实体

2.如何使用RabbitMQ发送消息

exchange接收到消息后,就根据消息的key和已经设置的binding,进行消息路由,将消息投递到一个或多个队列里

  • 客户端连接到消息队列服务器,打开一个channel
  • 客户端声明一个exchange,并设置相关属性
  • 客户端声明一个queue,并设置相关属性
  • 客户端使用routing key,在exchange和queue之间建立好绑定关系
  • 客户端投递消息到exchange

代码如下:

1.导入坐标

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
   <version>2.7.10</version>
</dependency>

2,生产者

public class RabbitProducerFirst {
   public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
       String exchange_name = "first_exchange";
       String route_key = "first_rabbitMQ";

       //创建连接工厂,连接RabbitMQ
       ConnectionFactory connectionFactory = new ConnectionFactory();
       connectionFactory.setHost("192.168.44.137");//端口号、用户名、密码可以使用默认的
       connectionFactory.setPort(5672);
       connectionFactory.setUsername("root");
       connectionFactory.setPassword("root");
       //创建连接
       Connection connection = connectionFactory.newConnection();
       //创建信道
       Channel channel = connection.createChannel();
       //在信道中设置交换器
       channel.exchangeDeclare(exchange_name, BuiltinExchangeType.DIRECT);
       //交换器和队列绑定放到消费者进行
       for (int i = 0; i < 10; i++) {
           String message = "你好 rabbitMQ ,我 是 " + i;
           //消息进行发送
           channel.basicPublish(exchange_name, route_key, false, null, message.getBytes("UTF-8"));
           System.out.println("rabbitMQ 发送消息 key:【" + route_key + "】,内容【" + message + "】");
           Thread.sleep(100);
       }
       //关闭信道
       channel.close();
       //关闭连接
       connection.close();
   }
}

3.消费者

public class RabbitConsumerFirst {

   public static void main(String[] args) throws IOException, TimeoutException {
       String exchange_name = "first_exchange";
       String queue_name = "first_queue";
       String binding_key = "first_rabbitMQ";

       //创建连接工厂,连接RabbitMQ
       ConnectionFactory connectionFactory = new ConnectionFactory();
       connectionFactory.setHost("192.168.44.137");//端口号、用户名、密码可以使用默认的
       connectionFactory.setPort(5672);
       connectionFactory.setUsername("root");
       connectionFactory.setPassword("root");
       //创建连接
       Connection connection = connectionFactory.newConnection();
       //创建信道
       Channel channel = connection.createChannel();
       //在信道中设置交换器
       channel.exchangeDeclare(exchange_name, BuiltinExchangeType.DIRECT);
       //声明队列
       channel.queueDeclare(queue_name, false, false, false, null);
       //交换器和队列绑定
       channel.queueBind(queue_name, exchange_name, binding_key);
       //绑定多个key
       //channel.queueBind(DIRECT_QUEUE, EXCHANGE_NAME, "key3");
       System.out.println("等待 message.....");
       //声明消费者
       Consumer consumer = new DefaultConsumer(channel) {
           @Override
           public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
               String message = new String(body, "utf-8");
               System.out.println("rabbitMQ 接受消息 key:【" + envelope.getRoutingKey() + "】;内容:【" + message + "】");
           }
       };
       //消费者在指定的对队列上消费
       // true 代表是否自动提交
       // queue_name 消费数据的队列
       channel.basicConsume(queue_name, true, consumer);
   }
}

测试:先启动消费者,在启动生产者

3.常用交换器

Exchange type(交换器类型)Default pre-declared names(预声明默认名称)
Direct exchange(直连交换器)(Empty string) and amq.direct
Fanout exchange(扇形交换器)amq.fanout
Topic exchange(主题交换器)amq.topic
Headers exchange(头信息交换器)amq.match (and amq.headers in RabbitMQ)

java代码中交换机的枚举类型如下
在这里插入图片描述

1.直连交换机(如果路由键完全匹配,消息就被投递到相应的队列):直连型交换机(direct exchange)是根据消息携带的路由键(routing key)将消息投递给对应绑定键的队列。直连交换机是一种带路由功能的交换机,一个队列会和一个交换机绑定,除此之外再绑定一个routing_key,当消息被发送的时候,需要指定一个binding_key,这个消息被送达交换机的时候,就会被这个交换机送到指定的队列里面去,同样的一个binding_key也是支持应用到多个队列中的
在这里插入图片描述
直连型交换机图例:
在这里插入图片描述

直连交换机的代码在上面给出,这里就不写了

注意:同一个交换机下消费者多个队列与消费者多个绑定key的情况
在这里插入图片描述

2.扇型交换机(如果交换器收到消息,将会广播到所有绑定的队列上):扇型交换机(fanout exchange)将消息路由给绑定到它身上的所有队列,而不理会绑定的路由键。如果 N 个队列绑定到某个扇型交换机上,当有消息发送给此扇型交换机时,交换机会将消息的拷贝分别发送给这所有的 N 个队列。扇型用来交换机处理消息的广播路由(broadcast routing)
在这里插入图片描述因为扇型交换机投递消息的拷贝到所有绑定到它的队列,所以他的应用案例都极其相似:

  • 大规模多用户在线(MMO)游戏可以使用它来处理排行榜更新等全局事件
  • 体育新闻网站可以用它来近乎实时地将比分更新分发给移动客户端
  • 分发系统使用它来广播各种状态和配置更新
  • 在群聊的时候,它被用来分发消息给参与群聊的用户

扇型交换机图例:
在这里插入图片描述

3.主题交换机(可以使来自不同源头的消息能够到达同一个队列,使用topic交换器时,可以使用通配符):基于消息的 routing key 与绑定到该交换器的队列的 pattern 进行匹配,路由消息到一个或多个队列,常用于复杂的发布/订阅场景,当出现多消费者/应用的场景,消费者选择性地接收消息时,应该考虑使用 topic exchange

  • 主题交换机图例

    • 在这里插入图片描述
  • 约束条件:

    • binding key 中可以存在两种特殊字符 “” 与“#”,用于做模糊匹配,其中 “” 用于匹配一个单词,“#”用于匹配多个单词(可以是零个)
    • routing key 为一个句点号 “.” 分隔的字符串(我们将被句点号 “. ” 分隔开的每一段独立的字符串称为一个单词),如“stock.usd.nyse”、“nyse.vmw”、“quick.orange.rabbit”,binding key 与 routing key 一样也是句点号 “.” 分隔的字符串
  • 使用案例

    • 分发有关于特定地理位置的数据,例如销售点
    • 由多个工作者(workers)完成的后台任务,每个工作者负责处理某些特定的任务
    • 股票价格更新(以及其他类型的金融数据更新)
    • 涉及到分类或者标签的新闻更新(例如,针对特定的运动项目或者队伍)
    • 云端的不同种类服务的协调
    • 分布式架构 / 基于系统的软件封装,其中每个构建者仅能处理一个特定的架构或者系统

4.头交换机(headers 类型的 Exchange 不依赖于 routing key 与 binding key 的匹配规则来路由消息,而是根据发送的消息内容中的 headers 属性进行匹配):头交换机可以视为直连交换机的另一种表现形式。但直连交换机的路由键必须是一个字符串,而头属性值则没有这个约束,它们甚至可以是整数或者哈希值(字典)等。灵活性更强(但实际上我们很少用到头交换机)

  • 工作流程:
    • 绑定一个队列到头交换机上时,会同时绑定多个用于匹配的头(header)
    • 传来的消息会携带header,以及会有一个 “x-match” 参数。当 “x-match” 设置为 “any” 时,消息头的任意一个值被匹配就可以满足条件,而当 “x-match” 设置为 “all” 的时候,就需要消息头的所有值都匹配成功

4.小结

类型名称路由规则
Default自动命名的直交换机
Direct把消息路由到BindingKey和RoutingKey完全匹配的队列中,Routing Key==Binding Key,严格匹配
Fanout发送到该交换机的消息都会路由到与该交换机绑定的所有队列上,可以用来做广播
Topictopic和direct类似,也是将消息发送到RoutingKey和BindingKey相匹配的队列中,只不过可以模糊匹配
Headers根据发送的消息内容中的 headers 属性进行匹配,性能差,基本不会使用
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
RabbitMQ是一个消息代理。它通过发送消息和接收消息来实现消息传递的功能。在介绍RabbitMQ的基础之前,我们需要了解一些常用的管理工具,如rabbitmqctl和rabbitmq-plugins,它们用于管理RabbitMQ服务器。 在开始使用RabbitMQ之前,我们可以通过一个简单的"helloworld"例子来了解它的基本使用方法。我们可以发送一个消息"helloworld"并接收它。同时,这个例子还会涉及到RabbitMQ基本概念,例如交换机和队列。 这些是RabbitMQ基本介绍,它是一个功能强大的消息代理系统,用于实现消息传递。在后续的文章中,我们将会更深入地了解RabbitMQ,并进行性能测试。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [RabbitMQ基础概念详细介绍](https://blog.csdn.net/qq_40704861/article/details/123067104)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [RabbitMQ基本概念和使用](https://download.csdn.net/download/weixin_38678022/14962733)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值