RabbitMQ学习笔记

RabbitMQ笔记

主流MQ简单了解

衡量标准

  1. 服务性能
  2. 数据存储
  3. 集群架构
ActiveMQ

适用于中小型企业,但在高并发情况下效率较低,不适用与并发

Kafka

高吞吐、速度快,但不支持事务,不能保证消息的可靠性
一般用于日志传输,不适用于事务场景

RocketMQ

阿里开发的商业性MQ,商业版收费
高吞吐、高可用
适用于大规模分布式

RabbitMQ

性能略差于RocketMQ,高于ActiveMQ,且支持大规模分布式,可靠性高,稳定性好

基于AMQP协议开发

AMQP核心概念

  1. Server:又称Broker,接收客户端连接,实现AMQP实体服务
  2. Connection:连接,应用程序与Broker的网络连接
  3. Channel:网络信道,几乎所有操作都在Channel中进行操作,是进行消息读写的通道。客户端可建立多个Channel,每个Channel代表一个会话任务
  4. Message:消息,服务器和应用程序之间传送的数据,又Properties和Body组成。Properties可以对消息进行修饰,如延迟时间,消息优先级等,Body中就是存放消息内容

包含几种属性:

correlationId:消息唯一ID

deliverMode:2为持久化消息

expiration:过期时间

headers:消息头,可以存放自定义消息

  1. Virtual host:虚拟地址,用于逻辑隔离,最上层的消息路由。一个VH里可以有若干的Exchange和Queue,同一个VH里不能有相同名称的Exchange和Queue
  2. Exchange:交换机,接收消息,根据路由键转发到绑定的队列上

包含几种属性:

Name:交换机名称

Type:交换机类型direct、topic、fanout、headers

Durability:是否持久化

Auto Delete:当最后一个绑定到Exchange上的队列删除后,自动删除该Exchange

Internal:当前Exchange是否用于RabbitMQ内部使用,默认false

Arguments:扩展参数,扩展AMQP协议自定义化使用

  1. Binding:Exchange和Queue之间的虚拟连接,Binding中可以包含routing key
  2. Routing key:一个路由规则,虚拟机可用它来确定如何路由一个特定消息
  3. Queue:消息队列,保存消息并把它们转发给消费者

包含几种属性:

Name:队列名称

Durability:是否持久化

Auto Delete:当最后一个监听删除后,自动删除该Queue

基本命令
  1. rabbitmqctl(控制相关,队列/交换机/集群等操作)
  2. rabbitmq-plugins(rabbitmq插件)
  3. rabbitmq-server(服务相关操作,如启动,停止)
消息模式
普通队列

在这里插入图片描述


//初始化连接
public static Connection getConnection() throws IOException, TimeoutException {
   
        ConnectionFactory connectionFactory = new ConnectionFactory();
        //服务ip
        String HOST = "127.0.0.1";
        //默认端口号
        Integer PORT = 5672;
        //虚拟主机名称
        String VIRTUALHOST = "/vhost_z";
        //用户名
        String USERNAME = "user_z";
        //密码
        String PASSWORD = "123";
        connectionFactory.setHost(HOST);
        connectionFactory.setPort(PORT);
        connectionFactory.setUsername(USERNAME);
        connectionFactory.setPassword(PASSWORD);
        connectionFactory.setVirtualHost(VIRTUALHOST);
        Connection connection = connectionFactory.newConnection();
        return connection;
 }
 
//生产者
public static void main(String[] args) {
   
     try {
   
         //1.获取连接
         Connection connection = ConnectionUtils.getConnection();
         //2.获取通道
         Channel channel = connection.createChannel();
         //3.声明队列 可以在消费者端声明
         //channel.queueDeclare("test_queue",false,false,false,null);
         String msg = "sent message!";
         //4.发送消息 如果不声明交换机 那么消息会自动发到amqp的默认交换机上
         // 默认交换机会根据routingkey去找匹配的队列
         channel.basicPublish("","test_queue",null,msg.getBytes());
         //5.关闭通道和连接
         channel.close();
         connection.close();
     } catch (Exception e) {
   
         e.printStackTrace();
     }
 }

//消费者
 public static void main(String[] args) {
   
        try {
   
            //1.获取连接
            Connection connection = ConnectionUtils.getConnection();
            //2.创建通道
            Channel channel = connection.createChannel();
            //3.声明队列
            channel.queueDeclare("test_queue",false,false,false,null);
            //消费者对象
            DefaultConsumer defaultConsumer = 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("consumer1===="+msg);
                }
            };
            //4.监听队列
            channel.basicConsume("test_queue",false,defaultConsumer);
        } catch (Exception e) {
   
            e.printStackTrace();
        }
    }
工作队列

RabbitMQ学习笔记_第1张图片

QOS(服务质量保证),在非自动确认消息的前提下(一定要手动确认消息),如果一定数目的消息未被确认前,不进行消费新的消息

