RabbitMQ--索引重建

【背景】

在实际使用过程中,发现有时候rabbitmq启动后,很快就能提供服务(在指定端口上侦听,客户端能正常连接到rabbitmq);而有时候则需要过一段时间才能提供服务,尤其是启动前有许多持久化的消息未被消费掉的时候。在这种情况下,日志文件中可以看到如下类似的日志信息:

从日志的字面意思来看是需要进行索引的重建工作,那么,什么时候需要进行索引的重建,什么时候不需要进行索引的重建?索引重建具体是怎样进行的呢?作者通过源码分析与实际测试,进行了如下总结。

【索引重建相关的文件】

在rabbitmq中,持久化消息存储在后缀为rdq的文件中(msg_store的存储方式),消息在队列中的位置(索引)存储在后缀为idx的文件中(消息也可能直接存储在索引文件中,可以参考这篇文章),整体情况大概如下图所示:

由于在msg_store中存储的一条消息,可能会被多个队列引用,因此rabbitmq内部维护了几张表 ,用于记录相关信息。

当rabbitmq正常关闭时(通过rabbitmqctl stop),msg_store消息文件存储所在目录,除了存储消息的rdq文件外,还有其他几个文件:

其中“msg_store_index.ets”对应消息在文件中的索引信息表中的记录信息;“file_summary.ets”对应文件概述表中的记录信息;“clean.dot”为元数据文件,该文件记录了持久化队列的信息以及维护消息索引的模块名称信息,该文件中的内容大概是这样的:

注:对于采用msg_store方式存储的消息,每个队列都作为客户端向msg_store的服务进程发送消息的读写请求,队列发送请求之前会像服务进程进行注册,注册时就会带上客户端的reference信息,也就是队列的唯一ID;文件中记录的client_refs也就是每个队列的唯一ID。因此可以说clean.dot包含了各个队列的信息。

另外,针对每个vhost,rabbitmq正常关闭时,还会生成一个“recovery.dets”文件。该文件记录了每个队列的概要信息:包括队列的reference(唯一ID),持久化消息数,持久化消息字节数,每个索引文件中unack的消息数。例如:

注意,这里可以看到队列的persistent_ref信息也在“clean.dot”文件中的client_refs也有记录。

上述所说的几个文件,这里统称为recovery文件,这些文件存在的目的就是方便快速的完成索引重建。

【重建流程】

rabbitmq启动时,针对每个vhost,会读取vhost对应的“recovery.dets”文件,从中获取有效队列的相关信息;然后启动msg_store的服务进程,在服务进程中会加载“file_summary.ets”,“clean.dot”,“msg_store_index.ets”文件中的内容。

如果“recovery.dets”中拿到的有效队列的唯一ID,与“clean.dot”中记录的队列信息完全匹配,同时“file_summary.ets”与“msg_store_index.ets”也都正确加载,这意味着可以直接根据这些文件中记录的信息完成索引的重建;否则,则需需要遍历读取所有的消息文件(*.rdq)、队列的索引文件(*.idx)来完成索引的重建工作。

异常情况下,比如断电,或者直接将rabbitmq的进程kill掉,那么上面提到的recovery文件就不会存在(正常关闭时才生成,启动加载后会删除这些文件)或者文件不完整。这种情况下,recovery文件会加载失败,因此就需要遍历所有的消息文件与队列索引文件进行索引的重建。

在分析相关源码后,发现,这种情况下的索引重建,队列索引文件(*.idx)会被读取两次。第一次读取用于帮助msg_store中消息的正确引用计数,第二次读取则是用于恢复每个队列本身的队列索引信息。因此这将会是一个很耗时的动作。

【总结】

尽可能优雅(正常)的关闭rabbitmq,这样启动时就不会有索引重建的耗时工作了。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值