rabbitMQ(1)

AMQP协议解释,官网地址:https://www.rabbitmq.com/tutorials/amqp-concepts

rabbitMQ是个消息队列中间件,它默认的消息传输协议是AMQP 0-9-1,AMQP是 Advanced Message Queuing Protocol的缩写,意思为高级消息队列协议。而且Spring对rabbitMQ的支持也是spring-amqp模块。

该协议有最基本的三个组件:1,publisher(发布者),2,Messaging broker(消息代理),3,consumer(消费者)。

其中消息代理有三个概念:1,消息队列(queue),2,Exchange(交换机),3,bindings(绑定规则)。

所以整个流程就有了,发布者仅将消息发布到消息代理的交换机,然后交换机会根据绑定规则将消息转发到绑定到自身的队列里面,然后通过push或者pull api 送到消费者那里。

一、交换机 Exchange
这个Exchange算是里面最重要的概念之一,我们只需要知道,一个消息代理可以有多个交换机,但是发布者只能绑定一个,而且只能把消息发布到这个交换机里面,然后这个交换机并不存储消息,而是把消息直接推送到队列里面。
发布者发布消息比较简单,就一条线,消息带着参数直接扔给交换机就结束了,但是交换机可以绑定0个或者多个队列,队列是真正存储消息的地方。如何推送消息到队列取决于交换机的类型,及路由规则,路由规则在消费者端也叫绑定规则。
交换机一共四种类型。还有一些属性,其中最重要的属性:1,name 靠这个跟发布者和消费者绑定,2,durability 是否持久化,注意这里的持久化是只这个交换机在消息代理重启之后是否还存在,而不是消息的持久化,3,Auto-delete 这里的自动删除也是 这个交换机在没有队列绑定之后的自动删除而不是消息的自动删除。

1,直接交换机(direct Exchange):该类型的交换机转发消息就靠一个 routing key,如果发布者和消费者绑定都绑定到同一个直接交换机上并且 routing key 一样,那么消息就能从发布者到该交换机然后再到消费者。如果有多个消费者绑定相同的routing key,默认使用轮询策略。
注意,rabbitMQ提前声明了一个默认的交换机,该交换机name属性是空字符串,它是个直接交换机,消费者创建出来所有的没有绑定规则的队列,都直接自动绑定在这个默认的交易锁上。发布者只需要拿这个队列的名字作为routing key 就可以给对应的消费者发送消息。这里如果有多个消费者声明了同一个队列,那么会轮询发布消息。

2,扇形交换机(fanout Exchange):这个交换机不关心routing key,只要有队列绑定在该类型的交换机上,这个队列就可以收到该交换机里面的信息。所以这个类型的交换机适合做广播路由。比如用于排行榜或积分的实时更新,分布式系统里面的配置的实时发布更新。群聊里面分发消息等。

3,主题交换机(Topic Exchange):这个类型的交换机根据路由规则可以讲消息分发到一个或者多个队列里面,常用语消息的组播路由。

4,标头交换机(Headers Exchange):这个类型的交换机不根据routing key 来路由而是根据消息头里面的属性。

二、Queue 队列
队列就是真正存储消息的一个先进先出的数据结构,想要使用队列必须先声明,如果队列不存在就会创建一个,如果存在且队列的属性相同则啥也不做,如果存在但是属性不一样就会保存。
队列的重要属性有:1,name,声明绑定都需要,可以交给消息代理自动生成。2,durable,持久化,消息代理重启后该队列是否还存在,也就是消息是否持久化到硬盘,否则的话只存在内存,重启就没有了。3,exclusive,独有的,仅被一个连接使用的队列,当连接关闭后自动删除该队列。4,auto-delete,当没有消费者绑定时自动删除

三、绑定 bindings,
交换机想要将消息发布到队列里面得有一些路由规则,就是交换机要绑定一个或者多个队列,如果没有绑定可以配置消息是直接丢弃还是放入私信队列。
(为什么不能坚持呢,这个东西很难吗?不难,那么是什么在阻止你?是枯燥乏味,是精力不济,一切都会好起来的。)

四,关于消费者, Consumers
消费者有两种方式从队列里面获取消息一个是订阅,另一个是拉取,其中拉取叫耗费资源不建议使用。每一个消费者都会有个字符串标识叫做 consumerTag,可以用来取消订阅。

