我们在网站上添加了下载视频文件的功能。我们的服务器上使用 nginx。现在奇怪的问题是,有时文件可以下载,有时则不能。
我们在 nginx error.log 中收到的错误
[crit] 62196#62196: *15951408 aio read "/path/to/storage/files/[unique_filecode].mp4" failed (22: Invalid argument) while sending response to client, client: [client ip], server: storage.example.com, request: "GET /api/download/files/filename.mp4 HTTP/1.0", upstream: "fastcgi://unix:/var/run/php-fpm/php7.3-fpm.sock", host: "storage.example.com", referrer: "https://example.com/download?file_id=FILE_ID"
[error] 62197#62197: *15951406 upstream prematurely closed connection while reading response header from upstream, client: [SERVER_IP], server: storage.example.com, request: "GET /api/download/files/filename.mp4 HTTP/1.1", upstream:
要开始下载,我们使用 php 并输出标题
$path = /download/files/[unique_filecode].mp4?file_id=[file_id]&ip=[CLIENT IP]&speed=0&mode=1×tamp=[unix timestamp];
// Speed: Limit the download speed depending on the user type
return response('', 200)->withHeaders([
'Content-type' => 'video/mp4',
'X-Accel-Redirect' => $path,
'Content-disposition' => '"attachment";'
]);
我们的 nginx 配置
user www-data www-data;
worker_processes auto;
worker_rlimit_nofile 10240;
error_log /var/log/nginx/error.log info;
events {
worker_connections 10240;
multi_accept on;
}
http {
include mime.types;
default_type video/mp4;
server_tokens off;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
# file handle caching / aio
open_file_cache max=200000 inactive=3m;
open_file_cache_valid 2m;
open_file_cache_min_uses 2;
open_file_cache_errors on;
aio on;
directio 8m;
directio_alignment 4096;
access_log off;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
limit_conn_zone $binary_remote_addr zone=addr:20m;
include conf.d/*.conf;
}
server {
listen 80;
server_name storage.example.com;
set $storagePath "/path/to/storage";
location /download/ {
internal;
alias $storagePath/;
limit_conn addr 2;
set $limit_rate $arg_speed;
}
}
为什么 aio 会抛出Invalid argument
错误?我检查了路径并且它是正确的。
我们目前在存储服务器上使用 CentOS 7。
编辑:
存储磁盘采用 ext4 格式
/dev/sdd1 ext4 2.7T 2.2T 414G 85% /disk4
/dev/mapper/centos_hosted--by-disk1 ext4 2.5T 2.1T 228G 91% /disk1
编辑2:
Nginx 版本 1.15.11
Nginx 编译时使用:
Nginx 上传和 vod 模块是最新可用版本。
./configure
--error-log-path=/var/log/nginx/error.log
--access-log-path=/var/log/nginx/access.log
--with-debug
--with-http_auth_request_module
--with-http_stub_status_module
--with-http_mp4_module
--add-module=../nginx-upload-module
--add-module=../nginx-vod-module
--with-file-aio
--with-threads
--with-http_ssl_module
--with-http_v2_module
--with-http_realip_module
编辑3:
vod_open_file_thread_pool;
vod_path_response_prefix '';
vod_path_response_postfix '';
vod_segment_duration 20000;
vod_align_segments_to_key_frames on;
vod_expires 6h;
vod_mapping_cache mapping_cache 8m;
vod_response_cache response_cache 128m;
vod_metadata_cache metadata_cache 4000m;