【问题标题】:Does Apache read-lock files before serving them?Apache 在提供文件之前会读锁定文件吗?
【发布时间】:2012-02-19 18:23:58
【问题描述】:

我有一个移动应用程序可以读取存储在 Apache 服务器上的 JSON 文件。如果通过 GUI 更改某些内容,则会重新生成该 JSON 文件的内容(使用 PHP 脚本)。

我担心在 Apache 提供服务的过程中尝试覆盖 JSON 文件可能会导致问题。

Apache 在提供文件之前是否获得读锁?如果不是,如果我在提供服务的同时尝试编写它会发生什么?

【问题讨论】:

  • 你真的需要一个“物理”文件,还是仅仅通过输出内容来伪造文件?

标签: php json apache locking


【解决方案1】:

您在考虑 *nix 平台的错误范例。您想要的是原子文件写入脚本中的 JSON 文件。为此,您可以将文件写入目标目录中的唯一临时文件名,然后使用rename() 将此文件移到旧文件上。文件移动操作是原子的。异步进程将打开旧的 JSON 文件或新的但不是混合的。

有多种方法可以构建临时文件名。请参阅tempnam() 上的 PHP 文档用户 cmets。我的系统会生成一个请求唯一 ID,所以我只使用 $_SERVER["UNIQUE_ID"] 作为基础。

【讨论】:

    【解决方案2】:

    没有。在 POSIX 兼容的系统上,所有的锁都是建议性的,所以即使 apache 会获得读锁,其他进程也可以只写文件。

    你可以用strace来判断:

    [pid  7246] open("/var/www/file.json", O_RDONLY|O_CLOEXEC) = 11
    [pid  7246] fcntl(11, F_GETFD)          = 0x1 (flags FD_CLOEXEC)
    [pid  7246] mmap(NULL, 20, PROT_READ, MAP_SHARED, 11, 0) = 0x7f53f93da000
    [pid  7246] munmap(0x7f53f93da000, 20)  = 0
    [pid  7246] writev(10, [{"HTTP/1.1 200 OK\r\nDate: Thu, 26 J"}, ...) = 365
    [pid  7246] close(11)                   = 0
    

    因此,您的 JSON 文件可能只是部分写入。为避免此问题,请将您的 JSON 文件写入同一文件系统上的临时文件,并使用原子 rename 覆盖该文件。

    这样,如果open 成功,apache 将继续提供旧文件。如果 renameopen 之前完成,则 apache 将获得新的、已完成的文件。

    如果您担心一致性(在电源故障等情况下),您可能还需要在写入 JSON 文件的应用程序中调用fsync,然后再关闭它。

    【讨论】:

    • 如果我使用 PHP 的 php.net/manual/en/function.flock.php 并获得了写锁,可以吗?
    • @cdmckay 不,写锁没有效果,因为 apache 没有读锁。我扩展了答案。简而言之:使用rename
    • 出于好奇,为什么 Apache 不对它们进行读锁定?性能?
    • @cdmckay 那么,为什么 apache 应该读锁定它们?请记住,所有features start at -100 points,特别是如果它们会产生令人望而却步的性能成本,就像flock那样。
    猜你喜欢
    • 1970-01-01
    • 2014-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-06
    • 2012-04-22
    • 2012-05-19
    • 1970-01-01
    相关资源
    最近更新 更多