系统拆分解耦利器之消息队列---RabbitMQ-Persistence Configuration

来源:互联网 发布:诚信通软件下载 编辑:程序博客网 时间:2024/06/06 12:48

[一曲广陵不如晨钟暮鼓]

鉴于RabbitMQ官方文档的内容过多,且大部分内容在应用时基本使用默认配置,因此,后续我们将只翻译部分文档。更多内容请各位看官参考其他资料吧。

本文,我们将介绍RabbitMQ持久化配置相关的内容,废话不表,马上开始正文部分吧。

--------------------------------------------------------------------------------------------------------------------------------------------------------

Persistence Configuration

RabbitMQ的持久层是为了在大多数没有配置的情况下,仍然提供相对较好的服务。但其中的一些配置,在某些情况下,是非常有用的。接下来,我们就来解释如何配置它们。强烈建议你在开始修改这些配置之前先阅读本文相关内容

How persistence works

首先,在某些场景下:持久的和临时的消息都被写入到磁盘中。其中,持久的消息将在其到达队列之时就会被写入到磁盘之中,而临时的消息只会在内存不够用时,为了释放内存压力而被临时的写入磁盘当中。此时,持久化的消息也采用了同样的策略。持久层的作用是将这两种类型的消息都写入到此到磁盘当中。

在本文中我们说“队列queue"是代表一个无镜像队列或者一个队列的master或者一个队列的slave节点。

持久层由两个组件组成:队列索引(queue index)和消息存储(message store)。

队列索引负责维护一个关于在队列当中的一个给定消息的信息,以及它是否已经被传递和被确认的相关信息。因此,每一个队列当中都会有一个队列索引。

消息存储是消息的一个key-value的存储,其在服务器中的所有队列当中共享。消息(消息体,属性,头部信息)能够直接存储在队列的索引当中,或者被写入消息存储。从技术上而言有两个存储(持久的,临时的),但是他们都通常被认为是“消息存储”。

Memory costs

在内存压力下,RabbitMQ持久层总是尽可能多的将消息写入到磁盘中,并从移除尽可能多的消息。但是,其中有一些必须被保留到内存当中的内容:

  • 每个队列维护一些未得到确认的消息的元数据。如果消息的目的地是消息存储区的话,那么该消息是可以从内存当中移除的。
  • 消息存储需要一个索引。默认的,消息存储索引为每个消息使用非常小的内存做存储。

Messages in the queue index

以下是向队列索引中写入消息的优点以及缺点。

优点:

  • 消息能够一次性的写入到磁盘当中。而不是两步操作;对于小数据的消息体是一个有效的性能提升。
  • 写入消息索引的消息不再需要在消息存储索引中占据一个条目,因此,在消息换出内存时,没有内存消耗。

缺点:

  • 队列索引在内存中持有记录的固定数量的块。如果消息体积巨大的话,那写入到队列索引当中后,会占据大量的内存。
  • 如果消息通过exchange路由到多个队列当中,消息将会需要被写入到多个队列索引当中。如果这样的消息被写入到消息存储中,那只有一个副本需要被写入。
  • 对于未确认的目的地是消息索引的消息,其将会一直被保存到内存当中。

在这种设计下,将体积小的消息写入到队列索引当中是推荐的做法。而对其他体积较大的消息应该被写入到消息存储当中。这个功能被配置项queue_index_embed_msgs_blow控制。默认的,消息序列化之后的大小应该小于4096个字节将被存储在队列索引当中。


当从磁盘当中读取消息时,每一个队列索引需要在内容当中最少对应一个文件片段。这个文件片段包含16384个消息记录。因此,需要谨慎的增加配置项queue_index_embed_msgs_below的值,一个小的增量都会导致大量的内存被占用。

Accidentally limited persisterperformance

持久化的性能表现可能存在达不到期望的情况。是因为持久化的过程受限于文件处理或异步线程。当你有大量的队列需要进行磁盘访问时就可能导致发生这两种情况。

Too few file handles

RabbitMQ 服务器通常情况下是只有有限数量的文件句柄供其使用。(至少在Unix上)。每一个运行状态的网络连接都需要一个文件句柄,其余的供队列使用。在网络连接已经占据部分句柄之后,如果存在更多访问磁盘的队列,在数量上超过了文件句柄的数量。 那么磁盘访问队列将会共享这些文件句柄。每个被使用的文件句柄在使用完成之后交给另一个句柄使用。

这种策略防止服务器因为过多的磁盘访问而发生崩溃,但与此同时,其代价也是非常昂贵的。提供的管理插件可以观察到集群中每个节点I/O的统计信息。以及显示读,写,搜索等内容的速度。并且还会显示文件句柄回收,重新打开的速度。一个繁忙的服务器拥有很少的文件句柄就可以处理每秒钟数百次的句柄回收与重新打开,在这种情况下,如果加入更多的句柄就可以显著的提升性能。

Too few async threads

Erlang虚拟机创建了一个异步线程池来专门处理长时间运行文件I/O的操作。该线程池在所有的队列中共享。每一个活动的文件I/O操作使用一个异步线程。如果异步线程太少将很大程度上影响性能表现。

注意:在使用异步线程的情况下不同于文件句柄。如果队列执行I/O操作的数量和异步线程数量相同的情况下,其性能表现最好。否则的,将耗费额外的CPU来刷新和寻找线程进行处理。然而,队列并没有从操作序列过程中持有异步线程中获得任何好处。(事实上,其也不是这样做的。话句话说:就是在执行操作过程中,并不独占某个异步线程,这样做没有任何意义)。

因此,在理想的情况下,应该有足够的文件句柄供队列在执行I/O流操作时使用,并且,有足够的异步线程供你的存储层可能同时执行I/O操作数量所使用。

不太明显的是,当缺乏异步线程时,将导致性能问题。(一般情况下,也不太可能。建议你先检查其他配置项)太少的异步线程的典型表现如:每秒I/O操作的数量下降到0。短暂的时间内,服务器应该忙于进行持久化,并且每秒I/O操作的的报告时间增加。

异步线程的数量是通过+A参数在Erlang虚拟机进行配置。(取值范围为0--1024,默认为10)。通常情况下,在环境变量RABBITMQ_SERVER_ERL_ARGS中进行设置。默认的值为+A 30。将建议你在改变这个值之前先实验不同的值,在观察效果之后,再决定是否改变。

Alternate message store index implementations

正如上文所述,每一个被写入到消息存储的消息都使用少量的内容来存储其索引条目。消息存储索引在RabbitMQ中是可插拔的,并且其他的实现都可以通过插件来解除这个限制。(我们不与其他服务器关联的原因是它们都是用了本地代码)但是需要注意:这样的插件通常情况下会使得消息存储变得缓慢。

------------------------------------------------------------------------------------------------------------------------------------------------------

至此,系统拆分解耦利器之消息队列---RabbitMQ-Persistence Configuration 结束


参考资料:

官方文档:http://www.rabbitmq.com/persistence-conf.html

0 0