RabbitMQ

基本介绍

RabbitMQ是一个队列 该队列中用于存放消息
​
常见的消息队列
ActiveMQ        实现了JDK的一个规范
RabbitMQ        获取较活跃 管理完善 支持并发在几万级别
RocketMQ        阿里巴巴 支持的并发在几十万级别
Kafka           最开始用于日志收集 因日志的先后顺序严格 就用来做消息队列 支持几十万级别并发

基本作用

消峰填谷

RabbitMQ是一个消息队列 所以消息以队列的方式进行存储 大量请求到来时 消费者同时消费一定数量的消息 其余消息进行等待

异步通信

常见的消息消费为串行链式消费 其中分为多个步骤 而RabbitMQ并行执行这些步骤 效率得到了提升

模块解耦

常见的模块直接调用其他模块 耦合性很强 RabbitMQ将模块信息存入队列 当模块需要进行模块调用时 去消息队列中查询并调用相应模块

基本安装

1.安装环境
yum install epel-release
yum install erlang
2.下载RabbitMQ
wget http://www.rabbitmq.com/releases/rabbitmq-server/v3.6.15/rabbitmq-server-3.6.15-1.el7.noarch.rpm
3.安装RabbitMQ
yum install rabbitmq-server-3.6.15-1.el7.noarch.rpm
4.设置开机启动
systemctl enable rabbitmq-server.service
5.查看服务状态
systemctl status rabbitmq-server.service
6.启动服务
systemctl start rabbitmq-server.service
​
停止服务
systemctl stop rabbitmq-server.service
查看当前所有用户
rabbitmqctl list_users
查看guest用户权限
rabbitmqctl list_user_permissions guest
删除guest账户
rabbitmqctl delete_user guest
添加新用户
rabbitmqctl add_user buliyat 123
设置角色
rabbitmqctl set_user_tags buliyat administrator
设置权限
rabbitmqctl set_permissions -p / buliyat ".*" ".*" ".*"
查看用户权限
rabbitmqctl list_user_permissions buliyat
开启web管理端
rabbitmq-plugins enable rabbitmq_management

通信模型

HelloWorld(点对点)

生产者将消息发送到队列 消费者从队列中获取消息 
public class Producer {

    private static final String QUEUE_NAME = "hello";
    public static void main(String[] args) throws IOException, TimeoutException {

        Connection conncetion = RabbitMQUtils.getConncetion();
        Channel channel = conncetion.createChannel();
        // 参数:队列名 持久化 排外 自动删除 创建队列自带参数
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
        // 参数:交换机名 路由key 发送消息附带键值对消息
        channel.basicPublish("",QUEUE_NAME,null,"Helloworld模型".getBytes("UTF-8"));
    }
}
public class Consumer {

    private static final String QUEUE_NAME = "hello";
    public static void main(String[] args){
        Connection connection = RabbitMQUtils.getConnection();
        final Channel channel = connection.createChannel();
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
        DefaultConsumer defaultConsumer = new DefaultConsumer(channel){

            @Override
            public void handlerDelivery(String consumerTag, Envelope envolope,AMQP.BasicProperties properties, byte[] body) throws IOException{
                String str = new String(body,"UTF-8");
                System.out.println("接收到:"+str);
                channel.basicAck(envelop.getDeliveryTag(),true);
            }
        };
        channel.basicConsume(QUEUE_NAME,false,defaultConsumer);
    }
}

work

生产者将消息发送到队列 队列将消息分发到不同消费者(均分不重复)
public class Producer {

    public static void main(String[] args){

        Connection connection = RabbitMQUtils.getConnection();
        Channel channel = connection.createChannel();
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
        for(int i=1; i<=100; i++){
            channel.basicPublish("",QUEUE_NAME,null,("work模型").getBytes("UTF-8"));
        }
    }
}
public class Consumer {

    private static final String QUEUE_NAME = "work";
    public static void main(String[] args) throws Exception {

        Connection conncetion = RabbitMQUtils.getConncetion();
        final Channel channel = conncetion.createChannel();
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
        channel.basicQos(5);
        DefaultConsumer defaultConsumer=new DefaultConsumer(channel){

            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {

                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }

                String str = new String(body, "UTF-8");
                System.out.println("1接收到:"+str);
                channel.basicAck(envelope.getDeliveryTag(),true);
            }
        };
        channel.basicConsume(QUEUE_NAME,false,defaultConsumer);
    }
}
public class Consumer {

