重命名是锁定文件的安全方法吗?

Is renaming a safe way of locking files?

我正在为 node.js.[=13] 重写 PHP 应用程序=]

其中一个组件涉及解析实时网络服务器日志,使用信息然后将其中的一些写回日志。

我锁定文件以避免覆盖(在生产和解析中每小时大约有 100+ entries/second,它们确实经常在没有锁定的情况下发生),如下所示:

$fh = fopen('./my.log', 'r');
flock($fh, LOCK_EX);
// parse the content, remove old entries, rewrite back the newer ones
flock($fh, LOCK_UN);
fclose($fh);

使用节点的 fs,我知道有 no native way to lock the files. Surely ,但我的第一个驱动器是尝试这样的事情:

fs.renameSync('./my.log','./my.log_') // rename the file to something else
fs.writeFileSync('./my.log_', info_to_keep, {flag: 'w+'}) // safely(!?) replace the content
fs.renameSync('./my.log_','./my.log') // rename back
// (would be done async in production, this is for quick testing only)

看来任务完成了。即使原始 my.log 在那几毫秒内重新创建,它也会被很好地替换(我不太关心丢失的数据位!-它们都是瞬态的,用于采样目的)。

虽然我没有现场测试,所以我不确定它是否可靠地工作。是否存在任何风险,例如重命名过程中的碰撞或类似情况?

好吧,根据一些 nginx doc(参见“日志循环”部分),nginx 保持日志文件打开,因此当您重命名它时,nginx 只是继续写入它拥有的相同文件描述符现在重命名的文件。在您发出信号之前,它不会创建新文件。所以重命名日志文件不会对 nginx 做任何事情。据此,它将继续写入重命名的文件。

所以,我想 “重命名是一种安全的文件锁定方式吗?” 对于 nginx 的答案是 “没有”。它不锁定任何东西。

简而言之:Linux 进程打开文件后,进程不关心文件名。文件处理程序将保留磁盘上文件的地址并将其用于 IO 操作。 现在,如果在打开文件时名称出现问题,它不会影响已经打开处理程序的进程。 更重要的是,即使是物理 space 也不是 de-allocated 直到所有进程关闭文件句柄。这意味着您甚至可以使用 rm 删除文件,但只要对文件编程 reads/writes,数据就会保持健康。 这就是 NGinx 日志轮转机制 btw 的基础。

这是一篇关于 Linux 文件系统操作和陈旧文件句柄基础知识的好文章: https://www.baeldung.com/linux/stale-file-handles