RabbitMQ 概念和基本用法

一、互联网大厂为什么选择RabbitMQ

①RabbitMQ是使用Erlang语音编写的,并且基于AMQP协议;
②它是一个开源的消息代理和队列服务器,可以通过普通协议实现夸语言、跨平台之间的高性能、高可靠、可用性数据共享服务。
③可以提供可靠的投递模式(confirm)、返回模式(return)
④与springAMQP整合完美,提供丰富的api
⑤集群模式丰富、表达式配置、HA模式、镜像队列模型

二、RabbitMQ 是如何做到高性能的

核心就是Erlang语言,这种语言具有和原生socket一样的低延迟,使得具有高性能特性

三、什么是AMQP高级协议

AMQP(即Advanced Message Queuing Protocol):二进制协议,通用消息队列协议规范,高级消息队列协议

在这里插入图片描述
Server: 又称Broker,接受客户端连接实现AMQP实体服务
Connection: 应用程序与Broker的网络连接
Channel: 网络信道,几乎所有的操作都在Channel中进行,Channel是进行消息读写的通道。客户端可以建立多个channel,每个channel代表一个会话任务。

Message: 消息服务器和应用程序之间传送的数据,由properties和Body组成。properties可以对消息进行修饰,比如消息的优先级、延迟等高级特性;body则就是消息的内容。

Virtual host: 虚拟地址,用于进行逻辑隔离,最上层的消息路由。一个virtual host里面可以有若干个Exchange和Queue,同一个virtual host里面不能出现相同名称的Exchange和Queue。
Exchange: 交换机,接收消息;根据由键转发消息到绑定的队列。
Binding: Exchange和Queue进行虚拟连接,binding可以包含routing key。
Routing key: 一个路由规则,虚拟机通过交换机类型和路有规则确定特定的消息队列的。

四、RabbitMQ的整体架构

在这里插入图片描述
生产者将消息投递到Exchange,然后Exchange按照Routing key规则路由到绑定了对应的Queue中,消费者监听对应的Queue就可以接收到消息了;中间的server就是一个broker对象。

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

  • direct:直连方式,所有发送到exchange都直接转发到相同routingKey的Queue上(默认就是direct模式,按照routekey查找队列名,找不到将被抛弃)
  • topic:所有发送到topic的消息被转发到所有关心Routkey中指定的topic的Queue上(exchange可以按照Queue的路由键routingKey模糊匹配)
  • fanout:这种类型下的routingKey是失效的,生成者直接将消息转发至交换机下所有绑定的队列上,这种类型也是速度最快的。

Durability:是否需要持久化 ,默认为 true 表示持久化
Auto Delete:当最后一个绑定到Exchange上的队列删除后,自动删除该Exchange
Internal:当前Exchange是否用于RabbitMQ内部使用,默认为False
Arguments:扩展参数,用于扩展AMQP协议自制定化使用Name:交换机名称

五、安装和使用

rabbitmq-server start & //后台开启服务
rabbitmq-plugins enable rabbitmq_management //安装页面管理端插件 页面端口15672
rabbitmqctl start/stop_app/status 

1、交换机类型为:direct直接转发

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;

public class Product {

    public static void main(String[] args) throws IOException, TimeoutException {
        //创建一个连接工厂,并配置
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("192.168.25.128");
        connectionFactory.setPort(5672);
        connectionFactory.setVirtualHost("/");

        //创建一个连接
        Connection connection = connectionFactory.newConnection();
        //创建一个channel用通信
        Channel channel = connection.createChannel();

        //发布一条消息
        String msg = "test one message!";
        Map<String, Object> map = new HashMap<>();
        map.put("key1","value1");
        AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder()
                .headers(map) //在properties中放置一些信息
                .expiration("10000")//设置这个消息10秒后将在队列中消失
                .build();
        channel.basicPublish("test_direct_exchange","test_direct",properties,msg.getBytes());

        channel.close();
        connection.close();
    }
}
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;

public class Customer {

    public static void main(String[] args) throws IOException, TimeoutException {
        //创建一个连接工厂,并配置
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("192.168.25.128");
        connectionFactory.setPort(5672);
        connectionFactory.setVirtualHost("/");
        connectionFactory.setAutomaticRecoveryEnabled(true);//自动重连
        connectionFactory.setNetworkRecoveryInterval(3000);//自动重连时间间隔3秒

        //创建一个连接
        Connection connection = connectionFactory.newConnection();
        //创建一个channel用通信
        Channel channel = connection.createChannel();

        //声明一个test_direct_exchange名称、类型为direct、持久化的交换机
        String exchangName = "test_direct_exchange";
        channel.exchangeDeclare(exchangName,"direct",true);
        //声明一个队列
        String queueName = "test_direct_queue";
        channel.queueDeclare(queueName,true,false,false,null);
        //将队列绑定到交换机上,按照键test_direct路由
        channel.queueBind(queueName,exchangName,"test_direct");
        //创建消费者
        Consumer consumer = new DefaultConsumer(channel){
            @Override //处理接受到的消息
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.err.println("接收到message:"+ new String(body,"UTF-8"));
                System.err.println("接收到properties属性:"+ properties.getHeaders().get("key1"));

            }
        };

        //监听队列,回调消费处理方法方法
        channel.basicConsume(queueName,true,consumer);
    }
}

2、交换机类型为:topic exchange可以按照Queue的路由键模糊匹配
在这里插入图片描述

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;