    private static final String QUEUE_NAME = "work";
    public static void main(String[] args) throws Exception {

        Connection conncetion = RabbitMQUtils.getConncetion();
        final Channel channel = conncetion.createChannel();
        channel.queueDeclare(QUEUE_NAME,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 str = new String(body, "UTF-8");
                System.out.println("2接收到:"+str);
                channel.basicAck(envelope.getDeliveryTag(),true);
            }
        };
        channel.basicConsume(QUEUE_NAME,false,defaultConsumer);
    }
}

发布订阅模型

生产者将消息发送到交换机 交换机将消息发布到不同消费者(消费者得到的消息一直 是完全重复) 
适合做模块间的异步通信 模块间的解耦
public class Producer {

    private static final String EXCHANGE_NAME = "exchange_01";

    public static void main(String[] args) throws IOException, TimeoutException {

        Connection conncetion = RabbitMQUtils.getConncetion();
        Channel channel = conncetion.createChannel();
        channel.exchangeDeclare(EXCHANGE_NAME,"fanout");
        for (int i = 1; i <=100 ; i++) {
            channel.basicPublish(EXCHANGE_NAME,"",null,("发布订阅:"+i).getBytes("UTF-8"));
        }
    }
}
public class Consumer {

    private static final String QUEUE_NAME = "fanout_queue_01";
    private static final String EXCHANGE_NAME = "exchange_01";
    public static void main(String[] args) throws Exception {

        Connection conncetion = RabbitMQUtils.getConncetion();
        final Channel channel = conncetion.createChannel();
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
        channel.exchangeDeclare(EXCHANGE_NAME,"fanout");
        DefaultConsumer defaultConsumer=new DefaultConsumer(channel){

            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                String s = new String(body, "UTF-8");
                System.out.println("1接收到:"+s);
                channel.basicAck(envelope.getDeliveryTag(),true);
            }
        };

        channel.queueBind(QUEUE_NAME,EXCHANGE_NAME,"");
        channel.basicConsume(QUEUE_NAME,false,defaultConsumer);

    }
}
public class Consumer {

    private static final String QUEUE_NAME = "fanout_queue_01";
    private static final String EXCHANGE_NAME = "exchange_01";
    public static void main(String[] args) throws Exception {

        Connection conncetion = RabbitMQUtils.getConncetion();
        final Channel channel = conncetion.createChannel();
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
        channel.exchangeDeclare(EXCHANGE_NAME,"fanout");
        DefaultConsumer defaultConsumer=new DefaultConsumer(channel){

            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                String s = new String(body, "UTF-8");
                System.out.println("2接收到:"+s);
                channel.basicAck(envelope.getDeliveryTag(),true);
            }
        };

        channel.queueBind(QUEUE_NAME,EXCHANGE_NAME,"");
        channel.basicConsume(QUEUE_NAME,false,defaultConsumer);

    }
}

路由模型

生产者将消息发送到交换机 交换机根据路由key将消息分发到不同消费者
public class Producer {

    private static final String EXCHANGE_NAME = "routing_exchange_01";
    public static void main(String[] args) throws IOException, TimeoutException {

        Connection conncetion = RabbitMQUtils.getConncetion();
        Channel channel = conncetion.createChannel();
        channel.exchangeDeclare(EXCHANGE_NAME,"direct");
        for (int i = 1; i <=100 ; i++) {
            channel.basicPublish(EXCHANGE_NAME,"red",null,("路由模型"+i).getBytes("UTF-8"));
        }
    }
}
public class Consumer {

    private static final String QUEUE_NAME = "routing_exchange_01";
    private static final String EXCHANGE_NAME = "routing_exchange_01";
    public static void main(String[] args) throws Exception {

        Connection conncetion = RabbitMQUtils.getConncetion();
        final Channel channel = conncetion.createChannel();
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
        channel.exchangeDeclare(EXCHANGE_NAME,"direct");
        DefaultConsumer defaultConsumer=new DefaultConsumer(channel){

            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                String str = new String(body, "UTF-8");
                System.out.println("1接收到:"+str);
                channel.basicAck(envelope.getDeliveryTag(),true);
            }
        };
        channel.queueBind(QUEUE_NAME,EXCHANGE_NAME,"red");
        channel.basicConsume(QUEUE_NAME,false,defaultConsumer);
    }
}
public class Consumer {

