已开启sendfile,为何Nginx仍不使用sendfile系统调用?
我的Nginx配置
user www-data; worker_processes auto; pid /run/nginx.pid; include /etc/nginx/modules-enabled/*.conf; events { worker_connections 4096; multi_accept on; } http { autoindex off; output_buffers 1 8m; sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; types_hash_max_size 2048; include /etc/nginx/mime.types; default_type application/octet-stream; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE ssl_prefer_server_ciphers on; access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log; gzip on; include /etc/nginx/conf.d/*.conf; include /etc/nginx/sites-enabled/*; }
问题现象
通过strace -p {ngx1} -p {ngx2} .... -e sendfile跟踪所有Nginx worker进程,发现即使在下载文件时,也无sendfile相关输出,Nginx大量使用的是write系统调用。用包含sendfile调用的简单C程序测试时,strace能正常捕获到该调用。
排查方向与解决方法
gzip压缩导致sendfile失效:Nginx的sendfile无法处理压缩后的内容,若配置中开启
gzip on,当请求文件符合压缩条件时,Nginx会先压缩再通过write发送,不会触发sendfile。
解决:临时将gzip on改为gzip off,重启Nginx后重新测试;若需保留gzip,可针对不需要压缩的静态文件路径单独关闭gzip。传输内容非静态常规文件:sendfile仅适用于本地常规静态文件,动态生成内容(如PHP、CGI输出)、代理转发的响应都无法触发sendfile。
解决:确保测试时下载的是服务器本地的静态文件(如未压缩的图片、纯文本文件等)。HTTPS场景未开启ssl_sendfile:Nginx处理HTTPS连接时,默认关闭sendfile支持(
ssl_sendfile off),即使全局开启sendfile on也无效。
解决:在http块或对应HTTPS server块中添加ssl_sendfile on;,重启Nginx后测试。过大的output_buffers配置影响:配置中
output_buffers 1 8m设置了较大的输出缓冲,可能导致Nginx优先使用缓冲写入而非sendfile。
解决:注释掉该配置,使用Nginx默认的output_buffers 2 32k,重启后测试。
内容的提问来源于stack exchange,提问作者Vladislav Eganov

