使用RabbitMQ进行消息代理

RabbitMQ is open-source message brokering software written in Erlang. The MQ in its name refers to a standard known as Advanced Message Queuing Protocol.  For our purposes, and most others, it acts as a middleman between producer (sending) and consumer (receiving) programs — it simply accepts and forwards messages. A common analogy with RabbitMQ is that it acts like a shipping service, like a post office. You send a package to your friend in any part of the world and your friend eventually receives the package without really knowing or caring how it got there.  In this analogy, RabbitMQ is the shipping service, the producer program is you (sending the package), the package is a generic blob of data, and the consuming program is your friend.

RabbitMQ是用Erlang编写的开源消息代理软件。 MQ的名称是指称为高级消息队列协议的标准。 就我们以及其他大多数人而言,它充当生产者(发送)程序和消费者(接收)程序之间的中间人,它只是接受和转发消息。 RabbitMQ的一个常见比喻是,它像邮递局一样充当运输服务。 您将包裹发送给您在世界任何地方的朋友,您的朋友最终在不真正知道或关心包裹如何到达的情况下收到包裹。 以此类推,RabbitMQ是运输服务,生产者程序是您(发送包裹),包裹是通用的数据块,而消费程序是您的朋友。

Both producers and consumers can be written in any language that has an available RabbitMQ or AMQP client library. In this article, I’ll demo a producer program written in PHP and a consuming program in Python.

生产者和消费者都可以使用任何具有可用RabbitMQ或AMQP客户端库的语言编写。 在本文中,我将演示一个用PHP编写的生产程序和一个用Python编写的消费程序。

安装RabbitMQ和客户端库 (Installing RabbitMQ and Client Libraries)

Go to rabbitmq.com/download.html and pick the installation file suitable for your particular system. I happen to be using Ubuntu and have had problems installing the package provided by Ubuntu (it’s not the freshest package available). In this case, using the .deb package from rabbitmq.com provided a trouble-free installation as well as the latest version.

转到rabbitmq.com/download.html并选择适合您特定系统的安装文件。 我碰巧正在使用Ubuntu,在安装Ubuntu提供的软件包时遇到了问题(这不是最新的软件包)。 在这种情况下,使用Rabbitmq.com的.deb软件包可提供无故障安装以及最新版本。

Once installed, there is a plugin installation tool available called rabbitmq-plugins.  As an optional step, you can install the rabbitmq_management plugin which will provide a web browser view of the server and make various monitoring/management tasks easier. To enable the plugin on Ubuntu, I ran:

安装后,将有一个名为rabbitmq-plugins的插件安装工具。 作为可选步骤,您可以安装rabbitmq_management插件,该插件将提供服务器的Web浏览器视图,并使各种监视/管理任务更加容易。 要在Ubuntu上启用该插件,我运行了:

sudo rabbitmq-plugins enable rabbitmq_management

Restart the rabbitmq server for changes to take effect:

重新启动rabbitmq服务器以使更改生效:

sudo /etc/init.d/rabbitmq-server restart

Point your browser to http://localhost:55672/mgmt/ for the web-based GUI. The default login user and password will be “guest”.

将浏览器指向基于Web的GUI的http://localhost:55672/mgmt/ 。 默认的登录用户和密码将为“ guest”。

If you prefer a command line tool, rabbitmqctl can be used as an alternative.

如果您更喜欢命令行工具,可以使用rabbitmqctl作为替代。

PIP is a package manager for Python, similar to PHP’s PEAR of PECL, or Perl’s CPAN.  It can be used to easily install Pika, the RabbitMQ library for Python.

PIP是Python的软件包管理器,类似于PHP的PEAR of PECL或Perl的CPAN。 它可用于轻松安装Pika(Python的RabbitMQ库)。

sudo pip install pika

The RabbitMQ homepage provides a few links to different AMQP libraries for PHP, but the only one I found to work without headaches is php-amqplib, available from GitHub.  If you do not already have git installed, please install it as the project’s make file depends on it to clone some additional submodules.

RabbitMQ主页提供了一些指向PHP的不同AMQP库的链接,但是我发现可以正常使用的唯一库是php-amqplib ,可从GitHub获得。 如果尚未安装git,请安装它,因为项目的make文件依赖于它来克隆一些其他子模块。

The full README can be found at the project’s GitHub page, but the short version is as follows:

完整的README可以在项目的GitHub页面上找到,但是简短版本如下:

git clone git://github.com/videlalvaro/php-amqplib.git
cd php-amqplib/
make

