Linux日志管理Rsyslog之队列

Linux ginotang 2565℃ 0评论

队列(Queues)

实际上,队列在整个日志的生命周期中都存在,它是Rsyslog的核心,一般情况下,我们感觉不到它的存在;然而,从日志的产生到被处理的过程,都必须经过两个队列,一个是主消息队列(main message queue),另一个是动作队列(action queue)。通过下面的图片,可以理解得更加清楚(图片来源:RedHat官方

rsyslog_message_flow

从上图中可以看到,日志产生后,先经过预处理器然后就被压入main message queue等待后续的处理,在进入action queue之前,日志被解析器和过滤器处理,它们的作用是读取rsyslog.conf配置文件中设置的规则,和日志中的内容进行对比,然后发送到合适的action queue,一旦日志进入到这个action queue之后,就会从主消息队列中删除。

日志真正被处理的阶段发生在进入action queue之后,action processor(动作处理器)会从action queue中获取最先进入队列的日志进行处理,根据规则进行日志的输出,例如写入文件,录入数据库、发送到远程服务器,甚至是把它们丢弃。

rsyslog.conf中每一条规则的action都有一个action queue,这种queue默认类型是direct queue,但严格来说,它不属于队列,虽然名字中有queue字样。direct queue通常处理简单的行为,例如把日志写入本地文件。

在direct queue下,同一条日志如果被多个动作处理器消费,这个时候,同一条日志会被复制到各个动作队列中,那么可能会造成的现象是,当你使用discard丢弃日志的时候,会发现discard指令没有生效,原因是:discard指令丢弃的是原始日志的副本,而原始的日志会继续活动在原来的工作流中。

主消息队列(main message queue)

rsyslog中只有一个主消息队列,任何消息都要先进入这个队列,然后直到进入到动作队列之后消息才会从这个队列中删除。通常,我们都不会太过在意主消息队列的设置,因为默认的设置已经工作得很好;往往rsyslog中的关于队列的配置,都是针对动作队列的,这也是我们接下来要说的。

动作队列(action queue)

消息经过主消息队列之后,就被rule processor解析和处理,然后根据预先配置的规则压入各自的动作队列,动作队列之后消息最终被消费掉,例如输出到指定的地方。正是如此,往往我们都会根据实际情况对动作队列的行为作出一些适当的调整。

注意事项

如果消息最终不能被消费(输出到指定位置),那么这些消息就会停留在先前的队列中。这就有可能会导致队列被填满,一旦队列填满,后续的输入消息就不能再进入消息队列,最终造成某些服务无法进行日志记录,最坏的后果是导致该服务无法正常提供服务。

队列的种类

队列的类型划分为下面几种:

  • Direct queue
  • Disk queue
  • In-memory queue (LinkedList/FixedArray)
  • Disk-Assisted In-memory queue

设置队列类型的语法如下:

Direct Queue

Direct queue是默认的行为,它不是一种队列。通常输出到本地硬盘的时候都是使用这种类型。

而Direct queue是唯一一个会把执行结果(成功/失败)从消费者(action processor)返回给生产者的队列。action processor正是通过这个返回值提醒action queue,让action queue取回这些处理失败的消息,如此循环,直到消息处理成功。

Disk Queue

Disk queue使用硬盘作为消息缓冲设备,而不会使用任何内存作为缓冲。因此,它的最大好处是可靠,缺点是,它的写入速度是最慢的。如果不是必须,不推荐使用这种队列。

当Disk queue写入文件的时候,它是以块的方式接收消息的,一个数据块是一个文件,每一个数据块默认是10m,文件有一个前缀,可以通过$<Object>QueueFileName配置。文件的默认大小可以使用$<Object>QueueMaxFileSize设置。

每一个队列可以使用不同的位置保存数据,通过$WorkDirectory指令设置,这个指令要在队列创建之前配置。

In-memory Queue

这种类型的队列把所有的消息都保存在内存中,因此它的处理速度非常快,缺点是当电脑关闭或死机的时候,所有未被处理的消息都会丢失。如果希望电脑关机的时候保存这些消息,可以使用$<Object>QueueSaveOnShutdown设置。

有两种类型的内存队列,它们是:

  • FixedArray queue
  • LinkedList queue

main message queue默认是FixedArray Queue, main message queue的默认上限是10000个消息。

FixedArray队列预先分配一定的内存来保存这些消息,它的缺点是,无论你的日志有多少,它都需要完全占用这些内存;好处是当数据量不大的时候,它的性能是最好的。

LinkedList队列和FixedArray队列不同,它的内存是运行时分配的,会根据数据量的不同而作出调整,好处是内存利用率高,LinkedList队列适合使用在一些突发数据量大的场景。

Disk-Assisted In-memory Queue

这种队列实际上是以内存队列为主,Disk Queue为辅的队列。在正常情况下,不会使用辅助的Disk queue,但当内存队列被填满,或者主机关闭的时候,Disk Queue就会被激活,数据被写入硬盘。结合两者使用,可以同时满足速度和数据的可靠性。

这种类型的队列创建指令是(以action queue为例子):

也就是说,在建立一个普通的内存队列之后,再使用指令设置一个保存文件,两者组合在一起之后,就成了Disk-Assisted In-memeory Queue。

$<Object>QueueHighWatermark和$<Object>QueueLowWatermark

$<Object>QueueHighWatermark的作用是:当队列中的数据超过这个设置的值的时候,要么把数据保存,要么把数据丢弃,如果是Disk-Assisted In-memory Queue,队列中的数据超过这个值,Disk Queue就会被激活。

$<Object>QueueLowWatermark的作用:和上面的相反,这是一个低水位设置,当数据小于这个值的时候,就停止相关的操作,如果是Disk-Assisted In-memory Queue,数据低于这个值,Disk Queue就会被取消激活状态。

管理队列

队列的管理过程实际上是对队列的参数进行调优的过程。main message queue的参数和action queue的参数基本一样。

下面是主消息队列和动作队列共有的设置指令,它们的作用在两种队列中基本一样:

这些指令的位置十分重要,必须在队列创建之后才能使用,每个不同的队列可以设置不同的数值,这些值在下一个队列创建之前被重置,前一个队列设置的值不会影响到下一个队列。

限制队列的容量

上面的参数中,对于容量限制的指令有两个,它们是:

  • $<Object>QueueSize  <number>
  • $<Object>QueueHighWaterMark <number>

两者之间有细微的差别,$<Object>QueueSize用于设置队列的总容量,即队列可容纳的消息数量。

而$<Object>QueueHighWaterMark只用于disk-assisted类型的队列,当队列中的消息数量达到这个值之后,消息就会被写入到硬盘。但是这种行为是有依赖性的,仅当日志的输出目标无法到达的时候(数据库无法访问,远程服务器离线等),它才会发生。

丢弃消息(Discarding Messages)

控制这个行为的指令是$<Object>QueueDiscardMark,当队列中的消息达到这个指定的值时,消息就会被丢弃。至于丢弃哪一种消息,则由$<Object>QueueDiscardSeverity指令控制,这个指令接受以文字表示的等级或以数字表示的等级。具体的等级和对应的数字如下:

队列的终止

我们不能控制队列的终止,只有在系统被关闭的那一刻,队列才会结束。当队列终止的时候,可能会遇到这样的情况:队列中依然有数据尝试进入。这种情况rsyslog会试图处理这些数据,如果希望控制这些数据的处理时间,可以使用这个指令:$<Object>QueueTimeoutShutdown <milliseconds>。当时间超过这个值,队列中的所有数据被丢弃。如下图:

图一rsyslog time line

另一种情况是,当超时后,依然希望队列处理完当前正在被处理的数据再关闭,那么可以使用$<Object>QueueTimeoutActionCompletion指令,它设置了处理当前数据的时间,也就是说除了当前正在被处理的消息外,其他任何的消息都被丢弃。

图二syslog time line 2

和图一不同的是,图二保留了当前正在被处理的消息(队列最前绿色)。

如果不希望丢弃任何消息,可以使用$<Object>QueueSaveOnShutdown指令。这个指令要求队列是Disk Queue或者Disk-assisted Queue。

为什么我们需要队列

把这个问题放到最后才说,是有原因的,因为到这个位置,才比较清楚队列都干了什么。知道它的作用,才能回答这个问题。从上面几种队列可以看到,队列的作用无非是两种,一种是加速,另一种是可靠。那么,现在再回答一个问题,为什么默认Action Queue是Direct Queue(不进入队列)?

原因很简单:比起其他操作,例如写入数据库或者是通过网络协议传输日志,直接写入硬盘速度是最快的,也是最可靠的,因此,它使用的是Direct Queue。参考:rsyslog performance: main and action queue workers

那么另一个问题是:我们什么时候使用队列?这个问题其实可以根据上面的解释回答,也就是在一些慢操作和可靠性不高的场景(写入数据库、网络传输)。

 

转载请注明:Pure nonsense » Linux日志管理Rsyslog之队列

喜欢 (3)
0 0 投票数
文章评分
订阅评论
提醒
guest
0 评论
内联反馈
查看所有评论
0
希望看到您的想法,请您发表评论x
()
x