    private static final String QUEUE_NAME = "routing_exchange_02";
    private static final String EXCHANGE_NAME = "routing_exchange_01";
    public static void main(String[] args) throws Exception {

        Connection conncetion = RabbitMQUtils.getConncetion();
        final Channel channel = conncetion.createChannel();
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
        channel.exchangeDeclare(EXCHANGE_NAME,"direct");
        DefaultConsumer defaultConsumer=new DefaultConsumer(channel){

            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                String str = new String(body, "UTF-8");
                System.out.println("2接收到:"+str);
                channel.basicAck(envelope.getDeliveryTag(),true);
            }
        };
        channel.queueBind(QUEUE_NAME,EXCHANGE_NAME,"blue");
        channel.basicConsume(QUEUE_NAME,false,defaultConsumer);
    }
}

主题模型

生产者将消息发送到交换机 交换机根据路由key将消息分发到不同消费者
与路由模型的不同:主题模式是模糊匹配 路由模式是精准匹配
*代码一个单词 #代表多个单词
public class Producer {
    private static final String EXCHANGE_NAME = "topic_exchange_01";

    public static void main(String[] args) throws IOException, TimeoutException {

        Connection conncetion = RabbitMQUtils.getConncetion();
        Channel channel = conncetion.createChannel();
        channel.exchangeDeclare(EXCHANGE_NAME,"topic");
        for (int i = 1; i <=100 ; i++) {
            channel.basicPublish(EXCHANGE_NAME,"buliyat",null,("主题模型"+i).getBytes("UTF-8"));
        }
    }
}
public class Consumer {

    private static final String QUEUE_NAME = "topic_queue_01";
    private static final String EXCHANGE_NAME = "topic_exchange_01";
    public static void main(String[] args) throws Exception {

        Connection conncetion = RabbitMQUtils.getConncetion();
        final Channel channel = conncetion.createChannel();
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
        channel.exchangeDeclare(EXCHANGE_NAME,"topic");
        DefaultConsumer defaultConsumer=new DefaultConsumer(channel){

            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                String str = new String(body, "UTF-8");
                System.out.println("1接收到:"+str);
                channel.basicAck(envelope.getDeliveryTag(),true);
            }
        };
        channel.queueBind(QUEUE_NAME,EXCHANGE_NAME,"buli*");
        channel.basicConsume(QUEUE_NAME,false,defaultConsumer);
    }
}
public class Consumer {

    private static final String QUEUE_NAME = "topic_queue_02";
    private static final String EXCHANGE_NAME = "topic_exchange_01";
    public static void main(String[] args) throws Exception {

        Connection conncetion = RabbitMQUtils.getConncetion();
        final Channel channel = conncetion.createChannel();
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
        channel.exchangeDeclare(EXCHANGE_NAME,"topic");
        DefaultConsumer defaultConsumer=new DefaultConsumer(channel){

            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                String str = new String(body, "UTF-8");
                System.out.println("2接收到:"+str);
                channel.basicAck(envelope.getDeliveryTag(),true);
            }
        };
        channel.queueBind(QUEUE_NAME,EXCHANGE_NAME,"buli#");
        channel.basicConsume(QUEUE_NAME,false,defaultConsumer);
    }
}

高级应用

Confirm机制

channel.basicPublish()方法并没有返回值 当使用该方法向队列发送消息时 并不知道消息是否到达队列
​
解决方案
    Confirm机制
    事务(RabbitMQ的事务)-->若发送失败 则事务回滚
    
Confirm机制与事务不能同时使用
Confirm机制 向队列发送消息后 实现回调 返回消息发送是否成功
​
每一个RabbitMQ都是一个broker
public class Producer {

    private static final String QUEUE_NAME = "hello";
    public static void main(String[] args) throws IOException, TimeoutException {

        Connection conncetion = RabbitMQUtils.getConncetion();
        Channel channel = conncetion.createChannel();
        channel.confirmSelect();
        channel.addConfirmListener(new ConfirmListener() {

            // 参数:消息的唯一标志 消息确认被接收 
            public void handleAck(long l, boolean b) throws IOException {
                System.out.println("发送消息成功...");
            }
            // 参数:消息的唯一标志 消息确认未被接收 
            public void handleNack(long l, boolean b) throws IOException {
                System.out.println("发送消息失败...");
                // TODO 重试发送
            }
        });
        // 参数:队列名 持久化 排外 自动删除 创建队列自动的参数
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
        // 参数:交换机名 路由key 发送消息附带的键值对参数
        channel.basicPublish("",QUEUE_NAME,null,"Helloworld".getBytes("UTF-8"));
    }
}