The config.php file will contain basic connection settings.  This is the place to make any changes if you have installed the RabbitMQ server anywhere other than localhost.

config.php文件将包含基本连接设置。 如果您已在本地主机以外的任何地方安装RabbitMQ服务器,则可以在此处进行任何更改。

队列和交换 (Queues and Exchanges)

A quick glance at the first few lines of amqp_publisher.php reveals some basic RabbitMQ ideas.

快速浏览一下amqp_publisher.php的前几行, amqp_publisher.php发现一些基本的RabbitMQ思想。

A queue in RabbitMQ can be thought of as a mailbox, or an inbox, or more generally an endpoint at which messages can arrive.  Queues are typically used by consumers to pluck off new messages and make interesting things happen, but both consumers and producers can declare or create queues that they will use.

RabbitMQ中的队列可以被认为是邮箱,收件箱,或更一般地说是消息可以到达的端点。 消费者通常使用队列来发出新消息并使有趣的事情发生,但是消费者和生产者都可以声明或创建他们将使用的队列。

$ch->queue_declare($queue, false, true, false, false);

The extra Boolean parameters correspond to the passive, durable, exclusive, and auto_delete bits used by RabbitMQ.  They are not extremely important right now, but they are fully documented online.

额外的布尔参数对应于RabbitMQ使用的被动,持久,排他和auto_delete位。 它们现在并不十分重要,但已在网上进行了充分记录

queue_declare() creates a queue named “msgs”.  If a queue named “msgs” already exists, nothing extra will happen.  Only one queue per unique name can be created at once.  Because of this, it is typical that both consumer and producer programs will each call queue_declare().  This ensures the queue will always be ready when you are unsure which program (producer or consumer) will be running first.  It is also important to note that messages are not written to queues directly — they must go through an exchange.

queue_declare()创建一个名为“ msgs”的队列。 如果已经存在名为“ msgs”的队列,则不会发生任何其他情况。 每个唯一名称只能一次创建一个队列。 因此,通常,消费者程序和生产者程序都将分别调用queue_declare() 。 这样可以确保在不确定哪个程序(生产者或使用者)将首先运行时,队列始终准备就绪。 同样重要的是要注意,消息不是直接写到队列中的-它们必须经过交换。

An exchange is “all the stuff in the middle” when you think of the shipping service or post office analogy of RabbitMQ.  We don’t send a package directly to a friend’s mailbox, rather we drop it off at some acceptable pickup point, and it is then magically routed to its destination.  In this demo source code, the $exchange name variable was aptly named ‘router’, which is another good way to think of an exchange.

当您想到RabbitMQ的运输服务或邮局类比时,交换就是“中间的一切”。 我们不会将包裹直接发送到朋友的邮箱,而是会在可接受的取件点将包裹放下,然后神奇地路由到目的地。 在此演示源代码中, $exchange name变量被恰当地命名为“ router”,这是考虑交换的另一种好方法。

$ch->exchange_declare($exchange, 'direct', false, true, false);

Again there are some extra parameters here: passive, durable, and auto_delete. See the documentation for more information.

同样,这里还有一些额外的参数:passive,持久性和auto_delete。 请参阅文档以获取更多信息。

The second parameter, ‘direct’, is the type of exchange.  To make sense of what the different types of exchanges are, we need to know about binding keys and routing keys. A routing key is an identifier used when a producer publishes a message to an exchange. A binding key is identifier that binds a particular queue to an exchange. Both keys are limited to 255 bytes in length.

第二个参数“直接”是交换的类型。 为了弄清楚不同类型的交换是什么,我们需要了解绑定键和路由键。 路由密钥是生产者将消息发布到交换机时使用的标识符。 绑定密钥是将特定队列绑定到交换机的标识符。 两个密钥的最大长度限制为255个字节。

In a direct exchange, a routing key is sent with a message to the exchange.  If a queue is bound to that exchange with a binding key that directly matches the routing key, then the message is routed to that queue.

在直接交换中,路由密钥与消息一起发送到交换。 如果队列使用直接与路由密钥匹配的绑定密钥绑定到该交换机,则消息将路由到该队列。

In the diagram below, queue Q1 is bound to an exchange with binding_key="spades", and queue Q2 is bound to the same exchange with binding_key="clubs"

在下图中,队列Q1绑定到具有binding_key="spades"的交换,队列Q2绑定到具有binding_key="clubs"交换

alt

