这是 nginx/WebDAV 竞争条件吗?如何解决它?

这是 nginx/WebDAV 竞争条件吗?如何解决它?

我在 Debian Stretch 上运行了一个 nginx 1.10.3 服务器。它所服务的站点之一是 WebDAV 共享,由桌面应用程序读取和写入。当名为的文件myfile保存到 WebDAV 服务器时,该应用程序执行以下步骤:

  1. DELETE /myfile.tmp
  2. PUT /myfile.tmp,主体包含新文件数据
  3. DELETE /myfile
  4. MOVE /myfile.tmpDestination: http://webdav.example.com/myfile
  5. GET /myfile

客户端应用程序将步骤 5 中的响应与步骤 2 中发送的数据进行比较,如果文件数据不匹配,则会引发错误。这些步骤在我们的特定网络上发生得非常快(服务器和客户端在地理位置上很近,连接到同一个以太网交换机)——我用 tcpdump 进行的测试表明整个对话在 45 毫秒内完成。

问题是,步骤 5 返回的数据没有立即地与客户端在步骤 2 中发送的内容相匹配。返回的数据是 的先前版本myfile,在DELETE/MOVE步骤将其替换之前。如果我稍后返回并手动重复步骤 5,文件数据将如预期的那样成为新版本。

我知道客户端会等待每个响应到达后再发出后续请求。我最好的猜测是,不同的请求会命中不同的 nginx 工作线程/线程,或者可能存在某种缓存失效或刷新速度不够快的情况。

如何在不修改客户端应用程序或人为减慢请求速度的情况下解决此问题?

完整的 nginx.conf 和站点配置如下:

pid /run/nginx.pid;
user www-data;
worker_processes auto;
worker_rlimit_nofile 20000;

events {
    multi_accept on;
    use epoll;
    worker_connections 4000;
}

http {
    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log warn;

    sendfile on;
    server_tokens off;
    tcp_nodelay on;
    tcp_nopush on;
    keepalive_requests 100000;
    keepalive_timeout 65;
    client_body_timeout 10;
    send_timeout 10;
    reset_timedout_connection on;
    types_hash_max_size 2048;

    open_file_cache max=200000 inactive=20s;
    open_file_cache_errors on;
    open_file_cache_min_uses 2;
    open_file_cache_valid 30s;

    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    gzip on;
    gzip_buffers 16 8k;
    gzip_comp_level 6;
    gzip_disable msie6;
    gzip_http_version 1.1;
    gzip_min_length 10240;
    gzip_proxied any;
    gzip_vary on;
    gzip_types
        application/atom+xml
        application/javascript
        application/json
        application/ld+json
        application/manifest+json
        application/rss+xml
        application/vnd.geo+json
        application/vnd.ms-fontobject
        application/x-font-ttf
        application/x-javascript
        application/x-web-app-manifest+json
        application/xhtml+xml
        application/xml
        application/xml+rss
        font/opentype
        image/bmp
        image/svg+xml
        image/x-icon
        text/cache-manifest
        text/css
        text/javascript
        text/plain
        text/vcard
        text/vnd.rim.location.xloc
        text/vtt
        text/x-component
        text/x-cross-domain-policy
        text/xml;

    server {
        listen 80;
        listen [::]:80;
        server_name webdav.example.com;

        root /var/www/webdav.example.com;

        autoindex on;
        autoindex_exact_size off;
        autoindex_localtime on;
        dav_access user:rw group:r all:r;
        dav_methods DELETE MOVE PUT;
        create_full_put_path on;
    }
}

编辑:我发现了一个有趣的现象。如果我重新加载 nginx ( sudo service nginx reload),第一次保存文件的尝试就会成功。但如果我随后尝试保存它,就会发生同样的错误。

答案1

原来是 open_file_cache 的问题。文档听起来好像它只是缓存文件元数据,就像统计缓存一样,但在这种情况下,它实际上使得一些响应变得陈旧。

open_file_cache off;在块内部server { ... }就完成了所有操作,现在它运行良好。

相关内容