rabbitMQ使用(一)

一、什么是MQ

MQ全称 Message queue(消息队列),是在消息的传输过程中保存消息的容器。用于分布式项目之间的进行通信。

二、MQ的优缺点

优点:
	应用解耦:提高系统的可维护性和可容错性
	异步提速:提升用户体验和系统吞吐量
	削峰填谷:提高系统的稳定性
缺点:
	服务复杂度增加:
		系统的组件越多,就越复杂。增加一个MQ,系统的复杂度又提升了
	服务稳定性降低
		系统越复杂,出现错误的几率越大。
	数据一致性问题
		A系统处理完业务,通过MQ给B,C,D三个系统发消息数据,如果B,C处理成功,D处理失败,如何保证数据的一致性?

三、图解MQ

1、应用解耦

	当有一个应用,有A,B,C等子服务,其中A服务需要将数据传递给B,C等服务,那么
直接在A服务中直接调用B,C等服务即可,但是如果有几百个服务需要A服务的数据,
并且这几百个服务的数量还是在波动,并且还要考虑下游服务的出错的情况,这就不
适合再使用传统的调用。

在这里插入图片描述

	当这种情况下,我们可以使用MQ作为中间件,A服务将其他服务需要的数据放在MQ中,然后需要该数据的服务向MQ中取数据,这样并不影响A服务的运行。

在这里插入图片描述

2、流量削峰

	假设我们的项目平常的访问量很少,每秒也就几百个访问,那么一台服务器就可以
应对了。但是如果有秒杀活动的话,那么访问量就是几十倍的增加,一台服务器肯定
不够用,那么我们再去买服务器吗?肯定不是,因为我们平常的访问量很少。这是否
就可以使用MQ了,访问请求先发送到MQ存储,排队等待处理,然后我们的服务再慢
慢的从MQ中读取请求去处理,减轻瞬间访问的压力。

普通情况:
在这里插入图片描述
秒杀情况:
在这里插入图片描述

3、异步调用

	当我们一个流量高峰,比如五一回家使用12306抢票,当我们下订单的时候,还没有调用付款业务之前,是非常快的。但是调用付款业务,就速度很慢了,甚至卡死,如果等待下单成功的应答,那就玩完了,整条链路就挂掉了。此时使用MQ,将下单付款的请求先放到MQ中,付块业务可以使用异步的方式从队列中读取请求,这就不影响付款之前业务的运行了。

普通模式:耗时1min+200ms
在这里插入图片描述加入MQ:耗时200ms+5ms
在这里插入图片描述

四、常见的MQ

在这里插入图片描述

五、Centos7安装RabbitMQ

1、上传安装软件(①erlang    ②rabbitmq)
		官网地址:https://www.rabbitmq.com/
2、安装rabbitmq依赖的环境
		 yum install -y gcc socat openssl openssl-devel
3、安装erlang和rabbitMQ
		rpm -ivh erlang-22.0.7-1.el7.x86_64.rpm
		rpm -ivh rabbitmq-server-3.7.17-1.el7.noarch.rpm
4、开启管理界面及配置     ---可以通过网页访问
		rabbitmq-plugins enable rabbitmq_management
		开设一个用户用来页面访问时使用:
			进入到rabbitMQ的安装目录:
			cd /usr/share/doc/rabbitmq-server-3.7.17
			我们需要更改rabbitmq.config.example文件,但是要将它改为rabbitmq.example才管用,所以我们复制出来一份:
			cp rabbitmq.config.example /etc/rabbitmq/rabbitmq.config 
			然后修改 /etc/rabbitmq/rabbitmq.config 配置文件:

在这里插入图片描述

5、开启rabbitMQ服务器
	systemctl start rabbitmq-server    开启命令
	systemctl restart rabbitmq-server   重启的命令

使用网页连接:用户名和密码 guest
在这里插入图片描述连接成功:
在这里插入图片描述