消息确认机制有两种,1,消息代理发送消息给消费者 之后接着删除消息(自动确认模型),2,消费者消费完消息之后发送信号给消息代理再删除消息,可以保证消息不丢失(显示确认模型)。如果消费者在确认消息之前挂了,消息代理会将消息传给另外的消费者或者等待一个消费者。

五、关于消息 Message
消息有很多的属性(Attributes)比如 content-type,携带的数据称之为有效负载,可以是空负载。消息可以被持久化到磁盘,但会影响性能。

六,关于连接 Connections
AMQP的连接是长连接 AMQP是应用层协议,使用TCP协议传输,支持TLS,

七,关于通道,Channels
通道就是共享一个TCP连接的轻量级连接,通道与通道之间完全隔离,每个都会有一个ID,通道只存在与连接的上下文中,连接关闭,通道也就没了。对于多线程系统而言,建议每个线程创建一个通道,而不是共享它。

八,关于虚拟主机 Virtual Hosts
同一个消息代理可以通过虚拟主机创建多个隔离的环境共不同的系统使用。

️九,demo代码
根据之前对AMQP协议的简介,我们知道rabbitMQ共有四种exchange,其中最常用的一种就是topic,他的功能最强大,所以一般情况下,推荐直接使用topic。
topic类型的exchange最特别的就是routing key有一定的规则,必须是使用"."连接的多个单词,可以通过* 和 # 来模糊匹配。其中*匹配单个单词,#匹配0个或者多个单词。

1,首先是安装rabbitMq,自己测试推荐使用docker安装:
docker run -it --rm --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:3.13-management
运行之后 进入容器内部运行命令:
rabbitmq-plugins enable rabbitmq_management
开启rabbitMQ界面管理插件,然后访问地址:http://localhost:15672 使用 guest:guest 登陆后可以查看UI管理界面。

2,依赖

<dependencies>
    <dependency>
        <groupId>com.rabbitmq</groupId>
        <artifactId>amqp-client</artifactId>
        <version>5.14.3</version>
    </dependency>
</dependencies>




3,生产者代码:

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

public class EmitLogTopic {

  private static final String EXCHANGE_NAME = "topic_logs";

  public static void main(String[] argv) throws Exception {
    ConnectionFactory factory = new ConnectionFactory();
    factory.setHost("localhost");
    try (Connection connection = factory.newConnection();
         Channel channel = connection.createChannel()) {

        channel.exchangeDeclare(EXCHANGE_NAME, "topic");

        String routingKey = getRouting(argv);
        String message = getMessage(argv);

        channel.basicPublish(EXCHANGE_NAME, routingKey, null, message.getBytes("UTF-8"));
        System.out.println(" [x] Sent '" + routingKey + "':'" + message + "'");
    }
  }
}


运行参数:"kern.critical" "A critical kernel error"

4,消费者代码:

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.DeliverCallback;

public class ReceiveLogsTopic {

  private static final String EXCHANGE_NAME = "topic_logs";

  public static void main(String[] argv) throws Exception {
    ConnectionFactory factory = new ConnectionFactory();
    factory.setHost("localhost");
    Connection connection = factory.newConnection();
    Channel channel = connection.createChannel();

    channel.exchangeDeclare(EXCHANGE_NAME, "topic");
    String queueName = channel.queueDeclare().getQueue(); //这是声明一个默认的队列

    if (argv.length < 1) {
        System.err.println("Usage: ReceiveLogsTopic [binding_key]...");
        System.exit(1);
    }

    for (String bindingKey : argv) {
        channel.queueBind(queueName, EXCHANGE_NAME, bindingKey);
    }

    System.out.println(" [*] Waiting for messages. To exit press CTRL+C");

    DeliverCallback deliverCallback = (consumerTag, delivery) -> {
        String message = new String(delivery.getBody(), "UTF-8");
        System.out.println(" [x] Received '" +
            delivery.getEnvelope().getRoutingKey() + "':'" + message + "'");
    };
    channel.basicConsume(queueName, true, deliverCallback, consumerTag -> { });
  }
}


运行参数可以是:"#" "kern.*" "*.critical" 或者 "kern.critical"
多运行几个消费者代码可以感受到其中的设计。

代码地址:https://gitee.com/luxiao_gitee/rabbitmq.git



 

  • 13
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lx18854869896

和谐社会靠你了,老铁...

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值