RabbitMQ(一)基础

1,370 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第5天,点击查看活动详情

啥是RabbitMQ

消息中间件

创始人1983 MIT(麻省)

image-20220705213245693

一个pc发信息到另一个pc,我使用TCP或者http你就必须使用TCP或者http

我使用啥你都用啥,然后这个小伙子想,能不能不这样

集成的多了,一个系统内部实现的通信协议就很多了

减少复杂度只用一种协议

就是上图的Bus

就是MQ,集成到一起

各种公司有自己的MQ,这样下来又复杂了

2007RabbitMQ的第一年

Rabbit是兔子,跑的快,繁殖的快

image-20220705214749898

(创始人用的ErLang,天生支持高并发)

image-20220706130346519

使用MQ

image-20220706130943869

image-20220706131009705

  1. MQ可以把同步变成异步
  2. 系统解耦合

image-20220706132001482

解耦之后:

image-20220706132100220

  1. 流量削峰(队列的特性)

就相当于火车站售票员,就算火车站人再多,也是一个窗口一个窗口的(一个个队列)

峰值的访问量平摊到后面的时间

image-20220706132510772

问题:

  1. MQ必须不能挂,整个系统的可用性降低
  2. 系统的复杂度增加

安装可以看这个

blog.csdn.net/weixin_4377…

结果是:

image-20220706194418244

查看用户

rabbitmqctl.bat list_users

image-20220706194502256

可以访问:

http://localhost:15672

image-20220706195004303

工作模型

image-20221003143722655

高可靠

灵活的路由

多客户端(多种语言)

集群与扩展性

高可用队列

权限管理(每种用户有自己的权限)

插件系统

可靠性

与Spring集成

image.png

运行MQ的软件我们叫做Broker,这个单词的意思的“中介,代理”

Producer和Consumer要与Broker建立连接TCP长连接,太消耗资源,所以在TCP的长连接里建立了虚连接channel,我们把这个叫做信道,通信完之后释放一个个channel

发送过来的消息存queue中

Exchange是交换机,本质是绑定列表,实现消息灵活分发

默认端口5672

可以在一台服务器上运行多个Broker,但是没有必要

可以在一个个Broker里创建多个VHost

不同用户用不同的Vhost,他们之间是相互隔离的

image-20220706135224867

Exchange路由消息详解

交换机类型

1、Direct Exchange直连路由的交换机

image.png

channel.basicPublish(exc_name,"spring",msg)

(exchange的名字,路由键名字,消息)

只有当router_key和binding_key一样的时候,消息才会送到对应的queue中

2、TopicExchange主题类型的交换机

符号*表示一个单词,符号#表示0个或者多个单词

image.png

就比如,第一个binding key匹配的路由键是junior或者junior.a.b或者junior.a.b.c.d.e

比如:

channel.basicPublish("myexc","junior.abc.jvm","msg3");

这条消息能发送给哪个队列?

答案是只有第一个队列

3、FanoutExchange风扇交换

image.png 没有绑定的

广播类型的交换机

RabbitMQ的基本使用

安装ErLang环境

不演示了

注意版本对应

docker安装教程:gper.club/articles/7e…

流程

  1. 引入依赖
  2. 消费者
  3. 生产者
  4. 参数详解

实操

  1. 引入依赖
<dependency>
    <groupId>com.rabbitmq</groupId>
    <artifactId>amqp-client</artifactId>
    <version>5.6.0</version>
</dependency>
  1. 消费者

谁使用,谁管理,所以在消费者里创建一些

import com.rabbitmq.client.*;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.concurrent.TimeoutException;
​
public class MyConsumer {
    private final static String EXCHANGE_NAME = "SIMPLE_EXCHANGE";
​
    private final static String QUEUE_NAME = "SIMPLE_QUEUE";
​
    public static void main(String[] args) throws IOException, TimeoutException {
        ConnectionFactory factory = new ConnectionFactory();
        // 连接IP
        factory.setHost("127.0.0.1");
        // 默认监听端口
        factory.setHost("5672");
        // 虚拟机
        factory.setVirtualHost("/");
​
        // 设置访问的用户
        factory.setUsername("guest");
        factory.setPassword("guest");
        // 建立连接
        Connection conn = factory.newConnection();
        // 创建消息通道
        Channel channel = conn.createChannel();
​
        // 声明交换机
        // String exchange, String type, boolean durable, boolean autoDelete, Map<String, Object> args
        // 交换机名字         种类          是否持久化         是否自动删除          其他参数
        channel.exchangeDeclare(EXCHANGE_NAME, "direct", false, false, null);
​
        // 声明队列
        // String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> args
        // 队列名字        是否持久化         是否重复定义         是否自动删除           其他参数
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);
        System.out.println("Waiting for message....");
​
        // 绑定队列和交换机
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "gupao.best");
​
        // 创建消费者
        Consumer consumer = new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties basicProperties, byte[] body ) throws UnsupportedEncodingException {
                String msg = new String(body, "UTF-8");
                System.out.println("Received message:'"+msg+"'");
                System.out.println("consumerTag:"+consumerTag);
                System.out.println("deliveryTag:"+envelope.getDeliveryTag());
            }
        };
​
        // 开始获取消息
        // String queue, boolean autoAck, Consumer callback
        channel.basicConsume(QUEUE_NAME, true, consumer);
    }
}
  1. 生产者
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
​
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeoutException;
​
public class MyProducer {
​
    private final static String EXCHANGE_NAME = "SIMPLE_EXCHANGE";
​
    public static void main(String[] args) throws IOException, TimeoutException {
        ConnectionFactory factory = new ConnectionFactory();
        // 连接IP
        factory.setHost("127.0.0.1");
        // 默认监听端口
        factory.setHost("5672");
        // 虚拟机
        factory.setVirtualHost("/");
​
        // 设置访问的用户
        factory.setUsername("guest");
        factory.setPassword("guest");
        // 建立连接
        Connection conn = factory.newConnection();
        // 创建消息通道
        Channel channel = conn.createChannel();
        // 发送消息
        String msg = "Hello world, Rabbit MQ!";
​
        // String exchange, String routingKey, BasicProperties props, byte[] body
        channel.basicPublish(EXCHANGE_NAME, "gupao.best", null, msg.getBytes());
        channel.close();
        conn.close();
    }
}

\