Return机制

场景:发送消息到交换机 交换机不存在或交换机未绑定队列 消息的结果会是怎样
触发Return机制 没有地方路由就会触发Reutrn机制
public class Producer {

    private static final String EXCHANGE_NAME = "exchange_01";
    public static void main(String[] args) throws IOException, TimeoutException {

        Connection conncetion = RabbitMQUtils.getConncetion();
        Channel channel = conncetion.createChannel();
        // 参数:交换机名 交换机类型(发布订阅模型只能写fanout)
        channel.exchangeDeclare(EXCHANGE_NAME, "fanout");
        channel.addReturnListener(new ReturnListener() {

            public void handleReturn(int i, String s, String s1, String s2, AMQP.BasicProperties basicProperties, byte[] bytes) throws IOException {
                System.out.println("没有可路由的消费者..."+new String(bytes,"UTF-8"));
            }
        });
        // 第三个参数为ture才会触发return机制
        channel.basicPublish(EXCHANGE_NAME, "", true,null, ("发布订阅").getBytes("UTF-8"));
    }
}

消费限流

// 预取大小:每次从消息队列中预取消息的最大字节数
// 预取数量:每次从消息队列中预取消息的最大数量
// 全局设置:是否将上述设置应用于所有消费者
channel.basicQos(0,5,true);

重回队列

public class Consumer {

    private static final String QUEUE_NAME = "hello";

    public static void main(String[] args) throws Exception {
        Connection conncetion = RabbitMQUtils.getConncetion();
        final Channel channel = conncetion.createChannel();
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);
        channel.basicQos(0, 5, true);
        DefaultConsumer defaultConsumer = new DefaultConsumer(channel) {

            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                String str = new String(body, "UTF-8");
                System.out.println("接收到:" + str);
                // 参数:消息唯一标识 批量应答 重回队列
                channel.basicNack(envelope.getDeliveryTag(),true,true);
            }
        };
        channel.basicConsume(QUEUE_NAME, false, defaultConsumer);
    }
}

TTL队列

设置队列中消息的过期时间 丢弃过期时间到达还未被消费的消息
public class Producer {

    private static final String QUEUE_NAME = "ttl_queue";
    public static void main(String[] args) throws IOException, TimeoutException {

        Connection conncetion = RabbitMQUtils.getConncetion();
        Channel channel = conncetion.createChannel();
        Map<String,Object> maps=new HashMap<String, Object>();
        maps.put("x-message-ttl",5000);
        // 第五个参数 可设置maps map集合 key存储消息 val存储过期时间(单位:ms)
        channel.queueDeclare(QUEUE_NAME,false,false,false,maps);
        channel.basicPublish("",QUEUE_NAME,null,"数据".getBytes("UTF-8"));
    }
}

死信队列

死信的产生:
    队列已满 再存储消息时 消息并不能进入队列 
    TTL队列 消息的过期时间已到达
    消息没有可路由的消费者
    
死信队列:当消息成为死信 存在死信属性 通过此死信属性 所有的死信可路由到指定队列中
public class Producer {

    private static final String NORMAL_QUEUE_NAME = "normal_queue";
    private static final String DEAD_QUEUE_NAME = "dead_queue";
    private static final String DEAD_EXCHANGE_NAME="dead_exchange_01";
    public static void main(String[] args) throws IOException, TimeoutException {

        Connection conncetion = RabbitMQUtils.getConncetion();
        Channel channel = conncetion.createChannel();
        Map<String,Object> maps=new HashMap<String, Object>();
        maps.put("x-message-ttl",5000);
        maps.put("x-dead-letter-exchange",DEAD_EXCHANGE_NAME);
        channel.queueDeclare(NORMAL_QUEUE_NAME,false,false,false,maps);
        channel.queueDeclare(DEAD_QUEUE_NAME,false,false,false,maps);
        channel.exchangeDeclare(DEAD_EXCHANGE_NAME,"fanout");
        channel.queueBind(DEAD_QUEUE_NAME,DEAD_EXCHANGE_NAME,"");
        channel.basicPublish("",NORMAL_QUEUE_NAME,null,"数据".getBytes("UTF-8"));
    }
}

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值