RabbitMQ:
MQ:message queue.MQ全称为Message Queue, 消息队列(MQ)是一种应用程序对应用程序的通信方法。应用程序通过读写出入队列的消息(针对应用程序的数据)来通信,而无需专用连接来链接它们。消 息传递指的是程序之间通过在消息中发送数据进行通信,而不是通过直接调用彼此来通信,直接调用通常是用于诸如远程过程调用的技术。排队指的是应用程序通过 队列来通信。队列的使用除去了接收和发送应用程序同时执行的要求。其中较为成熟的MQ产品有IBM WEBSPHERE MQ。ActiveMQ.
下载:http://www.rabbitmq.com/download.html
首先要安装Erlange:http://www.erlang.org/download.html
配置环境变量 ERLANG_HOME C:\Program Files (x86)\erl6.1
添加到PATH %ERLANG_HOME%\bin;
配置环境变量 C:\Program Files (x86)\RabbitMQ Server\rabbitmq_server-2.8.0
添加到PATH %RABBITMQ_SERVER%\sbin;
进入sbin目录,启动,或者在star menu点击start。
rabbitmq-service.bat start
接着安装管理工具
参考官方文档:http://www.rabbitmq.com/management.html
操作起来很简单,只需要在DOS下面,进入安装目录(C:\RabbitMQ Server\rabbitmq_server-3.2.2\sbin)执行如下命令就可以成功安装。
rabbitmq-plugins enable rabbitmq_management
可以通过访问http://localhost:15672进行测试,默认的登陆账号为:guest,密码为:guest。
如果访问成功了,恭喜,整个rabbitMQ安装完成了。
RabbitMQ服务端是用AMPQ协议的, 而客户端支持多种语言(Java, .NET, C/C++,Erlang......)。下面我们准备用java来写一个hello world,测试RabbitMQ是否安装OK。
Install the Server
Firstly, download and run the Erlang Windows Binary File. It takes around 5 minutes.
Then just run the installer, rabbitmq-server-3.3.5.exe. It takes around 2 minutes, and will set RabbitMQ up and running as a service, with a default configuration.
Run RabbitMQ Service
- Customise RabbitMQ Environment Variables
-
The service will run fine using its default settings. You may want to customise the RabbitMQ environment or edit configuration. - Run RabbitMQ
-
The RabbitMQ service starts automatically. You can stop/reinstall/start the RabbitMQ service from the Start Menu. - Manage the Service
-
You can find links to RabbitMQ directories in the Start Menu.There is also a link to a command prompt window that will start in the sbin dir, in the Start Menu. This is the most convenient way to run the various command line tools.
Default user access
The broker creates a user guest with password guest. Unconfigured clients will in general use these credentials. By default, these credentials can only be used when connecting to the broker as localhost so you will need to take action before connecting fromn any other machine.
See the documentation on access control for information on how to create more users, delete the guestuser, or allow remote access to the guest user.
Managing the Broker
To stop the broker or check its status, use rabbitmqctl.bat in sbin (as an administrator).
- Stopping the Broker
-
Use rabbitmqctl stop. - Checking the Broker Status
-
Use rabbitmqctl status. All rabbitmqctl commands will report the node absence if no broker is running (i.e. nodedown).
More info on rabbitmqctl
Logging
Output from the server is sent to a RABBITMQ_NODENAME.log file in the RABBITMQ_LOG_BASE directory. Additional log data is written to RABBITMQ_NODENAME-sasl.log.
The broker always appends to the log files, so a complete log history is retained.
You can rotate logs using rabbitmqctl rotate_logs.
Troubleshooting When Running as a Service
In the event that the Erlang VM crashes whilst RabbitMQ is running as a service, rather than writing the crash dump to the current directory (which doesn‘t make sense for a service) it is written to anerl_crash.dump file in the base directory of the RabbitMQ server (set by the RABBITMQ_BASE environment variable, defaulting to %APPDATA%\%RABBITMQ_SERVICENAME% - typically %APPDATA%\RabbitMQ otherwise).
使用场景:
在项目中,将一些无需即时返回且耗时的操作提取出来,进行了异步处理,而这种异步处理的方式大大的节省了服务器的请求响应时间,从而提高了系统的吞吐量
编程测试rabbitMQ:
http://www.rabbitmq.com/tutorials/tutorial-one-java.html
下面代码来自上面网址:
Send:
import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.Connection; import com.rabbitmq.client.Channel; public class Send { private final static String QUEUE_NAME = "hello"; public static void main(String[] argv) throws Exception { ConnectionFactory factory = new ConnectionFactory(); factory.setHost("localhost"); Connection connection = factory.newConnection(); Channel channel = connection.createChannel(); channel.queueDeclare(QUEUE_NAME, false, false, false, null); String message = "Hello World!"; channel.basicPublish("", QUEUE_NAME, null, message.getBytes()); System.out.println(" [x] Sent ‘" + message + "‘"); channel.close(); connection.close(); } }
The connection abstracts the socket connection, and takes care of protocol version negotiation and authentication and so on for us. Here we connect to a broker on the local machine - hence the localhost. If we wanted to connect to a broker on a different machine we‘d simply specify its name or IP address here.
Next we create a channel, which is where most of the API for getting things done resides.
To send, we must declare a queue for us to send to; then we can publish a message to the queue。
Declaring a queue is idempotent - it will only be created if it doesn‘t exist already. The message content is a byte array, so you can encode whatever you like there.
The code (in Recv.java) has almost the same imports as Send:
import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.Connection; import com.rabbitmq.client.Channel; import com.rabbitmq.client.QueueingConsumer;
The extra QueueingConsumer is a class we‘ll use to buffer the messages pushed to us by the server.
Setting up is the same as the sender; we open a connection and a channel, and declare the queue from which we‘re going to consume. Note this matches up with the queue that sendpublishes to.
public class Recv { private final static String QUEUE_NAME = "hello"; public static void main(String[] argv) throws java.io.IOException, java.lang.InterruptedException { ConnectionFactory factory = new ConnectionFactory(); factory.setHost("localhost"); Connection connection = factory.newConnection(); Channel channel = connection.createChannel(); channel.queueDeclare(QUEUE_NAME, false, false, false, null); System.out.println(" [*] Waiting for messages. To exit press CTRL+C"); ... } }
Note that we declare the queue here, as well. Because we might start the receiver before the sender, we want to make sure the queue exists before we try to consume messages from it.
We‘re about to tell the server to deliver us the messages from the queue. Since it will push us messages asynchronously, we provide a callback in the form of an object that will buffer the messages until we‘re ready to use them. That is what QueueingConsumer does.
QueueingConsumer consumer = new QueueingConsumer(channel); channel.basicConsume(QUEUE_NAME, true, consumer); while (true) { QueueingConsumer.Delivery delivery = consumer.nextDelivery(); String message = new String(delivery.getBody()); System.out.println(" [x] Received ‘" + message + "‘"); }
QueueingConsumer.nextDelivery() blocks until another message has been delivered from the server.
几个概念:
Exchange:交换机,决定了消息路由规则;
Queue:消息队列;
Channel:进行消息读写的通道;
Bind:绑定了Queue和Exchange,意即为符合什么样路由规则的消息,将会放置入哪一个消息队列;
RabbitMQ是流行的开源消息队列系统,用erlang语言开发。我曾经对这门语言挺有兴趣,学过一段时间,后来没坚持。RabbitMQ是AMQP(高级消息队列协议)的标准实现。如果不熟悉AMQP,直接看RabbitMQ的文档会比较困难。不过它也只有几个关键概念,这里简单介绍。[1]
RabbitMQ的结构图如下:
几个概念说明:
Broker:简单来说就是消息队列服务器实体。
Exchange:消息交换机,它指定消息按什么规则,路由到哪个队列。
Queue:消息队列载体,每个消息都会被投入到一个或多个队列。
Binding:绑定,它的作用就是把exchange和queue按照路由规则绑定起来。
Routing Key:路由关键字,exchange根据这个关键字进行消息投递。
vhost:虚拟主机,一个broker里可以开设多个vhost,用作不同用户的权限分离。
producer:消息生产者,就是投递消息的程序。
consumer:消息消费者,就是接受消息的程序。
channel:消息通道,在客户端的每个连接里,可建立多个channel,每个channel代表一个会话任务。
消息队列的使用过程大概如下:
(1)客户端连接到消息队列服务器,打开一个channel。
(2)客户端声明一个exchange,并设置相关属性。
(3)客户端声明一个queue,并设置相关属性。
(4)客户端使用routing key,在exchange和queue之间建立好绑定关系。
(5)客户端投递消息到exchange。
exchange接收到消息后,就根据消息的key和已经设置的binding,进行消息路由,将消息投递到一个或多个队列里。
exchange也有几个类型,完全根据key进行投递的叫做Direct交换机,例如,绑定时设置了routing key为”abc”,那么客户端提交的消息,只有设置了key为”abc”的才会投递到队列。对key进行模式匹配后进行投递的叫做Topic交换机,符号”#”匹配一个或多个词,符号”*”匹配正好一个词。例如”abc.#”匹配”abc.def.ghi”,”abc.*”只匹配”abc.def”。还有一种不需要key的,叫做Fanout交换机,它采取广播模式,一个消息进来时,投递到与该交换机绑定的所有队列。
RabbitMQ支持消息的持久化,也就是数据写在磁盘上,为了数据安全考虑,我想大多数用户都会选择持久化。消息队列持久化包括3个部分:
(1)exchange持久化,在声明时指定durable => 1
(2)queue持久化,在声明时指定durable => 1
(3)消息持久化,在投递时指定delivery_mode => 2(1是非持久化)
如果exchange和queue都是持久化的,那么它们之间的binding也是持久化的。如果exchange和queue两者之间有一个持久化,一个非持久化,就不允许建立绑定。[1]
参考:http://baike.baidu.com/view/4095865.htm?fr=aladdin