文章主要翻译自RabbitMQ官方文档,主要是为了练习英语翻译,顺便学习一下RabbitMQ😶
其中也记录了一些爬过的坑
Introduction
RabbitMQ is a message broker. The principal idea is pretty simple: it accepts and forwards messages. You can think about it as a post office: when you send mail to the post box you're pretty sure that Mr. Postman will eventually deliver the mail to your recipient. Using this metaphor RabbitMQ is a post box, a post office and a postman.
The major difference between RabbitMQ and the post office is the fact that it doesn't deal with paper, instead it accepts, stores and forwards binary blobs of data ‒messages.
RabbitMQ, and messaging in general, uses some jargon.
译:RabbitMQ是一个消息中间件(message broker)。它的核心思想(principal idea)非常简单:它可以接受和发送消息。你可以把它就想象成一个寄信过程:当你寄信时,你要把信投到邮箱里,然后你相信一定会有邮递员把信取走,并且安全无误的把信送到收件人的手中。一个恰当的比喻,RabbitMQ扮演了三个角色,它是一个邮箱,也是一个邮局,还是一个邮递员。
当然,它和邮局最重要的区别是,RabbitMQ存储、发送的不是纸(废话),而是二进制的数据。
RabbitMQ在使用中有一些术语。
Producing means nothing more than sending. A program that sends messages is a producer. We'll draw it like that, with "P":
译:“生产者”其实和“消息发送”意思差不多。代表一个发送消息的生产者。我们简称它为“P”:
Aqueue is the name for a mailbox.It lives inside RabbitMQ.Although message flow through RabbitMQ and your applications,they can be stored
only inside a queue.A queue is not bound by any limits,it can store as many messages as you like - it's essentially an infinite buffer. Many producers
can send messages that go to one queue, many consumers can try to receive data from one queue. A queue will be drawn as like that, with its name
above it:
译:一个队列可以比喻作是一个邮箱。它存在于RabbitMQ中。虽然消息的传输需要通过RabbitMQ和你的应用程序,这些消息只能保存在队列中。
一个队列是没有什么约束和限制的,只要你愿意它可以存储很多消息,本质上来说它就是一个无穷的缓冲区。许多消息生产者可以向一个
队列发送消息,同样许多消费者可以尝试接收一个队列中的消息。下图所示就是一个队列:
Consuming has a similar meaning to receiving. A consumer is a program that mostly waits to receive messages. On our drawings it's shown with "C":
译:消费也可以理解为接收。一个接收者就是一个等待接收消息的程序。下图就是一个接受者“C”:
Note that the producer, consumer, and broker do not have to reside on the same machine; indeed in most applications they don't.
译:注意,生产者、消费者、中间件不必在同一台机器上。事实上他们没有在一台机器上。
"Hello World"
(using the Java Client)
In this part of the tutorial we'll write two programs in Java; a producer that sends a single message, and a consumer that receives messages and prints them out. We'll gloss over some of the detail in the Java API, concentrating on this very simple thing just to get started. It's a "Hello World" of messaging.
In the diagram below, "P" is our producer and "C" is our consumer. The box in the middle is a queue - a message buffer that RabbitMQ keeps on behalf of the consumer.
译:这部分的内容会指导我们用Java语言写几个程序;一个用来发送单独消息的生产者,和一个接收消息的消费者,并将他们输出出来。我们会忽略一些调用JavaAPI的细节,只关心这个简单的例子可以跑起来。
在下方的图表中“P”代表我们的生产者,“C”代表我们的消费者。它们中间这个盒子是队列——它保持着RabbitMQ代表消费者的消息缓冲区。
The Java client library
RabbitMQ speaks multiple protocols. This tutorial uses AMQP 0-9-1, which is an open, general-purpose protocol for messaging. There are a number of clients for RabbitMQ in many different languages. We'll use the Java client provided by RabbitMQ.
Download the client library package, and check its signature as described. Unzip it into your working directory and grab the JAR files from the unzipped directory:
$ unzip rabbitmq-java-client-bin-*.zip
$ cp rabbitmq-java-client-bin-*/*.jar ./
(The RabbitMQ Java client is also in the central Maven repository, with the groupIdcom.rabbitmq and the artifactId amqp-client.)
译:首先需要引入Java client库的依赖,可以通过下载jar包,或者使用Maven构建工具,下面补充一下官方文档没有举例的maven配置:
com.rabbitmq
amqp-client
3.3.4
Now we have the Java client and its dependencies, we can write some code.
译:现在我们有了RabbitMQ封装好的client和这个依赖,下面我们就可以敲一些代码了。
Sending
We'll call our message sender Send and our message receiver Recv. The sender will connect to RabbitMQ, send a single message, then exit.
译:我们调用我们的消息发送者“Send”和我们的消息接受者“Recv”。这个发送者会连接RabbitMQ,发送一条消息,然后退出。
In Send.java, we need some classes imported:
译:在Send.java中,我们需要引入一些类:
1 importcom.rabbitmq.client.ConnectionFactory;2 importcom.rabbitmq.client.Connection;3 import com.rabbitmq.client.Channel;
Set up the class and name the queue:
译:建立类并声明队列的名字:
1 public classSend {2 private final static String QUEUE_NAME = "hello";3
4 public static voidmain(String[] argv)5 throwsjava.io.IOException {6 ...7 }8 }
then we can create a connection to the server:
译:然后我们就可以和server来建立一个连接:
1 ConnectionFactory factory = newConnectionFactory();2 factory.setHost("localhost");3 Connection connection =factory.newConnection();4 Channel channel = connection.createChannel();
注意,这里也可以设置Connection的端口号,通过:
factory.setPort(5672);
查看源码,默认的端口是:
public static final int DEFAULT_AMQP_OVER_SSL_PORT = 5671;
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 thelocalhost. 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:
译:这个连接抽象自socket连接,并且我们负责协议的版本协商和认证等方面。在这里我们连接一个本机的中间件——也就是“localhost”。如果我们想连接到其它机器上的中间件,我们需要简单的制定它的机器名或者IP地址。接下来我们创建一个通道,要做的大多事情都在这个API中。发送,我们必须声明一个消息队列用来为我们发送消息;然后我们就可以发送消息给队列了。
1 channel.queueDeclare(QUEUE_NAME, false, false, false, null);2 String message = "Hello World!";3 channel.basicPublish("", QUEUE_NAME, null, message.getBytes());4 System.out.println(" [x] Sent '" + message + "'");
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.
Lastly, we close the channel and the connection;
译:我们声明的这个队列是幂等的——如果不存在队列,则创建一个。消息的内容是一个字节数组,所以你可以随心所欲的编码你要发送的内容。
Lastly, we close the channel and the connection;
译:最后,我们关闭建立的通道和连接。
1 channel.close();2 connection.close();
下面是Send.java完整源码,其中注释有声明队列和发送消息时参数列表说明:
1 packageProducer;2
3 importcom.rabbitmq.client.Channel;4 importcom.rabbitmq.client.Connection;5 importcom.rabbitmq.client.ConnectionFactory;6
7 importjava.io.IOException;8
9 /**
10 * Created by zhengbin06 on 16/9/10.11 */
12 public classSend {13 private final static String QUEUE_NAME = "hello";14 public static void main(String[] args) throwsIOException {15 ConnectionFactory connectionFactory = newConnectionFactory();16 connectionFactory.setHost("localhost");17 //connectionFactory.setPort(5672);
18 Connection connection =connectionFactory.newConnection();19 Channel channel =connection.createChannel();20 /**
21 * Declare a queue22 *@seecom.rabbitmq.client.AMQP.Queue.Declare23 *@seecom.rabbitmq.client.AMQP.Queue.DeclareOk24 *@paramqueue the name of the queue25 * 队列:这是这个队列的名字26 *@paramdurable true if we are declaring a durable queue (the queue will survive a server restart)27 * 持久性:true代表声明一个持久的队列(服务器的重启不会影响到队列)28 *@paramexclusive true if we are declaring an exclusive queue (restricted to this connection)29 * 独有性(唯一性):true代表声明一个唯一的消息队列(仅限于这个连接,也就是说在这个连接(通道)中这个消息队列是唯一的)30 *@paramautoDelete true if we are declaring an autodelete queue (server will delete it when no longer in use)31 * 自动删除:如果为true代表声明了一个会自动销毁的消息队列(当长时间不使用时,服务器将把它删除)32 *@paramarguments other properties (construction arguments) for the queue33 * 参数:其它的一些声明队列的构造参数列表34 *@returna declaration-confirm method to indicate the queue was successfully declared35 *@throwsjava.io.IOException if an error is encountered36 */
37 //在这个通道中,声明一个消息队列
38 channel.queueDeclare(QUEUE_NAME, false, false, false, null);39 String message = "Hello World!";40 /**
41 * Publish a message42 *@seecom.rabbitmq.client.AMQP.Basic.Publish43 *@paramexchange the exchange to publish the message to44 * 交换:交换发送的消息45 *@paramroutingKey the routing key46 * 路由密钥:代表路由的密钥47 *@paramprops other properties for the message - routing headers etc48 * 其它信息:一些关于消息的其他属性——路由的消息头等49 *@parambody the message body50 * 消息主体:消息的主体(一个字节数组)51 *@throwsjava.io.IOException if an error is encountered52 */
53 channel.basicPublish("", QUEUE_NAME, null, message.getBytes());54 System.out.println(" [x] Sent '" + message + "'");55 channel.close();56 connection.close();57 }58 }
View Code
到这步为止你就可以运行Send.java 的main方法了,如果报错或者没有输出,官方文档给出的解释是:
Sending doesn't work!
If this is your first time using RabbitMQ and you don't see the "Sent" message then you may be left scratching your head wondering what could be wrong. Maybe the broker was started without enough free disk space (by default it needs at least 1GB free) and is therefore refusing to accept messages. Check the broker logfile to confirm and reduce the limit if necessary. The configuration file documentation will show you to set disk_free_limit.
译:如果这是你第一次使用RabbitMQ并且你没有看到“Sent”出的消息,面对这个问题你会有点摸(yi)不(lian)到(de)头(meng)脑(bi)。这个问题可能的原因是中间件没有足够的磁盘空间(默认最少需要1GB的磁盘空间),并且因此拒绝接收消息。检查中间件(broker)的日志文件,必要时减少一些限制。配置文件中的有"disk_free_limit"这一项。
但是我并没有遇到这个问题,在运行Send.java时遇到的是这个问题:连接被拒绝。
其实这是我们没有RabbitMQ-Server的原因,在官方文档的开头就有提示:
译:这个教程的假定你已经安装并且运行了RabbitMQ,地址是localhost(本地)端口是5672(这个没搞清楚,源码显示默认是5671,可能是我引入的版本低的原因)
点击“installed”跳转至如下页面,然后选择操作系统:
最后按照下方页面的提示,进行安装:
译:下载压缩包,解压至任意文件夹下,解压,在Finder中打开该包下的sbin/rabbitmq-server文件(一个shell脚本文件),或者在终端中“sbin/rabbitmq-server”也可以,Ctrl+c终止服务:
或者加上"-detached"参数,表示(in which case the server process runs in the background)也就是说这种情况下服务器在后台运行:
查看Broker状态:“./rabbitmqctl status”
关闭Broker:“./rabbitmqctl stop”
列出所有队列:
你也许希望查看RabbitMQ中有哪些队列、有多少消息在队列中。此时你可以使用rabbitmqctl工具:
➜ sbin ./rabbitmqctl list_queues
这篇简单介绍了RabbitMQ中的三个角色,和“Hello World!”这个例子中的Send.java,下面的一篇继续完成例子中的消息消费者Recv.java。