通过FIFO登录,然后重定向到文件?


8

我有一个必须记录每个事务的应用程序。每条日志消息都会被刷新,因为我们需要记录导致崩溃的事件。我和我的同事很好奇如何在确保日志消息离开进程的同时实现缓冲的性能效果。

我们想到的是:

  • 创建应用程序可以写入的FIFO,并且
  • 通过重定向该FIFO的内容到常规文件cat

也就是说,通常是:

app --logfile logfile.txt

就是现在:

mkfifo logfifo
cat logfifo &> logfile.txt &
app --logfile logfifo

这种方法有什么陷阱吗?在我们测试它时它可以工作,但是我们要绝对确保即使原始应用程序崩溃了,消息也能找到到达重定向文件的方式。

(我们没有应用程序的源代码,因此,编程解决方案是不可能的。此外,应用程序不会写入stdout,因此直接用管道传输到其他命令syslog是不可能的。因此,这是不可能的)


更新:我添加了赏金。接受的答案将不会涉及logger的原因很简单,logger不是我所问。正如最初的问题所述,我只在使用FIFO时才发现问题。


到目前为止,在一些答案中似乎存在一些巨大的困惑。正如我最初在问题中强调的那样,我正在寻找使用FIFO作为日志记录中介的方法的陷阱。我对替代性建议不感兴趣,这些替代性建议至少没有探讨我原始问题的实质
chrisaycock 2012年

如果我对登录到stdout的回答不是您感兴趣的方向,您是否可以从问题中删除“此外,应用程序不会写到stdout,因此直接管道传输到其他命令是不可能的”?
nickgrim'2

Answers:


6

请注意,在写入的数量可能超过读出的数量的编程中,通常需要fifo。

因此,fifo不会像您预期的那样完全顺畅地工作,但是会在引入另一个问题的同时解决您的主要问题。

有三个可能的警告。

  1. 如果初始化时没有任何内容读取另一端,则无限期地禁止写入fifo。
  2. fifo具有64K的固定宽度,如果该点被缓冲区填充,则该宽度将被阻止,直到读写器追上来之前,将进一步阻止写操作。
  3. 如果读取器死亡或退出,则管道写入器将被SIGPIPE杀死。

这意味着您的问题(在非缓冲写入时模拟缓冲I / O)将得到解决。那是因为对FIFO的新“限制”实际上将成为任何实用程序将管道中的内容写入磁盘的速度(大概将被缓冲的I / O)。

但是,编写器将依赖您的日志读取器来运行。如果读者突然停止阅读,作家将被阻止。如果读取器突然退出(假设您的目标磁盘空间不足),则写入器将执行SIGPIPE并可能退出。

还要提到的另一点是,如果服务器紧急情况和内核停止响应,则可能会丢失该缓冲区中多达64k的数据。

解决此问题的另一种方法是将日志写入tmpfs(在Linux上为/ dev / shm),然后将输出拖到固定的磁盘位置。这样做对内存分配的限制较少(不是64K,通常是2G!),但如果编写器没有动态方式重新打开日志文件(您必须定期从tmpfs中清除日志),则可能对您不起作用。如果服务器在此方法中出现紧急情况,则可能会丢失更多数据。


关于,这是一些很好的信息/dev/shm。我们也考虑过,尽管它使我无法使用tail -f
chrisaycock 2012年

4
mkfifo logfifo
cat logfifo &> logfile.txt &
app --logfile logfifo

当您的cat logfifo进程死亡,有人无意中将其杀死或有人将其意外指向错误的位置时,会发生什么?

我的经验是,app将很快阻塞并挂起。我已经在Tomcat,Apache和一些小型的自制应用程序中进行了尝试,但遇到了同样的问题。我从来没有做过很长的调查,因为logger或者简单的I / O重定向可以实现我想要的功能。我通常不需要日志记录完整性,而这正是您要追求的。正如您所说,您不需要记录器。

Linux非阻塞fifo(按需记录)上对此问题进行了一些讨论。


有趣。因此,该应用仍然可以阻止吗?目前,我们正在考虑投入使用并订购Fusion IO。
chrisaycock 2012年

试试看。对我来说,这个结果很快发生了(在低规格硬件的测试环境中)。这是在Ubuntu和RedHat 5上进行的。不确定FreeBSD等是否具有类似的行为。
Stefan Lasiewski '02

2

您的选择受到应用程序的相当有限的限制,但是您所测试的内容仍然有效。

我们使用varnish和varnishncsa进行类似的操作,以获取对我们有用的日志。我们有一个fifo,只需使用syslog-ng从中读取,然后将其发送到需要的位置即可。我们可以处理大约50GB,到目前为止,这种方法还没有遇到问题


太酷了,很高兴听到我们不是唯一提出这个建议的人。
chrisaycock 2012年

2

环境是CentOS,应用程序将写入文件...

而不是发送到常规文件,我将输出发送到syslog并确保将syslog消息发送到中央服务器以及本地。

您应该能够使用如下的shell脚本:

logger -p daemon.notice -t app < fifo

您也可以从管道中输入(至logger):cattail -f

tail -f fifo | logger ...
cat fifo | logger ...

唯一的问题是,它不能根据日志消息的重要性来区分(一切都为NOTICE),但至少它会被记录并从主机发送到中央服务器。

配置syslog取决于您使用的服务器。有rsyslogsyslog-ng(两者都很有能力)。

编辑:从海报中获取更多信息后进行了修订。


日志消息将写入我们可以选择的文件中,但应用程序不会写入stdout。操作系统是CentOS(我将问题标记为linux,但是我想这很容易错过)。所有消息都是同等重要的,因此在此应用程序中,通知和错误之间没有区别。
chrisaycock'2

通知和错误之间没有区别吗?哦,真的Slow query detected和之间没有区别Database halted
Mei

(我更新了帖子。)
2012年

1

你写:

此外,该应用程序将不会写入stdout...

您是否尝试登录到“文件” /dev/stdout?这可能使您能够执行以下操作:

app --logfile /dev/stdout | logger -t app

这与FIFO不同吗?什么是陷阱?本质上,我不是在寻找替代方法;我正在寻找有关我列出的方法是否可靠的见解。这就是我感兴趣的
chrisaycock

1
是的,它与FIFO不同;它本质上是一个连接到STDOUT的文件。因此,您可以使用它登录到STDOUT,然后从那里登录到syslog或类似日志。它旨在解决您的原始问题,但由于移动部件较少,因此希望比FIFO更可靠。
nickgrim'2

1

没有必要先写入fifo,然后再由另一个进程将其写入文件。只需正常地直接写入文件,一旦write()返回,就在内核手中。如果应用程序崩溃,它将仍然将其写入磁盘。


每条日志消息都被刷新:这些阻塞了写操作。由于没有应用程序的源代码,因此我们无法对此进行控制。
chrisaycock 2012年

@chrisaycock,对...所以问题出在哪里?
psusi'2

我和我的同事很好奇如何在确保日志消息离开进程的同时实现缓冲的性能效果。
chrisaycock

@chrisaycock,哦,所以应用程序当前使用O_SYNC或fsync()等待每次写入击中磁盘,而您不希望这种情况发生(如果发生系统崩溃,可能会造成损失)?
psusi'2

1
@chrisaycock,它与驱动器的接口无关,它通常只是意味着内核已将其复制到文件系统缓存中(并从应用程序中复制出来)。就像我最初在回答中所说的那样,一旦write()返回,应用程序可能会崩溃,只要内核不崩溃,数据就会将其保存到磁盘上。
psusi'2
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.