• [译]rabbitmq 2.2 Building from the bottom: queues


    我对rabbitmq学习还不深入,这些翻译仅仅做资料保存,希望不要误导大家。

    You have consumers and producers under your belt, and now you’re itching to get

    started eh? Not so fast. First, you need to understand queues. Conceptually, there are

    three parts to any successful routing of an AMQP message: exchanges, queues, and

    bindings. The exchanges are where producers publish their messages, queues are

    where the messages end up and are received by consumers, and bindings are how the

    messages get routed from the exchange to particular queues. Before you get to examine

    exchanges and bindings, you need to understand what a queue is and how it

    works. Take a look at figure 2.3.

    已经有了consumer和producer的经验,现在已经恨不得要开始了?没那么快。

    首先,你需要理解queue。

    为了成功routing一个AMQP消息,有3个必须的部分:exchange,queue,binding。

    exchange - producer发送消息的地方

    queue - message结束,被consumer接收的地方

    binding - 消息如何从exchange被路由到queue中

    As we said when we were talking about producers and consumers, queues are like

    named mailboxes. They’re where messages end up and wait to be consumed. Consumers

    receive messages from a particular queue in one of two ways:

    queue正如mailbox,是message 结束并且等待被消费的地方。

    consumer以下面2个方式从指定的queue中接收消息:

    1 By subscribing to it via the basic.consume AMQP command. This will place the

    channel being used into a receive mode until unsubscribed from the queue.

    While subscribed, your consumer will automatically receive another message

    from the queue (as available) after consuming (or rejecting) the last received

    message. You should use basic.consume if your consumer is processing many

    messages out of a queue and/or needs to automatically receive messages from a

    queue as soon as they arrive.

    1.通过 basic.consume订阅。在取消订阅之前,channel会被设置为接收模式。

    订阅之后,consumer在消费(或拒绝)了最后的收到的消息之后,将会自动收到queue(如果存在)中的消息。

    如果你的consumer会处理许多queue之外的消息,并且(或者)需要尽快的自动从queue中接收消息,

    那么你应该使用basic.consume设置为订阅。

    2 Sometimes, you just want a single message from a queue and don’t need to be

    persistently subscribed. Requesting a single message from the queue is done by

    using the basic.get AMQP command. This will cause the consumer to receive

    the next message in the queue and then not receive further messages until the

    next basic.get. You shouldn’t use basic.get in a loop as an alternative to

    basic.consume, because it’s much more intensive on Rabbit. basic.get essentially

    subscribes to the queue, retrieves a single message, and then unsubscribes

    every time you issue the command. High-throughput consumers should always

    use basic.consume.

    2.有时,你只是想要queue中的单个的消息。

    从queue中获取一个消息可以使用basic.get,可以获得queue中的下一条消息。

    在再次调用basic.get之前,你不会受到消息。

    不要用循环basic.get来代替basic.consume,因为这会很频繁。

    basic.get本质上是订阅了一个queue,接收单个消息,然后取消订阅。

    高吞吐的consumer应该使用basic.consume。

    If one or more consumers are subscribed to a queue, messages are sent immediately

    to the subscribed consumers. But what if a message arrives at a queue with no subscribed

    consumers? In that case, the message waits in the queue. As soon as a consumer

    subscribes to the queue, the message will be sent to that consumer. A more

    interesting question is how messages in a queue are distributed when multiple consumers

    are subscribed to the same queue.

    如果一个或者多个consumer在订阅一个queue,消息会马上发送到订阅的consumer。

    但是如果一个消息到达一个没有consumer订阅的queue中会怎样呢?

    消息会保存在queue中等待。当consumer订阅了queue,消息会被发送到consumer。

    更有意思的问题是:当多个consumer订阅了同一个queue,消息是如何分布的?

    When a Rabbit queue has multiple consumers, messages received by the queue are

    served in a round-robin fashion to the consumers. Each message is sent to only one

    consumer subscribed to the queue. Let’s say you had a queue named seed_bin and consumers

    Farmer Bob and Farmer Esmeralda subscribed to seed_bin. As messages arrive

    in seed_bin, the deliveries would look like this:

    1 Message_A arrives in the seed_bin queue.

    2 RabbitMQ sends Message_A to Farmer Bob.

    3 Farmer Bob acknowledges receipt of Message_A.

    4 RabbitMQ removes Message_A from the seed_bin queue.

    5 Message_B arrives in the seed_bin queue.

    6 RabbitMQ sends Message_B to Farmer Esmeralda.

    7 Farmer Esmeralda acknowledges receipt of Message_B.

    8 RabbitMQ removes Message_B from the seed_bin queue.

    当一个queue有多个consumer,queue收到消息后会循环发到consumer。

    每个消息只会发到一个订阅的consumer。

    假设你有一个queue,名字是seed_bin,已订阅的consumer 有 Bob 和 Esmeralda。

    当消息到达seed_bin:

    1. 消息A到达seed_bin

    2. rabbitmq发送消息A到Bob

    3. Bob 确认收到消息A

    4. rabbitmq将消息A移出队列seed_bin

    5. 消息B到达seed_bin

    6. rabbitmq发送消息B到Esmeralda

    7. Esmeralda 确认收到消息A

    8. rabbitmq将消息B移出队列seed_bin

    You may have noticed that Farmers Bob and Esmeralda did something we haven’t

    talked about yet: they acknowledged receipt of the message. Every message that’s

    received by a consumer is required to be acknowledged. Either the consumer must

    explicitly send an acknowledgement to RabbitMQ using the basic.ack AMQP command,

    or it can set the auto_ack parameter to true when it subscribes to the queue.

    When auto_ack is specified, RabbitMQ will automatically consider the message

    acknowledged by the consumer as soon as the consumer has received it. An important

    thing to remember is that message acknowledgements from the consumer have nothing

    to do with telling the producer of the message it was received. Instead, the acknowledgements

    are a way for the consumer to confirm to RabbitMQ that the consumer has

    correctly received the message and RabbitMQ can safely remove it from the queue.

    你好像注意到了一些新东西:"Bob 确认收到消息A"。

    每个consumer收到消息后,是需要返回acknowledged的。

    可以通过basic.ack设置自动返回,或者程序手动返回。

    如果设置了自动返回(auto_ack),当consumer收到消息后会马上返回acknowledged。

    需要记住的是,即使consumer返回了acknowledged,也不会告诉producer。

    只能代表consumer已经收到了消息,queue可以安全地移除消息了。

    If a consumer receives a message and then disconnects from Rabbit (or unsubscribes

    from the queue) before acknowledging, RabbitMQ will consider the message

    undelivered and redeliver it to the next subscribed consumer. If your app crashes, you

    can be assured the message will be sent to another consumer for processing. On the

    other hand, if your consumer app has a bug and forgets to acknowledge a message,

    Rabbit won’t send the consumer any more messages. 

    如果consumer收到了消息,但是还没回复acknowledged,然后与rabbitmq断链了(或者取消订阅),

    rabbitmq认为消息被没有被正确投递,然后投递到下一个consumer中。

    如果程序崩溃了,消息也是会被投递到下一个consumer中。

    另一方面,如果你的consumer程序有bug并且忘记返回acknowledged,

    rabbitmq将不会再向这个consumer投递任何消息。

    This is because Rabbit considers

    the consumer not ready to receive another message until it acknowledges the last one

    it received. You can use this behavior to your advantage. If processing the contents of

    a message is particularly intensive, your app can delay acknowledging the message

    until the processing has finished. This will keep Rabbit from overloading you with

    more messages than your app can handle.

    这是因为rabbitmq认为consumer收到最后一条消息后,如果没有返回acknowledged,

    则该consumer处于未准备好的状态。

    你可以利用这个特性。

    在程序未处理完之前,不要返回acknowledged。

    这可以防止rabbitmq向你的程序发送大量的程序导致程序超负荷。

    What if you want to specifically reject a message rather than acknowledge it after

    you've received it? For example, let’s say that when processing the message you

    encounter an uncorrectable error, but it only affects this consumer due to a hardware

    issue (this is a good reason to never acknowledge a message until it’s processed). As

    long as the message hasn’t been acknowledged yet, you have two options:

    1 Have your consumer disconnect from the RabbitMQ server. This will cause

    RabbitMQ to automatically requeue the message and deliver it to another consumer.

    he advantage to this method is that it works across all versions of

    RabbitMQ. The disadvantage is the extra load put on the RabbitMQ server

    from the connecting and disconnecting of your consumer (a potentially significant

    load if your consumer is encountering errors on every message).

    如何拒绝一条收到的消息呢?

    假设你的程序处理一条消息时发生了无法修复的错误,但是只是硬件错误。

    当消息未被acknowledged,你有2个选择:

    1.consumer程序主动与rabbitmq断链,这会导致rabbitmq自动把消息从新放到队列中并

    投递给另外一个consumer。

    好处是在rabbitmq的任何版本,你都可以这么干。

    坏处是导致了额外的断链和建链(如果每条消息都产生这个错误,那这问题很严重)。

    2 If you’re running RabbitMQ 2.0.0 or newer, use the basic.reject AMQP command.

    basic.reject does exactly what it sounds like: it allows your consumer

    to reject a message RabbitMQ has sent it. If you set the requeue parameter of

    the reject command to true, RabbitMQ will redeliver the message to the next

    subscribed consumer. Setting requeue to false will cause RabbitMQ to remove

    the message from the queue immediately without resending it to a new consumer.

    You can also discard a message simply by acknowledging it (this method

    of discarding has the advantage of working with all versions of RabbitMQ). This

    is useful if you detect a malformed message you know none of your consumers

    will be able to process.

    2. 如果rabbitmq的版本为2.0.0以上,可以使用 basic.reject,

    它可以拒绝已经收到的消息。

    如果设置为true,rabbitmq会重新投递该消息到其他已订阅的consumer。

    如果设置requeue会导致rabbitmq从queue中移除这条消息,不会发送到其他consumer。

    当然你也可以回复acknowledging(假丢弃,所有版本通用),这是一个很有用的方法,

    例如你收到一个错误的消息,即使投递给其他consumer,别的consumer也无法处理,

    那就通过这个方法丢弃他。

    NOTE 

    When discarding a message, why would you want to use the

    basic.reject command with the requeue parameter set to false instead of

    acknowledging the message? Future versions of RabbitMQ will support a special

    “dead letter” queue where messages that are rejected without requeuing

    will be placed. A dead letter queue lets you inspect rejected/undeliverable

    messages for issues. If you want your app to automatically take advantage of

    the dead letter queue feature when it’s added to Rabbit, use the reject command

    with requeue set to false.

    须知:

    为什么丢弃一个消息时,要使用basic.reject而不是直接acknowledging?

    因为以后版本的rabbitmq会支持“dead letter” queue,用于存放被reject并且不被

    重新放入queue的消息。

    你可以通过“dead letter” queue,查看reject或者无法投递的消息。

    如果你想自己弄这么一个“dead letter” queue,那么在使用reject的时候,

    rqueue属性设置false。

    There’s one more important thing you need to know about queues: how to create

    them. Both consumers and producers can create queues by using the queue.declare

    AMQP command. But consumers can’t declare a queue while subscribed to another

    one on the same channel. They must first unsubscribe in order to place the channel

    in a “transmit” mode. When creating a queue, you usually want to specify its name.

    The name is used by consumers to subscribe to it, and is how you specify the queue

    when creating a binding. If you don’t specify a name, Rabbit will assign a random

    name for you and return it in the response to the queue.declare command (this is

    useful when using temporary “anonymous” queues for RPC-over-AMQP applications, as

    you’ll see in chapter 4). 

    如何创建queue:

    所有consumer和producer可以都可以使用queue.declare创建queue。

    但是consumer不能在一个channel中订阅一个queue,声明另一个queue。

    必须先取消订阅,使channel处于 "transmit" 模式。

    当创建一个queue时,可以设置名字。

    这个名字,在consumer订阅时会用到,在创建一个binding关系时会用到。

    如果在使用queue.declare创建queue时没有指定名字,那么rabbitmq会分配一个随机

    名字,并返回。

    Here are some other useful properties you can set for the

    queue:

    以下是你可以设置的queue的一些有用属性:

    ~exclusive�When set to true, your queue becomes private and can only be

    consumed by your app. This is useful when you need to limit a queue to only

    one consumer.

    ~exclusive 当设置为true,这个queue是你的程序私有的。单个队列单个consumer。

    ~auto-delete�The queue is automatically deleted when the last consumer

    unsubscribes. If you need a temporary queue used only by one consumer, combine

    auto-delete with exclusive. When the consumer disconnects, the queue

    will be removed.

    ~auto-delete  当最后一个consumer取消订阅,queue会被自动删除。如果你需要

    一个只被一个consumer使用的临时queue,设置auto-delete和exclusive,

    当consumer断链,queue会被删除。

    What happens if you try to declare a queue that already exists? As long as the declaration

    parameters match the existing queue exactly, Rabbit will do nothing and return

    successfully as though the queue had been created (if the parameters don’t match,

    the declaration attempt will fail). If you just want to check whether a queue exists, you

    can set the passive option of queue.declare to true. With passive set to true,

    queue.declare will return successfully if the queue exists, and return an error without

    creating the queue if it doesn’t exist.

    如果你声明一个已经存在的queue,会怎么样?

    只要声明的参数和已经存在的queue正确匹配,rabbitmq会返回成功,

    (如果参数不匹配,会返回失败)。

    如果你只是想看下这个queue是否存在,你可以设置queue.declare的passive为true,

    这样的话,如果queue存在queue.declare会返回成功,然后返回一个错误,并且如果这个queue

    不存在,rabbitmq不会创建它。

    When you’re designing your apps, you’ll most likely ask yourself whether your producers

    or consumers should create the queues you need. It might seem that the most

    natural answer is that your consumers should create your queues. After all, they’re the

    ones that need to subscribe, and you can’t subscribe to a queue that doesn’t exist,

    right? Not so fast. You need to first ask yourself whether the messages your producers

    create can afford to disappear. Messages that get published into an exchange but have

    no queue to be routed to are discarded by Rabbit. 

    当你设计程序时,你需要想清楚你的producer或者consumer是否需要创建queue。

    通常来说,你都觉得需要。

    毕竟,你需要订阅一个queue,并且你不能订阅一个不存在的queue。

    你需要首先问问自己,你的producer能否接受消息丢失?

    消息投递到exchange中但是没有对应的queue,导致rabbitmq无法正确路由该消息。

    So if you can’t afford for your messages

    to be black-holed, both your producers and your consumers should attempt to

    create the queues that will be needed. On the other hand, if you can afford to lose

    messages or have implemented a way to republish messages that donˇt get processed

    (weˇll show you how to do this) you can have only your consumers declare the queues.

    Queues are the foundational block of AMQP messaging:

    ~ They give you a place for your messages to wait to be consumed.

    ~ Queues are perfect for load balancing. Just attach a bunch of consumers and let

    RabbitMQ round-robin incoming messages evenly among them.

    ~ Theyˇre the final endpoint for any messages in Rabbit (unless they get blackholed).

    With queues under your belt, youˇre ready to move to the next building block of

    Rabbit: exchanges and bindings!

    所以如果你不能接受你的消息被black-holed,

    那么你的producer,consumer都应该尝试创建所需的queue。

    另一方面,如果你能接受丢消息的问题,或者你有办法重发没被处理的消息,

    你可以只在consumer中声明queue。

    queue是AMQP消息发送的基础模块:

    ~queue可以作为消息被消费前存放的地方

    ~queue可以用于负载均衡。

    ~queue是消息在rabbitmq中的终点(除非消息被blackholed)

  • 相关阅读:
    深入理解memcached
    如何查看你的 memcached 的状态
    转: Linux 技巧:让进程在后台可靠运行的几种方法
    centos 如何用 rsyslog 搭建本地日志服务(续1: omprog模块与php deamon的配合使用)
    转: 解决MSYS2下的中文乱码问题
    解决windows下vim方向键变成 ABCD 的问题
    centos 如何用 rsyslog 搭建本地日志服务
    转:理解 Linux 的硬链接与软链接
    php include include_once require require_once 的区别与联系
    让块级元素水平垂直居中
  • 原文地址:https://www.cnblogs.com/solohac/p/4154177.html
Copyright © 2020-2023  润新知