这是交易: 我有一个多进程系统(pre-fork模型,类似于apache)。所有进程都写入同一个日志文件(事实上是一个记录请求和响应的二进制日志文件,但无论如何)。
我通过共享内存锁防止并发访问日志,当文件达到一定大小时,通知它的进程首先滚动日志:
问题是其他进程没有意识到,并且实际上继续写入旧的日志文件(已重命名为log.bin.1)。
我可以想到几个解决方案:
在我看来,这些都不是很优雅。
想法?建议?
答案 0 :(得分:3)
您的解决方案似乎很好,但您应该在共享内存中存储一个带有当前日志文件inode的整数(请参阅stat(2) stat.st_ino 成员)。
这样,所有进程都使用打开的inode文件保存了一个局部变量。
只有一个进程轮换时必须更新共享var,并且通过检查本地inode和共享inode之间的差异来了解所有其他进程。它应该导致重新开放。
答案 1 :(得分:1)
每次在写日志条目之前按名称打开文件怎么样?
或者你可以创建一个日志记录过程,它接收来自其他进程的日志消息,并从它们透明地处理所有旋转。
答案 2 :(得分:1)
您没有说出您正在使用的语言,但您的进程应该全部登录到日志进程,并且日志进程会抽象写入文件。
Logging client1 -> |
Logging client2 -> |
Logging client3 -> | Logging queue (with process lock) -> logging writer -> file roller
Logging client4 -> |
答案 3 :(得分:1)
您可以将 log.bin复制到log.bin.1,然后然后截断 log.bin文件。 所以问题仍然可以写入旧的文件指针,现在是空的。
另见man logrotate
:
copytruncate Truncate the original log file to zero size in place after cre‐ ating a copy, instead of moving the old log file and optionally creating a new one. It can be used when some program cannot be told to close its logfile and thus might continue writing (appending) to the previous log file forever. Note that there is a very small time slice between copying the file and truncat‐ ing it, so some logging data might be lost. When this option is used, the create option will have no effect, as the old log file stays in place.
答案 4 :(得分:1)
由于您正在使用共享内存,并且您知道有多少进程正在使用该日志文件。 您可以在共享内存中创建一个标志数组,告诉每个进程该文件已被旋转。然后,每个进程都会重置标志,以便它不会连续重新打开文件。