RabbitMQ(一)、基础篇

RabbitMQ基础

  • MQ的主要特点
  • 为什么要用MQ?
  • 使用MQ带来的问题
  • RabbitMQ基本特性
  • RabbitMQ工作模型
  • Exchange路由规则
    • 1. Direct Exchange 直连交换机
    • 2. Topic Exchange 主题交换机
    • 3. Fanout Exchange 广播交换机
  • Java RabbitMQ简易使用用例
    • 1. 引入依赖
    • 2. 创建配置类
    • 3. 消费端代码
    • 4. 生产端代码

RabbitMQ是由 Erlang 编写的一种实现了高级消息队列协议(AMQP)协议的开源消息中间件。

MQ的主要特点

用高效可靠的消息传递机制进行与平台无关的数据交流,并基于数据通信来进行分布式系统的集成。通过提供消息传递和消息队列模型,可以在分布式环境下扩展的通信。
RabbitMQ(一)、基础篇_第1张图片

为什么要用MQ?

  • 异步
  • 解耦
  • 削峰

使用MQ带来的问题

  • 系统的可用性降低
  • 提高了系统复杂度
  • 提高了代码复杂性(消息丢失、消息重复、消息一次性)

RabbitMQ基本特性

  • 高可靠:保证消息的可靠性(消息丢失、消息重复、消息一次性)
  • 灵活的路由:通过引入交换机(Exchange)提供了灵活的路由方式,
  • 支持多客户端:为多种语言提供了客户端的操作接口实现(如:Python、Java、PHP、C#、JavaScript、Go、Spring AMQP等)
  • 集群与扩展性:支持集群与扩展
  • 高可用队列:通过镜像队列,使不同集群队列可以相互复制,达到数据的冗余,提供可用性
  • 权限管理:可以进行资源的隔离
  • 插件系统:在不修改原码情况下,可以功能增强或变更。
  • 与Spring集成 Spring AMQP

RabbitMQ工作模型

RabbitMQ(一)、基础篇_第2张图片

  • Broker:部署RabbitMQ的实体服务器。提供一种传输服务,维护一条从生产者到消费者的传输线路,保证消息数据能按照指定的方式传输
  • VHost:Virtual Host,虚拟主机,一个Broker可以有多个虚拟主机,用作不同用户的权限分离。一个虚拟主机持有一组Exchange、Queue和Binding
  • Exchange:消息交换机。指定消息按照什么规则路由到哪个队列Queue
  • Queue:消息队列(底层以数据库-Mnesia进行实现)。消息的载体,每条消息都会被投送到一个或多个队列中
  • Binding:绑定。作用是将Exchange和Queue按照某种路由规则绑定起来
  • Routing Key:路由关键字。Exchange根据Routing Key进行消息传递。定义绑定时指定的关键字称为Binding Key
  • Producer:消息生产者。主要将消息投递到对应的Exchange上面。一般是独立的程序
  • Consumer:消息消费者。消息的接收者,一般是独立的程序
  • Connection:Producer和Consumer与Broker之间的TCP长连接。
  • Channel:消息通道,也称信道。在客户端的每个连接里可以建立多个channel,每个Channel代表一个会话任务。在RabbitMQ Java Client API 中,channel上定义了大量的编程接口

Exchange路由规则

1. Direct Exchange 直连交换机

定义:直连类型的交换机与一个队列绑定时,需要指定一个明确的binding key。

路由规则:发现消息到直连类型的交换机时,只有routing key和binding key完全匹配时,绑定的队列才能收到消息。
RabbitMQ(一)、基础篇_第3张图片

channel.basicPublish("DirectExchangeName", "binging key", null, msg.getBytes());

2. Topic Exchange 主题交换机

定义:主题类型的交换机与一个队列绑定时,可以指定按模式匹配的routing key。

匹配通配符有两个,* 代表匹配一个单词。# 代表匹配零个或者多个单词。单词与单词之间用.隔开。如:

  • kiss.*:匹配 kiss 后有一个单词,如kiss.my、kiss.you
  • *.kiss:匹配 kiss 前有一个单词,如my.kiss、you.kiss
  • kiss.#:匹配 kiss 后有零个或者多个单词,如kiss.my、kiss.my.you
  • #.kiss:匹配 kiss 前有零个或者多个单词,如my.kiss、my.you.kiss

路由规则:发送消息到主题类型的交换机时,routing key 符合 binding key 的规则时,绑定的队列才能收到消息。
RabbitMQ(一)、基础篇_第4张图片

// 队列1和队列3能收到消息
channel.basicPublish("TopicExchangeName", "kiss.my", null, msg.getBytes()); 
// 队列2和队列4能收到消息
channel.basicPublish("TopicExchangeName", "my.kiss", null, msg.getBytes()); 
// 只有队列3能收到消息
channel.basicPublish("TopicExchangeName", "kiss.my.you", null, msg.getBytes());
// 只有队列4能收到消息
channel.basicPublish("TopicExchangeName", "my.you.kiss", null, msg.getBytes());

3. Fanout Exchange 广播交换机

定义:广播类型的交换机与一个队列 绑定时,不需要指定binding key。

路由规则:当消息发送到广播类型的交换机时,不需要指定routing key,所有与之绑定的队列都能收到消息。
RabbitMQ(一)、基础篇_第5张图片

// 3个队列都会收到消息
channel.basicPublish("FanoutExchangeName", "", null, msg.getBytes());

Java RabbitMQ简易使用用例

1. 引入依赖

	<dependency>
		<groupId>com.rabbitmqgroupId>
		<artifactId>amqp-clientartifactId>
		<version>5.7.3version>
	dependency>

2. 创建配置类

public class RabbitMQConfig {
    private RabbitMQConfig() {
    }

    // 主机IP
    public static final String HOST = "127.0.0.1";
    // 主机port
    public static final Integer PORT = 5672;
    // 主机port
    public static final String VHOST = "/";
    // 主机port
    public static final String USERNAME = "admin";
    // 主机port
    public static final String PASSWORD = "admin";
    // 交换机名称
    public static final String DIRECT_EXCHANGE = "direct_exchange";
    // 队列名称
    public static final String QUEUE_NAME = "direct_queue";
    // Routing key
    public static final String ROUTING_KEY = "kiss";
}

3. 消费端代码

import com.rabbitmq.client.*;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

/**
 * 消费者
 */
public class MessageConsumer {

    public static void main(String[] args) throws IOException, TimeoutException {
        ConnectionFactory factory = new ConnectionFactory();
        // 设置主机IP
        factory.setHost(RabbitMQConfig.HOST);
        // 设置端口
        factory.setPort(RabbitMQConfig.PORT);
        // 设置 Vhost
        factory.setVirtualHost(RabbitMQConfig.VHOST);

        // 设置访问用户
        factory.setUsername(RabbitMQConfig.USERNAME);
        factory.setPassword(RabbitMQConfig.PASSWORD);
        // 建立连接
        Connection connection = factory.newConnection();
        // 创建Channel消息通道
        Channel channel = connection.createChannel();

        /**
         * 声明交换机,参数String exchange, String type, boolean durable, boolean autoDelete, Map arguments
         *
         * String exchange:指定交换机名称
         * String type:路由类型,direct、topic、fanout
         * boolean durable:是否持久化
         * boolean autoDelete:是否自动删除
         * Map arguments:其他参数
         */
        channel.exchangeDeclare(RabbitMQConfig.DIRECT_EXCHANGE, "direct", false, false, null);

        /**
         * 声明队列,参数String queue, boolean durable, boolean exclusive, boolean autoDelete, Map arguments
         * String queue:指定队列名称
         * boolean durable:是否持久化
         * boolean exclusive:是否排他,既是否创建者私有,如果为true,会对当前队列加锁,其他通道不能访问,并且
         * 					 在连接关闭时会自动删除,不受持久化和自动删除限制
         * boolean autoDelete:是否自动删除
         * Map arguments:其他参数
         */
        channel.queueDeclare(RabbitMQConfig.QUEUE_NAME, false, false, false, null);

        /**
         * 绑定交换和队列,参数String queue, String exchange, String routingKey, Map arguments
         */
        channel.queueBind(RabbitMQConfig.QUEUE_NAME, RabbitMQConfig.DIRECT_EXCHANGE, RabbitMQConfig.ROUTING_KEY, null);

        // 创建消费者
        Consumer consumer = new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                // 获取消息
                String msg = new String(body, "UTF-8");
                System.out.println("consumer message:" + msg);
            }
        };

        // 开始获取消息String queue, boolean autoAck, Consumer callback
        channel.basicConsume(RabbitMQConfig.QUEUE_NAME, true, consumer);
    }
}

4. 生产端代码

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

/**
 * 生产者
 */
public class MessageProvider {
    public static void main(String[] args) {
        ConnectionFactory factory = new ConnectionFactory();
        // 设置主机IP
        factory.setHost(RabbitMQConfig.HOST);
        // 设置端口
        factory.setPort(RabbitMQConfig.PORT);
        // 设置 Vhost
        factory.setVirtualHost(RabbitMQConfig.VHOST);

        // 设置访问用户
        factory.setUsername(RabbitMQConfig.USERNAME);
        factory.setPassword(RabbitMQConfig.PASSWORD);
        try (
                // 建立连接
                Connection connection = factory.newConnection();
                // 创建Channel消息通道
                Channel channel = connection.createChannel();
        ) {
            String msg = "阁下可是常山赵子龙";
            channel.basicPublish(RabbitMQConfig.DIRECT_EXCHANGE, RabbitMQConfig.ROUTING_KEY, null, msg.getBytes("UTF-8"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

你可能感兴趣的:(#,消息中间件,rabbitmq)