六、rabbitMQ的结构以及每个组件的作用

在这里插入图片描述

	Broker: 接收和分发消息的应用,rabbitMQ的核心逻辑,RabbitMQ server 就是Message Broker.
	Virtual host:出于多租户和安全因素设计的,把AMQP的基本组件划分到一个虚拟的
分组中, 类似于网络中namespace的概念。当多个不同的用户使用同一个RabbitMQ 
server提供服务时,可以划分出多个vhost,每个用户可以在自己的vhost创建
exchange/queue等。
	Connection:publisher/consumer和broker之间的TCP连接。
	channel:如果每一次访问RabbitMQ都建立一个Connection连接,在消息量大的时
候,建立TCP  Connection的开销将时巨大的,效率也低。channel是在connection中
建立的逻辑连接,如果应用程序支持多线程,通常每个thread创建单独的channel进行
通信,AMQP method中包含了channel id来帮助客户端和message broker识别
channel,所以channel是完全隔离的。channel作为轻量级的connection,极大的减少
了创建TCP Connection的开销。·
	Exchange:message到达broker的第一站,根据分发规则,匹配查询表中Routing key,分发消息到queue中去。常用的交换机路由类型有:direct(point-to-point),topic(publish-subscribe) and fanout(multicast)
	queue:消息最终被送到这里,被consumer取走。
	Binding:exchange和queue之间的虚拟连接,binding中可以包含routing key。Binding信息保存在exchange的查询表中,用于message的分发依据

七、rabbitMQ的模式

以下模式中,只要销毁者监控的队列中有消息,就会自动消费
使用之前要导依赖:使用的是普通的maven项目

<dependencies>
    <dependency>
        <groupId>com.rabbitmq</groupId>
        <artifactId>amqp-client</artifactId>
        <version>5.9.0</version>
    </dependency>
</dependencies>

1、简单模式(默认交换机)

在这里插入图片描述

上图中只有三个角色:
	p:producer:消息的生产者
	红色【queue】:存储消息
	c:consumer:消息的消费者

示例代码:
消息的生产者:

