有哪些优点

  • 可靠性:RabbitMQ 提供了多种技术可以让你在性能和可靠性之间进行权衡。这些技术包括持久性、投递确认、发布者证实和高可用性。

  • 灵活的路由:提供了多种内置交换机类型。如果你有更复杂的路由需求,可以将这些交换机组合起来使用,甚至你可以写自己的交换机类型

  • 多协议和广泛的客户端:RabbitMQ 支持多种消息协议中的消息传递以及 你能想到的语言几乎都有与其相适配的 RabbitMQ 客户端。

原理

  • Broker: 接收和分发消息的应用,RabbitMQ Server就是Message Broker。
  • Channel: 如果每一次访问都建立一个Connection,在消息量大的时候建立Connection的开销将是巨大的,效率也较低。Channel作为轻量级的Connection极大减少了操作系统建立connection的开销。线程池的思想。
  • Exchange: message到达broker的第一站,根据分发规则,匹配查询表中的routing key,分发消息到queue中去。常用的类型有:direct (point-to-point), topic (publish-subscribe) and fanout (multicast)。
  • Queue: 消息最终被送到这里等待consumer取走。一个message可以被同时拷贝到多个queue中。
  • Binding: exchange和queue之间的虚拟连接,binding中可以包含routing key。Binding信息被保存到exchange中的查询表中,用于message的分发依据。其实可以理解为Exchange与Queue的关系对照表。

工作流程

  • 消息被发布到exchanges,通常可将exchanges比作邮局或者邮箱
  • exchanges将消息副本分发到queues,按照bindings中的规则
  • AMQP brokers传递消息给与queues关联的consumers,或者consumers按照需求从queues拉取信息

以一个例子来解释Exchange、Queue、Binding三者之间的关系:乘客乘坐飞机到北京。
乘客是消息,飞机就是Exchange,Queue就是目的地北京,飞机可以通过不同的路线到达北京,这个路线就是Binding

交换机(exchange)

$connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');
$channel = $connection->channel();
$channel->exchange_declare('direct_logs', 'direct', false, false, false);

类型

Name(交换机类型)

Default pre-declared names(预声明的默认名称)

Direct exchange(直连交换机)  (Empty string) and amq.direct
Fanout exchange(扇型交换机) amq.fanout 
Topic exchange(主题交换机) amq.topic
Headers exchange amq.match (and amq.headers in RabbitMQ)

除交换机类型外,在声明交换机时还有许多其他的属性,其中最重要的几个分别是:

  • Durability (exchanges survive broker restart) :持久化(消息代理重启后,交换机是否还存在)
  • Auto-delete (exchange is deleted when all queues have finished using it) : 自动删除(当所有与之绑定的消息队列都完成了对此交换机的使用后,删掉它)
  • Arguments (these are broker-dependent) :其他属性(依赖代理本身)

默认交换机

default exchange是一个没有名称的、被broker预先申明的direct exchange。它所拥有的一个特殊属性使它对于简单的应用程序很有作用:每个创建的queue会与它自动绑定,使用queue名称作为routing key。
举例说,当你申明一个名称为“search-indexing-online”的queue时,AMQP broker使用“search-indexing-online”作为routing key将它绑定到default exchange。因此,一条被发布到default exchange并且routing key为”search-indexing-online”将被路由到名称为”search-indexing-online”的queue

直连交换机

直连型交换机(direct exchange)是根据消息携带的路由键(routing key)来将消息投递给队列的。直连交换机用来处理消息的单播路由(unicast routing)(尽管它也可以处理多播路由)。下边介绍它是如何工作的:

  • 一个队列绑定到某个交换机上,同时赋予该绑定一个路由键(routing key)
  • 当一个携带着路由键为R的消息被发送给直连交换机时,交换机会把它路由给绑定值同样为R的队列。

扇型交换机

扇型交换机(funout exchange)将消息路由给绑定到它身上的所有队列,而不理会绑定的路由键。如果N个队列绑定到某个扇型交换机上,当有消息发送给此扇型交换机时,交换机会将消息的拷贝分别发送给这所有的N个队列。扇型交换机处理消息的广播路由(broadcast routing)。

主题交换机(Topic Exchange)

主题交换机(topic exchanges)通过对消息的路由键和队列到交换机的绑定模式之间的匹配,将消息路由给一个或多个队列。主题交换机经常用来实现各种分发/订阅模式及其变种。主题交换机通常用来实现消息的多播路由(multicast routing)

