1、RabbitMQ 简介
MQ全称为Message Queue, (MQ)是一种应用程序对应用程序的通信方法。应用程序通过读写出入队列的消息(针对应用程序的数据)来通信,而无需专用连接来链接它们。
MQ是消费-生产者模型的一个典型的代表,一端往中不断写入消息,而另一端则可以读取或者订阅队列中的消息。
RabbitMQ 是一个消息代理。主要的原理就是通过接受和转发消息。RabbitMQ是实现AMQP(高级消息队列协议)的消息中间件的一种,消息中间件主要用于组件之间的解耦。
RabbitMQ服务器端用Erlang语言编写,支持多种客户端,如:Python、Ruby、.NET、Java、C、PHP、ActionScript、XMPP、STOMP等,支持AJAX。
2、使用场景
例如:应用程序A向应用程序B发送请求并期望得到响应。
发送方(应用程序A)向消息中间件(RabbitMQ) 发送请求,接受方(应用程序B)订阅请求。发送方将消息发送给消息中间件后,异步执行程序。
发送方(应用程序B)向消息中间件(RabbitMQ) 发送请求,接受方(应用程序A)订阅请求。发送方将消息发送给消息中间件后,异步执行程序。
在项目中,将一些无需即时返回且耗时的操作提取出来,进行了,而这种异步处理的方式大大的节省了服务器的,从而提高了系统的吞吐量。
3、RabbitMQ的优势
高并发;负载均衡;消息持久;耦合低;响应速度快;
4、RabiitMQ术语
Connection: 是RabbitMQ的socket链接,它封装了socket协议相关部分逻辑。
ConnectionFactory:Connection的制造工厂。
Channel:是我们与RabbitMQ打交道的最重要的一个接口,我们大部分的业务操作是在Channel这个接口中完成的,包括定义Queue、定义Exchange、绑定Queue与Exchange、发布消息等。
几个基本概念:
(1)生产者:生产过程就像发送过程,发送消息的程序就是一个生产者,我们使用“P”来描述它。
用于绑定交换机与队列间的key。
生产者发送消息给交换机时,一般都会指定routing key,用于绑定交换机与队列。
这还跟交换机类型(Exchange Type)有关:
四种类型,fanout,direct,topic,headers
图解分析:
生成者生产消息,发送消息到队列,消费者可以从队列获取消息并消费。
多个消费者订阅同一个队列,消息平摊:
实际情况:生产者投递消息永远只会先经过交换机,交换机根据交换机类型或规则路由到队列。
如果没有路由匹配到队列,则消息会丢失。
5、RabbitMQ交换机
2、生产者是将消息投递给交换机,消息将被发送到一个队列中还是对个队列中亦或是被抛弃,这都是交换机的类型决定的。
RabbitMQ服务器中存在一个匿名交换机,他不能被删除之前的代码中“”即为匿名交换机
channel.basicPublish("", "hello", null, message.getBytes());
当我们使用无参数调用queueDeclare()方法,我们创建一个自动产生的名字,不持久化,独占的,自动删除的队列。
String queueName = channel.queueDeclare().getQueue();//名字随机
绑定:
1)funout类型的交换机
即为交换机与队列绑定,假设一个funout类型的交换机。
channel.queueBind(queueName, "logs", "");
Fanout类型发给所有它所知道的队列。
channel.exchangeDeclare(“logs”, “fanout”);//声明fanout类型的队列
2)direct类型的交换机
当我们需要对日志系统做严格过滤规则时。比如由于电脑磁盘有限,日志系统只对error级别的日志做保存。显然用Fanout类型交换机满足不了要求。
3)topic类型的交换机
更灵活,选择性更高。通配符式交换机。
* (星标) 能替代任意一个单词。
# (哈希) 能代替零个或多个单词。
7、代码实例
(1)生产者发送消息:
1 //1、创建一个服务器连接 2 ConnectionFactory factory = new ConnectionFactory(); 3 factory.setHost(“localhost”); //可连远程主机IP 4 factory.setPort(5672);//固定端口 5 factory.setUsername(“guest”);//远程必须新建用户 6 factory.setPassword(“guest”);//密码 7 Connection connection = factory.newConnection(); 8 Channel channel = connection.createChannel(); 9 //2、生产者发布消息10 channel.queueDeclare(“hello”, false, false, false, null); //声明队列11 String message = "Hello World!"; 12 channel.basicPublish("", QUEUE_NAME, null, message.getBytes()); //发布13 //3、关闭连接14 channel.close();15 connection.close();
(2)消费者接收消息
1 //1、首先创建连接,与生产者一样 2 channel.queueDeclare(“hello”, false, false, false, null); //声明队列 3 QueueingConsumer consumer = new QueueingConsumer(channel); 4 channel.basicConsume(QUEUE_NAME, true, consumer); 5 //2、接收消息 6 while (true) { 7 //3、线程阻塞,挂起直到队列传输消息到来 8 QueueingConsumer.Delivery delivery = consumer.nextDelivery(); 9 String message = new String(delivery.getBody()); 10 }