RabbitMQ实战:性能和安全

本系列是「RabbitMQ实战:高效部署分布式消息队列」书籍的总结笔记。php

前两篇介绍了RabbitMQ在可用性、监控方面的考虑,这是基础保障,由于在某些场景下是不允许丢失消息的,但它和性能每每是对立的,须要根据业务场景作取舍。算法

当处理一些敏感数据时,好比银行卡信息,须要考虑安全性问题,上一篇总结了数据传输安全方面的知识点,这里就比较好理解了。数据库

经过介绍,你会了解到:安全

  • 对速度的考虑
  • 对内存和进程的考虑
  • 对安全的考虑

对速度的考虑

有不少因素影响RabbitMQ投递消息的速度,包括消息持久化、路由算法、绑定数目、以及消息确认策略等,下面分别来介绍。bash

消息持久化

当发布消息时,须要决定丢失其中的任何消息是否能够接受,若是能够接受,能够将delivery-model设置为1,消息就不会持久化到硬盘了。服务器

消息确认

当消费消息时,能够在队列订阅时,经过设定no-ack标记加快消息投递,若是设置为true,服务器就会在消息发送给客户端后自动将其出队。微信

这样,处理完消息以后就无须再发送确认消息回服务器了,能极大地加快消费者消费消息,但因为某些缘由链接中断了,或客户端应用程序发生故障了,消息就永远消息了。数据结构

路由算法和绑定规则

前面介绍了3种类型的交换器:direct、fanout、topic,每种交换器表明了服务器实现的特定路由算法,会根据消息的路由键以及队列与交换器之间的绑定来选择队列。异步

在服务器端,交换器和绑定做为记录条目存储在Mnesia数据库中,当匹配消息路由键时,会尝试查找对应路由键的绑定。分布式

fanout交换器在路由消息的时候,会忽略路由键,不须要进行查找。direct只有一个绑定,也会比较快,topic存储的路由信息比较复杂,因为路由键能够包含以点分隔的多个词,因此匹配消息路由键不只仅是简单字符串的匹配,也会占用更多内存。

RabbitMQ实现了trie树数据结构用来存储绑定路由键模式,以支持快速查询,关于这种数据结构,我以前没接触过,听说比桶状哈希表还快,后面专门写一篇介绍这个数据结构吧。

投递消息

在交换器找到消息须要路由的目的地以后,会将目的地列表返回给rabbit_router,以后会将消息的副本投递到每个目的地,若是发布的消息中mandatory和immediate标记设置为false,这个过程会以异步方式执行,从客户端角度看,服务器会变得很快,不然会同步投递。

当mandatory标志位设置为true时,若是exchange根据自身类型和消息routeKey没法找到一个符合条件的queue,那么会调用basic.return方法将消息返还给生产者,当mandatory设为false时,出现上述情形broker会直接将消息扔掉。

当immediate标志位设置为true时,若是exchange在将消息route到queue(s)时发现对应的queue上没有消费者,那么这条消息不会放入队列中。当与消息routeKey关联的全部queue(一个或多个)都没有消费者时,该消息会经过basic.return方法返还给生产者。

假如找到了投递的队列且有消费者准备好接收消息,若是队列为空,消息会直接发送给消费者,不会通过队列这一步,会极大提高速度,因此制定容量规划并计算消息的进出率时,应尽量让队列保持为空,若是消费滞后致使队列填满的化,服务器会收到内存告警,并将消息刷出磁盘。

还有个参数要注意:auto-ack,消费者接收到消息后,会马上确认消息,而不用等到逻辑处理好。

消息路由过程

以上说的提升速度的方法大部分都会牺牲可用性,要根据不一样的业务场景进行平衡。

对内存和进程的考虑

在设计应用程序的时候,会有两个基本限制:选择的技术容许作什么,以及当前硬件设定容许作什么。上面讨论了第一点:不一样消息路由和分发算法如何影响设计决策。关于第二点,须要考虑AMQP的元素须要多少内存,以及Erlang VM对能够建立的进程总数的硬件限制。

内存考虑

关于内存占用,书上有详细说明,这里只列出分析结果,供你们在预估容量时参考:(√表示哪些表会为队列声明添加记录)

1.队列元数据

队列元数据

2.交换器元数据

交换器元数据

3.绑定元数据

一个持久化队列绑定到一个瞬时交换器会致使在rabbit_semi_durable_router表上建立条目。

绑定元数据

Erlang进程计数

能够在节点启动时指定Erlang节点上能运行的最大Erlang进程数,默认设置是每一个Erlang节点1048576,即2^20个。

Erlang应用程序在整个生命周期中会屡次建立并销毁进程。好比,RabbitMQ接收到AMQP客户端的TCP链接时,会建立一个进程进行管理该链接,同时,会有不少Erlang进程来处理消息存储的逻辑。

主要经过如下事件来增长进程数:到服务器的新链接、建立新的信道以及队列声明。一条新的链接会建立四个新的进程,一个新的通道也会建立四个新的进程,队列的开销最小,每一个队列一个进程。

对安全的考虑

有些消息,想以一种安全的方式进行传输,可使用SSL协议在消息通讯终端传输数据,RabbitMQ默认支持SSL,只须要配置相应的证书,使用openssl库进行设置和操做。

关于证书、openssl以及ssl,上一篇文章详细介绍了,如今来看看如何使用。

服务端

只须要修改下rabbitmq的配置便可,在rabbitmq.config中添加ssl_listeners和ssl_options配置项:

[
    {rabbit,[
        {ssl_listeners, [5671]},
        {ssl_options, [
            {cacertfile,"/path/to/rmqca/cacert.pem"},
            {certfile,"/path/to/server/cert.pem"},
            {keyfile,"/path/to/server/key.pem"},
            {verify,verify},
            {fail_if_no_peer_cert,false}
        ]}
    ]}

]
复制代码

配置中指定了ca的证书,服务端的证书,以及服务端的秘钥。

客户端

require_once(__DIR__ . '/../amqp.inc');

define('HOST', 'localhost');
define('PORT', 5671);
define('USER', 'guest');
define('PASS', 'guest');
define('VHOST', '/');
define('AMQP_DEBUG', true);
define('CERTS_PATH',
  '/path/to/ca/folder/');
  
$ssl_options = array(
      'cafile' => CERTS_PATH . '/rmqca/cacert.pem',
      'local_cert' => CERTS_PATH . '/phpcert.pem',
      'verify_peer' => true
  );
$conn = new AMQPSSLConnection(HOST, PORT, USER, PASS, VHOST, $ssl_options);

function shutdown($conn){
    $conn->close();
}
register_shutdown_function('shutdown', $conn);

while(1){}
复制代码

客户端代码指定了ca根证书和客户端证书和秘钥,phpcert.pem是客户端证书、秘钥、ca根证书的合并文件。

$ cat client/key.pem > phpcert.pem
$ cat client/cert.pem >> phpcert.pem
$ cat rmqca/cacert.pem >> phpcert.pem
复制代码

下一篇会介绍下RabbitMQ的插件,以便自定义插件扩展RabbitMQ功能。

欢迎扫描下方二维码,关注个人我的微信公众号,查看更多文章 ~

情情说
相关文章
相关标签/搜索