If we send a message of the form (message="Ace", routing_key="spades"), then that message will end up in Q1.  Sending a message in the form (message="King", routing_key="clubs") will result in Q2.  It is possible for Q1 or Q2 to have multiple bindings to the same exchange. Q1 could be bound with “spades” and “hearts”, so that any message with the routing key “spades” or “hearts” will be routed to Q1.

如果我们发送形式为(message="Ace", routing_key="spades")消息,则该消息将在第一季度结束。 以(message="King", routing_key="clubs")的形式发送消息将导致第二季度。 Q1或Q2可能对同一交换具有多个绑定。 Q1可以绑定“黑桃”和“心脏”,因此任何带有路由键“黑桃”或“心脏”的消息都将被路由到Q1。

Another type of exchange is known as fanout. In this type of exchange, routing keys are not important because the exchange will broadcast the message to all known bounded queues.  This is probably the simplest exchange to work with.

另一种交换类型称为扇出。 在这种类型的交换中,路由键并不重要,因为交换会将消息广播到所有已知的有界队列。 这可能是最简单的交换方式。

A more interesting type of exchange is called topic.  A topic exchange uses a dot-delimited group of words for routing keys, which provide more complex routing capabilities. For example, “error.production.database” or “weather.ny.syracuse”.

一种更有趣的交换类型称为主题。 主题交换使用点分隔的一组单词作为路由键,这提供了更复杂的路由功能。 例如,“ error.production.database”或“ weather.ny.syracuse”。

When binding queues to a topic exchange, we can use two special characters to match routing keys in a limited regular expression fashion.

将队列绑定到主题交换机时,我们可以使用两个特殊字符以有限的正则表达式方式匹配路由键。

  • * (asterisk) – matches exactly one word

    *(星号)–精确匹配一个单词
  • # (octothorpe) – matches one or more words

    #(octothorpe)–匹配一个或多个单词

If Q1 is bound with the binding key “*.production.*”, Q1 receives any production message of any severity level.  All of the following routing keys will be routed to Q1:

如果Q1与绑定键“ * .production。*”绑定,则Q1会收到任何严重性级别的生产消息。 以下所有路由密钥都将路由到Q1:

  • error.production.database

    错误生产数据库
  • info.production.database

    信息生产数据库
  • debug.production.web

    debug.production.web

Q2 bound with “info.#” receives any info message, regardless of source.  All of these routing keys would end up in Q2:

与“ info。#”绑定的Q2接收任何信息消息,而不管其来源如何。 所有这些路由密钥将在第二季度结束:

  • info.staging.database

    info.staging.database
  • info.production.web

    info.production.web

Q3 could receive all database messages with binding “*.*.database”.

Q3可以接收所有绑定了“ *。*。database”的数据库消息。

演示生产者和消费者 (A Demo Producer and Consumer)

Let’s create a pair of simple demo programs, one in PHP which will produce messages and one in Python that will act as the consumer.  All messages will be sent through a topic exchange.

让我们创建一对简单的演示程序,一个用PHP生成消息,另一个用Python充当使用者。 所有消息将通过主题交换发送。

<?php
include("config.php");
use PhpAmqpLibConnectionAMQPConnection;
use PhpAmqpLibMessageAMQPMessage;

$exchange = "rabbitmq_demo";
$exchangeType = "topic";
$queue = "events";

$message = $_SERVER["argv"][1];
$routingKey = $_SERVER["argv"][2];

$connection = new AMQPConnection(HOST, PORT, USER, PASS, VHOST);
$channel = $connection->channel();

// declare/create the queue
$channel->queue_declare($queue, false, true, false, false);

// declare/create the exchange as a topic exchange.
$channel->exchange_declare($exchange, $exchangeType, false, false, false);

$msg = new AMQPMessage($message, array("content_type" => "text/plain"));

$channel->basic_publish($msg, $exchange, $routingKey);
print "Sent $message ($routingKey)n";
$channel->close();
$connection->close();
import sys
import pika

EXCHANGE = "rabbitmq_demo"
EXCHANGE_TYPE = "topic"
QUEUE = "events"

# consume callback function
def callback(ch, method, properties, body):
   print " - Received '%s' on routing_key %s" % (body, method.routing_key)
   # Anything else could happen here:
   # Send an email alert, send an xmnp message, trigger another process, etc

connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))
channel = connection.channel()
channel.exchange_declare(exchange=EXCHANGE, type=EXCHANGE_TYPE)
result = channel.queue_declare(queue=QUEUE, durable=True)

if len(sys.argv) != 2:
   sys.exit("You must provide a binding key.")