public class Producers {
    public static void main(String[] args) {
//        创建生产者:创建连接工厂  配置连接信息
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("192.168.253.128");
        try {
//        创建连接对象 Connection
            Connection connection = factory.newConnection();
//       创建信道
            Channel channel = connection.createChannel();
//        简单模式没有交换器,直接创建队列
            /**
             * String queue:队列的名称
             * boolean durable:队列中的信息是否实例化,也就是rabbitmq重启后信息是否还存在
             * boolean exclusive:是否独自占有,信道和队列之间
             * boolean autoDelete:是否自动删除,长时间没有消息时,队列删除
             * Map<String, Object> arguments 额外参数  先给null
             */
            channel.queueDeclare("lyd", true, false, false, null);
//       产生消息
            /**
             * String exchange: 交换机的名称 如果没有则使用“” 它回自动采用默认
             * String routingKey, 路由key  如果没有交换机的绑定 使用队列的名称
             * BasicProperties props, 消息的一些额外配置 目前先不加 null
             * byte[] body 消息的内容
             */
            String msg="i love you !!!!";
            channel.basicPublish("","lyd",null,msg.getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        } catch (TimeoutException e) {
            e.printStackTrace();
        }

    }
}

消息的消费者:

public class Consumers {
    public static void main(String[] args) {
//        创建连接工厂 --配置连接信息
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("192.168.253.128");
//        创建连接对象
        try {
            Connection connection = factory.newConnection();
//            创建信道
            Channel channel = connection.createChannel();
//            接收消息
            DefaultConsumer callback = new DefaultConsumer(channel) {
                @Override
                public void handleDelivery(String consumerTag,
                                           Envelope envelope,
                                           AMQP.BasicProperties properties,
                                           byte[] body)
                        throws IOException
                {
//                    body:接收到的信息
                    System.out.println("接收到的"+new String(body));
                }
            };
//            消费消息
            /**
             * @param queue the name of the queue
             * @param autoAck true if the server should consider messages
             * @param callback an interface to the consumer object
             */
            channel.basicConsume("lyd",true,callback);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (TimeoutException e) {
            e.printStackTrace();
        }
    }

}

2、工作者模式(work)

在这里插入图片描述

特点:
	1、一个生产者
	2、多个消费者
	3、一个队列
	4、消费者之间存在竞争关系(处理队列中消息的机会是相等的)
用处:
	比如批量处理上。rabbitMQ里面积压了大量消息时

生产者:

public class Producers {
    public static void main(String[] args) throws IOException, TimeoutException {
//        创建连接工厂   配置连接信息
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("192.168.253.128");

        Connection connection =null;
        Channel channel =null;
        try {
//        创建连接对象
            connection = factory.newConnection();
//        创建信道
            channel = connection.createChannel();
//         创建队列
            channel.queueDeclare("lyd_work", true, false, false, null);
//
            for(int i=0;i<10;i++){
                String msg="i love you !!!!";
//                发送消息
                channel.basicPublish("","lyd_work",null,msg.getBytes());
            }


        } catch (IOException e) {
            e.printStackTrace();
        } catch (TimeoutException e) {
            e.printStackTrace();
        }finally {
//            释放资源
            channel.close();
            connection.close();
        }
    }
}

消费者:
消费者1:

public class Consumer01 {
    public static void main(String[] args) {
//        创建连接工厂 --配置连接信息
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("192.168.253.128");
//        创建连接对象
        try {
            Connection connection = factory.newConnection();
//            创建信道
            Channel channel = connection.createChannel();
//            回调接收消息
            DefaultConsumer callback = new DefaultConsumer(channel) {
                @Override
                public void handleDelivery(String consumerTag,
                                           Envelope envelope,
                                           AMQP.BasicProperties properties,
                                           byte[] body)
                        throws IOException
                {
//                    body:接收到的信息
                    System.out.println("消费者01:"+new String(body));
                }
            };
//            消费消息
            /**
             * @param queue the name of the queue
             * @param autoAck true if the server should consider messages
             * @param callback an interface to the consumer object
             */
            channel.basicConsume("lyd_work",true,callback);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (TimeoutException e) {
            e.printStackTrace();
        }
    }

}

消费者2:

public class Consumer02 {
    public static void main(String[] args) {
//        创建连接工厂 --配置连接信息
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("192.168.253.128");
//        创建连接对象
        try {
            Connection connection = factory.newConnection();
//            创建信道
            Channel channel = connection.createChannel();
//            回调接收消息
            DefaultConsumer callback = new DefaultConsumer(channel) {
                @Override
                public void handleDelivery(String consumerTag,
                                           Envelope envelope,
                                           AMQP.BasicProperties properties,
                                           byte[] body)
                        throws IOException
                {
//                    body:接收到的信息
                    System.out.println("消费者02:"+new String(body));
                }
            };
//            消费消息
            /**
             * @param queue the name of the queue
             * @param autoAck true if the server should consider messages
             * @param callback an interface to the consumer object
             */
            channel.basicConsume("lyd_work",true,callback);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (TimeoutException e) {
            e.printStackTrace();
        }
    }

}

3、广播模式或者发布与订阅模式(fanout:扇形交换机)

在这里插入图片描述

特点:
	1、一个生产者
	2、一个交换机,转发消息
	3、多个队列
	4、多个 消费者

生产者:

public class Producers {
    public static void main(String[] args) throws IOException, TimeoutException {
        //        创建连接工厂   配置连接信息
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("192.168.253.128");

        Connection connection =null;
        Channel channel =null;
        try {
//        创建连接对象
            connection = factory.newConnection();
//        创建信道
            channel = connection.createChannel();
//            创建交换机
            /**
             * @param exchange the name of the exchange
             * @param type 交换机的类型
             * @param durable true if we are declaring a durable exchange (the exchange will survive a server restart)
             * @return a declaration-confirm method to indicate the exchange was successfully declared
             */
            channel.exchangeDeclare("fy_fanout", BuiltinExchangeType.FANOUT,true);

//         创建队列
            channel.queueDeclare("lyd_fanout01", true, false, false, null);
            channel.queueDeclare("lyd_fanout02", true, false, false, null);

//           绑定队列
            channel.queueBind("lyd_fanout01","fy_fanout","");
            channel.queueBind("lyd_fanout02","fy_fanout","");


            for(int i=0;i<10;i++){
                String msg="i love you !!!!";
                channel.basicPublish("fy_fanout","",null,msg.getBytes());
            }


        } catch (IOException e) {
            e.printStackTrace();
        } catch (TimeoutException e) {
            e.printStackTrace();
        }finally {
            channel.close();
            connection.close();
        }
    }
}

消费者:
消费者1:

public class Consumer01 {
    public static void main(String[] args) {
//        创建连接工厂 --配置连接信息
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("192.168.253.128");
//        创建连接对象
        try {
            Connection connection = factory.newConnection();
//            创建信道
            Channel channel = connection.createChannel();

//            接收消息
            DefaultConsumer callback = new DefaultConsumer(channel) {
                @Override
                public void handleDelivery(String consumerTag,
                                           Envelope envelope,
                                           AMQP.BasicProperties properties,
                                           byte[] body)
                        throws IOException
                {
//                    body:接收到的信息
                    System.out.println("消费者01:"+new String(body));
                }
            };
//            消费消息
            /**
             * @param queue the name of the queue
             * @param autoAck true if the server should consider messages
             * @param callback an interface to the consumer object
             */
            channel.basicConsume("lyd_fanout01",true,callback);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (TimeoutException e) {
            e.printStackTrace();
        }
    }
}

消费者2:
只要将消费者1中的 channel.basicConsume()中的队列名称改了就ok了

4、路由模式(直连交换机)

在这里插入图片描述

特点:
	1、一个生产者
	2、一个交换机
	3、多个队列
	4、多个消费者
	5、交换机和队列有 routing key绑定

生产者:

public class Producers {
    public static void main(String[] args) throws IOException, TimeoutException {
        //        创建连接工厂   配置连接信息
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("192.168.253.128");

        Connection connection =null;
        Channel channel =null;
        try {
//        创建连接对象
            connection = factory.newConnection();
//        创建信道
            channel = connection.createChannel();
//            创建交换机
            /**
             * @param exchange the name of the exchange
             * @param type the exchange type
             * @param durable true if we are declaring a durable exchange (the exchange will survive a server restart)
             * @return a declaration-confirm method to indicate the exchange was successfully declared
             */
            channel.exchangeDeclare("fy_direct", BuiltinExchangeType.DIRECT,true);

//         创建队列
            channel.queueDeclare("lyd_direct01", true, false, false, null);
            channel.queueDeclare("lyd_direct02", true, false, false, null);

             /*           绑定队列
                        routingKey:路由标识,交换机分发消息时,就是根据routingkey来分发到符合的队列中
                        routingkey的值是可以自定义的
                        */
            channel.queueBind("lyd_direct01","fy_direct","info");
            channel.queueBind("lyd_direct02","fy_direct","info");
            channel.queueBind("lyd_direct02","fy_direct","error");

            //
            for(int i=0;i<10;i++){
                String msg="i love you !!!!";
                channel.basicPublish("fy_direct","info",null,msg.getBytes());
            }


        } catch (IOException e) {
            e.printStackTrace();
        } catch (TimeoutException e) {
            e.printStackTrace();
        }finally {
            channel.close();
            connection.close();
        }
    }
}

消费者:
消费者1:

public class Consumer01 {
    public static void main(String[] args) {
//        创建连接工厂 --配置连接信息
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("192.168.253.128");
//        创建连接对象
        try {
            Connection connection = factory.newConnection();
//            创建信道
            Channel channel = connection.createChannel();

//            接收消息
            DefaultConsumer callback = new DefaultConsumer(channel) {
                @Override
                public void handleDelivery(String consumerTag,
                                           Envelope envelope,
                                           AMQP.BasicProperties properties,
                                           byte[] body)
                        throws IOException
                {
//                    body:接收到的信息
                    System.out.println("消费者01:"+new String(body));
                }
            };
//            消费消息
            /**
             * @param queue the name of the queue
             * @param autoAck true if the server should consider messages
             * @param callback an interface to the consumer object
             */
            channel.basicConsume("lyd_direct01",true,callback);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (TimeoutException e) {
            e.printStackTrace();
        }
    }

}

消费者2:
只要将消费者1中的 channel.basicConsume()中的队列名称改了就ok了

5、主题模式(topic:主题交换机)

特点:
	1、一个生产者
	2、一个交换机
	3、多个队列
	4、多个消费者
	5、routing key 是模糊匹配的
			*:统配一个
			#:统配一个或者多个单词

生产者:
在这里插入图片描述

public class Producers {
    public static void main(String[] args) throws IOException, TimeoutException {
        //        创建连接工厂   配置连接信息
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("192.168.253.128");

        Connection connection =null;
        Channel channel =null;
        try {
//        创建连接对象
            connection = factory.newConnection();
//        创建信道
            channel = connection.createChannel();
//            创建交换机
            /**
             * @param exchange the name of the exchange
             * @param type the exchange type
             * @param durable true if we are declaring a durable exchange (the exchange will survive a server restart)
             * @return a declaration-confirm method to indicate the exchange was successfully declared
             */
            channel.exchangeDeclare("fy_topic", BuiltinExchangeType.TOPIC,true);

//         创建队列
            channel.queueDeclare("oo_topic01", true, false, false, null);
            channel.queueDeclare("oo_topic02", true, false, false, null);

/* 绑定队列和交换机 
            routingKey:这里写规则,routingKey的规则
            */
            channel.queueBind("oo_topic01","fy_topic","*.*.oo");
            channel.queueBind("oo_topic02","fy_topic","*.fy.*");
            channel.queueBind("oo_topic02","fy_topic","error.#");
            
            for(int i=0;i<10;i++){
                String msg="i love you !!!!";
                channel.basicPublish("fy_topic","error.dd.cc",null,msg.getBytes());
                channel.basicPublish("fy_topic","error.dd.oo",null,msg.getBytes());
            }
            
        } catch (IOException e) {
            e.printStackTrace();
        } catch (TimeoutException e) {
            e.printStackTrace();
        }finally {
            channel.close();
            connection.close();
        }
    }
}

生产者:
生产者1:

public class Consumer01 {
    public static void main(String[] args) {
//        创建连接工厂 --配置连接信息
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("192.168.253.128");
//        创建连接对象
        try {
            Connection connection = factory.newConnection();
//            创建信道
            Channel channel = connection.createChannel();

//            接收消息
            DefaultConsumer callback = new DefaultConsumer(channel) {
                @Override
                public void handleDelivery(String consumerTag,
                                           Envelope envelope,
                                           AMQP.BasicProperties properties,
                                           byte[] body)
                        throws IOException
                {
//                    body:接收到的信息
                    System.out.println("消费者01:"+new String(body));
                }
            };
//            消费消息
            /**
             * @param queue the name of the queue
             * @param autoAck true if the server should consider messages
             * @param callback an interface to the consumer object
             */
            channel.basicConsume("oo_topic01",true,callback);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (TimeoutException e) {
            e.printStackTrace();
        }
    }
}

生产者2:
只要将消费者1中的 channel.basicConsume()中的队列名称改了就ok了

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值