//生产者
 public static void main(String[] args) {
   
        try {
   
            //1.获取连接
            Connection connection = ConnectionUtils.getConnection();
            //2.获取通道
            Channel channel = connection.createChannel();
            //是否持久化 true 是
            boolean flag = true;
            //3.声明队列
            channel.queueDeclare("test_queue",flag,false,false,null);
            for (int i=0;i<50;i++){
   
                String msg = "sent message i= "+i+"!";
                //4.发送消息
                channel.basicPublish("","test_queue",null,msg.getBytes());
            }
            //5.关闭通道和连接
            channel.close();
            connection.close();
        } catch (Exception e) {
   
            e.printStackTrace();
        }
    }
    
    //消费者1
    public static void main(String[] args) {
   
        try {
   
            Thread.sleep(2000);
            //1.获取连接
            Connection connection = ConnectionUtils.getConnection();
            //2.创建通道
            Channel channel = connection.createChannel();
            //3.声明队列
            channel.queueDeclare("test_queue",true,false,false,null);
            //保证只发一个消息 需要手动应答 默认工作队列使用轮询,给连个消费者均分消息
            //若一个消费者消费的快,想提高效率 那么可以用手动应答 
            //修改basicQos限制每次消费1条消息 谁先消费完 就应答 再让生产者发送一条消息
            channel.basicQos(1);
            DefaultConsumer defaultConsumer = 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("consumer1===="+msg);
                    //手动应答
                    channel.basicAck(envelope.getDeliveryTag(),false);
                }
            };
            //4.监听队列
            channel.basicConsume("test_queue",false,defaultConsumer);
        } catch (Exception e) {
   
            e.printStackTrace();
        }
    }
    
    //消费者2
	public static void main(String[] args) {
   
        try {
   
            Thread.sleep(1000);
            //1.获取连接
            Connection connection = ConnectionUtils.getConnection();
            //2.创建通道
            Channel channel = connection.createChannel();
            //3.定义消费者
            channel.queueDeclare("test_queue",false,false,false,null);
            //保证只发一个消息
            channel.basicQos(1);
            DefaultConsumer defaultConsumer = 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("consumer2===="+msg);
                    channel.basicAck(envelope.getDeliveryTag(),false);
                }
            };
            //4.监听队列
            channel.basicConsume("test_queue",true,defaultConsumer);
        } catch (Exception e) {
   
            e.printStackTrace();
        }
    }
消息应答和消息持久化

在自动应答模式下,消息发送完后消息就会删除,但此时消费者服务宕机,消息就会丢失
手动应答模式,在消息消费完,应答之后消息才会删除,但内存是断电清空,为了防止MQ服务器宕机,可以将消息持久化,将队列也声明为持久化(已声明的队列无法再次修改属性)

	//手动应答 将第二个参数设为false
	channel.basicConsume("test_queue",flase,defaultConsumer);
	
	//生产者
  	public static void main(String[] args) {
   
        try {
   
            //1.获取连接
            Connection connection = ConnectionUtils.getConnection();
            //2.获取通道
            Channel channel = connection.createChannel();
            String exchangeName = "test_ack_exchange";
            String routingKey = "ack.info";
            //5.发送消息
            for(int i = 0;i<5;i++){
   
                Map<String,Object> headers = new HashMap();
                String msg = "sent ack message is info" + i;
                headers.put("num",i);
                AMQP.BasicProperties basicProperties = new AMQP.BasicProperties.Builder().
                        deliveryMode(2).//消息持久化设置
                        contentEncoding("utf-8").
                        headers(headers).
                        build();
                channel.basicPublish(exchangeName,routingKey,true,basicProperties,msg.getBytes());
            }
            //6.关闭通道和连接
            channel.close();
            connection.close();
        } catch (Exception e) {
   
            e.printStackTrace();
        }
    }
	
	//消费者
	public static void main(String[] args) {
   
        try {
   
            //1.获取连接
            Connection connection = ConnectionUtils.getConnection();
            //2.创建通道
            Channel channel = connection.createChannel();
            String exchangeName = "test_ack_exchange";
            String queueName = "test_ack_queue";
            String routingKey = "ack.#";
            //3.声明队列和交换机
            channel.exchangeDeclare(exchangeName,"topic",true,false,false,null);
            channel.queueDeclare(queueName,false,false,false,null);
            //4.绑定队列和路由key
            channel.queueBind(queueName,exchangeName,routingKey);
            //保证只发一个消息 
            //第一个参数指消息总数量 
            //第二个参数时每次消费次数 
            //第三个参数 是否将整个channel都设置成该配置
            channel.basicQos(0,1,false);
            DefaultConsumer defaultConsumer = new DefaultConsumer(channel){
   
                @Override
                public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
   
                    Integer num = (Integer) properties.getHeaders().get("num");
                    System.out.println("body="+new String(body,"utf-8") +" i="+num);
                    String msg = new String(body,"utf-8");
                    if(num.equals(0))

你可能感兴趣的:(RabbitMQ学习笔记)