头交换机(Headers Exchange)

对于消息的路由来说,有时使用多个属性来表示消息头比用路由键更方便,头交换机(headers exchange)就是为此而生的。头交换机使用多个消息属性来代替路由键建立路由规则。这个规则的建立是通过判断消息头的值是否与指定绑定相匹配而来的。

头交换机可以视为直连交换机的另一种表现形式。头交换机能够像直连交换机一样工作,不同之处在于头交换机的路由规则是建立在头属性值之上,而不是路由键。路由键必须是一个字符串,而头属性值则没有这个约束,它们甚至可以是整数或者哈希值(字典)等。

路由

绑定(Binding)是交换机(exchange)将消息(message)路由给队列(queue)所需遵循的规则。如果要指示交换机-E将消息路由给队列-Q,那么Q就需要与E进行绑定。绑定操作需要定义一个可选的路由键(routing key)属性给某些类型的交换机。路由键的意义在于从发送给交换机的众多消息中选择出某些消息,将其路由给绑定的队列。

$channel->basic_publish($msg, 'direct_logs', 'error');

最后一个 参数 error 就是 routing_key,具体可参考文档的用法。

消息确认

为了防止消息丢失,RabbitMQ 提供了消息响应(acknowledgments)。消费者会通过一个 ack(响应),告诉 RabbitMQ 已经收到并处理了某条消息,然后RabbitMQ 就会释放并删除这条消息。如果消费者(consumer)挂掉了,没有发送响应,RabbitMQ 就会认为消息没有被完全处理,然后重新发送给其他消费者(consumer)。这样,及时工作者(workers)偶尔的挂掉,也不会丢失消息。

消息是没有超时这个概念的;当工作者与它断开连的时候,RabbitMQ 会重新发送消息。这样在处理一个耗时非常长的消息任务的时候就不会出问题了。消息响应默认是开启的。之前的例子中我们可以使用 no_ack=True 标识把它关闭。是时候移除这个标识了,当工作者(worker)完成了任务,就发送一个响应。

$callback = function ($msg) {

    $channel = $msg->delivery_info['channel'];
$channel->basic_ack($msg->delivery_info['delivery_tag']); echo ' [x] Received ', $msg->body, "\n";
}; $channel->basic_consume('hello', '', false, false, false, false, $callback);
basic_consume 函数第 4 个参数 no_ack 设置为 false, 就是要消息确认。 通过 callback 回调处理。一个很容易犯的错误就是忘了 basic_ack,后果很严重。消息在你的程序退出之后就会重新发送,如果它不能够释放没响应的消息,RabbitMQ 就会占用越来越多的内存。

为了排除这种错误,你可以使用 rabbitmqctl 命令,输出 messages_unacknowledged 字段:

$ sudo rabbitmqctl list_queues name messages_ready messages_unacknowledged
Listing queues ...
hello
...done.

消息持久化

如果你没有特意告诉 RabbitMQ,那么在它退出或者崩溃的时候,将会丢失所有队列和消息。为了确保信息不会丢失,有两个事情是需要注意的:我们必须把“队列”和“消息”设为持久化。

首先,为了不让队列消失,需要把队列声明为持久化(durable):

$channel->queue_declare('hello', false, true, false, false);

第 3 个参数就是持久化的设置.

参考文献

AMQP 0-9-1 和 AMQP 模型高阶概述

消息队列协议AMQP的设计原理

RabbitMQ文档