public class TopicProduct {

    public static void main(String[] args) throws IOException, TimeoutException {
        //创建一个连接工厂,并配置
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("192.168.25.128");
        connectionFactory.setPort(5672);
        connectionFactory.setVirtualHost("/");
        connectionFactory.setAutomaticRecoveryEnabled(true);//自动重连
        connectionFactory.setNetworkRecoveryInterval(3000);//自动重连时间间隔3秒

        //创建一个连接
        Connection connection = connectionFactory.newConnection();
        //创建一个channel用通信
        Channel channel = connection.createChannel();

        //声明一个test_topic_exchange名称、类型为topic、持久化的交换机
        String exchangName = "test_topic_exchange";
        //路由键规则,*表示占一位、#表示模糊查询如数据库后置%效果
        String routingKey1 = "topic.update";
        String routingKey2 = "topic.save";
        String routingKey3 = "topic.create.abc";
        String msg = "生产者发送topic消息!";
        channel.basicPublish(exchangName,routingKey1,null,msg.getBytes());
        channel.basicPublish(exchangName,routingKey2,null,msg.getBytes());
        channel.basicPublish(exchangName,routingKey3,null,msg.getBytes());
        channel.close();
        connection.close();
    }
}
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;

public class TopicCustomer {

    public static void main(String[] args) throws IOException, TimeoutException {
        //创建一个连接工厂,并配置
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("192.168.25.128");
        connectionFactory.setPort(5672);
        connectionFactory.setVirtualHost("/");
        connectionFactory.setAutomaticRecoveryEnabled(true);//自动重连
        connectionFactory.setNetworkRecoveryInterval(3000);//自动重连时间间隔3秒

        //创建一个连接
        Connection connection = connectionFactory.newConnection();
        //创建一个channel用通信
        Channel channel = connection.createChannel();

        //声明一个test_topic_exchange名称、类型为topic、持久化的交换机
        String exchangName = "test_topic_exchange";
        String exchangeType = "topic";
        //路由键规则,*表示占一位、#表示模糊查询如数据库后置%效果
        String routingKey = "topic.*";
        channel.exchangeDeclare(exchangName,exchangeType);
        //声明一个队列
        String queueName = "test_topic_queue";
        channel.queueDeclare(queueName,false,false,false,null);
        channel.queueBind(queueName,exchangName,routingKey);

        channel.basicConsume(queueName, true, new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.err.println(new String(body,"UTF-8"));
            }
        });

    }
}

3、交换机类型:fanout ,如下只要是相同的exchange不管routingkey都将接受到消息

public class FanoutCustomer {

    public static void main(String[] args) throws IOException, TimeoutException {
        //创建一个连接工厂,并配置
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("192.168.25.128");
        connectionFactory.setPort(5672);
        connectionFactory.setVirtualHost("/");
        connectionFactory.setAutomaticRecoveryEnabled(true);//自动重连
        connectionFactory.setNetworkRecoveryInterval(3000);//自动重连时间间隔3秒

        //创建一个连接
        Connection connection = connectionFactory.newConnection();
        //创建一个channel用通信
        Channel channel = connection.createChannel();

        //声明一个test_fanout_exchange名称、类型为fanout、持久化的交换机
        String exchangName = "test_fanout_exchange";
        channel.exchangeDeclare(exchangName,"fanout",true);
        //声明一个队列
        String queueName1= "test_fanout_queue1";
        String queueName2= "test_fanout_queue2";
        channel.queueDeclare(queueName1,true,false,false,null);
        channel.queueDeclare(queueName2,true,false,false,null);
        //将队列绑定到交换机上,按照键test_fanout路由(其实这个键不起作用)
        channel.queueBind(queueName1,exchangName,"test_fanout1");
        channel.queueBind(queueName2,exchangName,"test_fanout2");
        //创建消费者
        Consumer consumer = new DefaultConsumer(channel){
            @Override //处理接受到的消息
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.err.println(new String(body,"UTF-8"));
            }
        };

        //监听队列,回调消费处理方法方法
        channel.basicConsume(queueName1,true,consumer);
        channel.basicConsume(queueName2,true,consumer);
    }
}
public class FanoutProduct {

    public static void main(String[] args) throws IOException, TimeoutException {
        //创建一个连接工厂,并配置
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("192.168.25.128");
        connectionFactory.setPort(5672);
        connectionFactory.setVirtualHost("/");

        //创建一个连接
        Connection connection = connectionFactory.newConnection();
        //创建一个channel用通信
        Channel channel = connection.createChannel();

        //发布一条消息,设置的随意路由键
        String msg = "test one message!";
        channel.basicPublish("test_fanout_exchange","test_fanout",null,msg.getBytes());

        channel.close();
        connection.close();
    }
}

六、管理端使用

针对于消费端开启手动签收消息(ACK),即 spring.rabbitmq.listener.simple.acknowledge-mode=manual

  • 1、生产者发送成功消息到broker,消息未被消费,ready=1、unacked=0、total=1 如下图
    在这里插入图片描述

  • 2、生产成功发送消息到broker,然后消费端消费但未确认(ACK动作),ready=0、unacked=1、total=1 ,由于消费端未ACK,消息将重回MQ消息队列。
    如下图:
    在这里插入图片描述

  • 3、生产成功发送消息到broker,然后消费端成功消费,ready=0、unacked=0、total=0 都为0如下图
    在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值