else:
   key = sys.argv[1]
channel.queue_bind(exchange=EXCHANGE, queue=QUEUE, routing_key=key)

print " Listening for messages..."
channel.basic_consume(callback, queue=QUEUE, no_ack=True)
channel.start_consuming()

The producer PHP program will take two command line arguments: the message itself and the routing key.  The consumer Python program will take a binding key as its only argument.  They will create a topic exchange called “rabbitmq_demo” and a queue called “events”.

生产者PHP程序将使用两个命令行参数:消息本身和路由键。 消费者Python程序将把绑定键作为唯一参数。 他们将创建一个名为“ rabbitmq_demo”的主题交换和一个名为“ events”的队列。

Run the Python program as follows:

运行Python程序,如下所示:

python topic_consumer.py python topic_consumer.py errors.production.*

This will listen for production errors from any source (a database, web server, etc.).

这将侦听来自任何来源(数据库,Web服务器等)的生产错误。

Now run the PHP program with an error message and routing key:

现在,运行带有错误消息和路由键PHP程序:

php topicProducer.php "the prod database has been deleted. call the authorities" errors.production.database

You should see the message picked up by the Python consumer.

您应该看到Python使用者收到的消息。

Listening for messages...
- Received 'the prod database has been deleted. call the authorities' on routing_key errors.production.database

This message sent from the producer should be ignored by the consumer since its routing key does not match:

从生产者发送的此消息应由消费者忽略,因为其路由密钥不匹配:

php topicProducer.php "DNS server timeout" warnings.prod.dns

You can press Control+C any time to stop the Python consumer, then start it back up with different binding keys to play around with how messages are routed.

您可以随时按Control + C来停止Python使用者,然后使用不同的绑定键将其启动以进行消息路由。

This basic example should do two things.  First, it should provide a way to try out different routing keys and see how topic exchanges can route messages.  Second, it should get you thinking about how relatively simple it is to provide a means of communication among any number of independent programs written in any permutation of languages.

这个基本示例应该做两件事。 首先,它应该提供一种方法来试用不同的路由键,并查看主题交换如何路由消息。 其次,它应该让您考虑在任何以多种语言编写的独立程序之间提供一种通信手段是多么简单。

结论 (Conclusion)

What if you worked in the operations world maintaining a collection of production level physical servers and software services?  And what if you had a everything from Perl to Ruby to Haskell.NET programs all monitoring different parts of your system and needed a way for them to report back through a central channel?  RabbitMQ can make your life a lot easier.  Especially if your consumer program was able to tap into an e-mail or XMNP library to alert real live human beings of production level problems.

如果您在运营领域工作,维护一组生产级别的物理服务器和软件服务,该怎么办? 而且,如果您拥有从Perl到Ruby到Haskell.NET的所有程序,它们都监视系统的不同部分,并且需要一种方法来使它们通过中央通道进行报告,那么该怎么办? RabbitMQ可以使您的生活更加轻松。 尤其是如果您的消费者程序能够利用电子邮件或XMNP库来向实际的人警告生产级问题。

Or what if you had a website front end written in PHP that was responsible for uploading and then processing a large amount of user photos or videos?  You may want to shift the processing burden to speedier or specialized language that can run in the background or on a different server instance.  RabbitMQ can be configured as a worker queue for such a situation.

或者,如果您有一个用PHP编写的网站前端负责上载然后处理大量用户照片或视频,该怎么办? 您可能希望将处理负担转移到可以在后台或其他服务器实例上运行的更快的语言或专用语言。 在这种情况下,RabbitMQ可以配置为工作队列。

Hopefully I’ve sparked an interest in RabbitMQ, and maybe it will turn out to be the right tool for a particular decoupling or scalability problem you might be facing.  It’s pretty easy to install and has wide selection of client libraries for your language of choice.  The examples of an operations monitoring system and a worker queue for executing large jobs are just two real world example where RabbitMQ can be helpful, but there may be many more scenarios where it could help.  Just use your imagination.

希望我引起了对RabbitMQ的兴趣,也许它将成为解决您可能面临的特定去耦或可伸缩性问题的正确工具。 它非常容易安装,并且可以选择多种语言来选择客户端库。 操作监视系统和执行大型作业的工作人员队列的示例只是两个真实的示例,RabbitMQ可能会有所帮助,但可能还有很多其他方案可以提供帮助。 只是发挥您的想象力。

Image via Fotolia

图片来自Fotolia

翻译自: https://www.sitepoint.com/message-brokering-with-rabbitmq/

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值