RabbitMQ 初探的更多相关文章

  1. RabbitMq初探——消息均发

    消息均发 前言 由前文 RabbitMq初探——消息分发 可知,rabbitmq自带分发机制——消息会按顺序的投放到该队列下的多个消费者,例如1,3,5投放消费者C1,2,4,6投放消费者C2. 这就 ...

  2. RabbitMq初探——安装

    rabbitmq Server安装 rabbitmq server安装很简单. 安装erlang环境 rpm -ihv erlang-18.1-1.el6.x86_64.rpm rpm -ihv ra ...

  3. RabbitMq初探——用队列实现RPC

    rabbitmq构造rpc 前言 rpc——remote procedure call 远程调用.在我接触的使用过http协议.thrift框架来实现远程调用.其实消息队列rabbitmq也可以实现. ...

  4. RabbitMq初探——发布与订阅

    publish and subscribe 前言 前面的例子 我们都是用到的都是消息单一消费,即一条消息被单个消费者消费.像微博系统的消息推送,是一条消息推送给所有订阅到该频道的用户. 这里我们就需要 ...

  5. RabbitMq初探——消息持久化

    消息持久化 前言 通过上一节,我们知道,有消息确认机制,保证了当消费者进程挂掉后,消息的不丢失. 但是如果rabbitmq挂掉呢?它的队列和消息都会丢失的.为了保证消息在rabbitmq挂掉重启后不丢 ...

  6. RabbitMq初探——消息确认

    消息确认机制 前言 消息队列的下游,业务逻辑可能复杂,处理任务可能花费很长时间.若在一条消息到达它的下游,任务刚处理了一半,由于不确定因素,下游的任务处理进程 被kill掉啦,导致任务无法执行完成.而 ...

  7. RabbitMq初探——消息分发

    消息分发 前言 我们在用到消息队列的场景,一般是处理逻辑复杂,耗时,所以将同步改为异步处理,接入队列,下游处理耗时任务. 队列消息数量很大,且下游worker进程(消费者)处理耗时长,所以就有了任务的 ...

  8. RabbitMq初探——php的一个demo

    <?php /** * Created by PhpStorm. * Date: 2017/10/17 * Time: 16:21 */ class Rabbit { public functi ...

  9. RabbitMq初探——Hello World

    HelloWorld 前言 这里我们弱化broker内部构造.将整体分为三部分. P:producer.生产者. C:Consumer.消费者. queue:队列. 后面的代码都依赖于 the php ...

随机推荐

  1. Spring简单获得实体类的实例, 使用ApplicationContext()方法的几点注意事项

    今天接触了Spring的初步用法, 感觉跟实例化实体类没啥区别, 像这种简单的代码还不如直接实例化来的方便, 这样使用Spring的话总共需要三个文件 第一个当然是一个实体类了, 定义好属性, get ...

  2. alter 和 update的用法和区别

    alter的增加和删除alter table xs_kc add xuefen number;alter table xs_kc drop column xuefen; 删除的时候必须使用column ...

  3. 人机大战中AlphaGo及其执子人黄士杰

    2016年3月9日注定要写入围棋界的历史.IT界的历史以及科学界的历史.当天,韩国著名围棋棋手李世石VS谷歌AlphaGo的人机大战赛在韩国首尔举行.对弈的一方为拥有1200多个处理器的谷歌人工智能系 ...

  4. ECMAScript5新特性之Object.isExtensible、Object.preventExtensions

    阻止对象扩展后: 1 不能添加属性. 2 可以修改属性的值. 3 可以删除属性. 4 可以修改属性描述符. var fruit = { name : '苹果', desc : '红富士' }; // ...

  5. ASP.NET中修改从数据库获取的datatable中的值

    有些时候,我们从数据库表中获取一个实体的对象,但有些内容并不是最终显示的内容,格式也都是不一样.经过一番尝试,发现datatable中的数值如果跟想要改变的类型不一致,就无法更改,只有添加新列,然后把 ...

  6. PAT L1-009 N个数求和(模拟分数加法)

    本题的要求很简单,就是求N个数字的和.麻烦的是,这些数字是以有理数“分子/分母”的形式给出的,你输出的和也必须是有理数的形式. 输入格式: 输入第一行给出一个正整数N(<=100).随后一行按格 ...

  7. [leetcode]785. Is Graph Bipartite? [bai'pɑrtait] 判断二分图

    Given an undirected graph, return true if and only if it is bipartite. Example 1: Input: [[1,3], [0, ...

  8. Qt中使用python--Hello Python!

    step1:install Python (version 2.7 or higher): step2:The configuration is as follows: 1.create qt con ...

  9. 面向对象设计模式纵横谈:Bridge 桥接模式(笔记记录)

    桥接模式是一个比较难理解的设计模式,设计和分析的时候也不容易把握,咱们听听“李建忠”老师是怎么来讲的.我们还是从演变的角度来说问题,一步一步的来把问题说清楚.先谈谈“抽象”和“实现”的关系. 抽象与实 ...

  10. 客户关系管理系统CRM

    http://www.cnblogs.com/Michael2397/tag/SSH%E9%A1%B9%E7%9B%AE-CRM/   客户关系管理系统