这是我的 Varnish 配置:
/usr/sbin/varnishd \
-a 127.0.0.1:6081 \
-T 127.0.0.1:6082 \
-f /varnish/default.vcl \
-P %t/%N/varnishd.pid \
-s malloc,4G \
-p thread_pools=12 -p thread_pool_min=250 -p default_ttl=1 -p default_grace=0 -p timeout_idle=1800
因此 12 * 250 = 3000 个线程。使用此设置,我最终打开了超过 400k 个文件。
将线程数减少到最低限度确实会大大减少打开文件的数量。
问题是:这怎么可能?每个 Varnish 线程打开这么多文件是正常的吗?
编辑:这是我的 VCL 文件:
vcl 4.1;
backend someBackend {
.host = "someBackend.net";
.connect_timeout = 2s;
.first_byte_timeout = 5s;
.between_bytes_timeout = 5s;
}
sub vcl_recv {
# Remove Varnish from X-Forwarded-For (set by Nginx)
set req.http.X-Forwarded-For = regsub(req.http.X-Forwarded-For, ",[^,]+$", "");
}
sub vcl_backend_fetch {
# Hide Varnish token
unset bereq.http.X-Varnish;
}
sub vcl_backend_response {
unset beresp.http.Vary;
}
sub vcl_deliver {
unset resp.http.Via;
unset resp.http.X-Varnish;
}
您设置的某些参数可能是导致打开文件数量过多的原因。
线程
让我们从 开始
thread_pools=12
。默认值为 2,我们不建议您更改它。虽然在您的用例中thread_pool_min
设置为250
,但 的默认thread_pool_max
值为5000
。问题是:“在高峰流量期间,或者甚至在活动线程数远低于 1000 个时,您是否看到 40 万个打开的文件?”
假设这种情况发生在绝对峰值流量期间,每个池有 5,000 个线程,但 12 个线程池产生 60,000 个活动线程。
这意味着每个线程大约有 7 个文件描述符,这并不不合理。
影响
timeout_idle
当然,还有一个参数,你可以将其从 5 增加到 1800。这意味着,如果设置了keepalive,
timeout_idle
则连接将空闲 1800 秒,然后关闭。那真是很长一段时间了。
空闲连接的文件描述符从线程中移出,并由等待线程管理。这意味着文件描述符被保留,而线程可以接受新的连接并创建更多的文件描述符。
需要进行更多调试
在我的回答中,我假设 400k 个打开的文件发生在高峰流量期间。如果不是这样,则需要进行更多调试才能确定哪些文件(或文件描述符)正在使用中。
其中一种方法是运行以下命令:
此命令将列出该进程正在使用的各种文件描述符。
当然,运行以下命令并结合参数来列出所有线程和连接:
评论后更新
在这个问题的评论部分,你会注意到一些来回的争论,试图收集更多信息并获取一些背景信息。
@NicoAdrian 提到他看到很多文件描述符指向
var/lib/varnish/varnishd/_.vsm_child/_.Stat.*
。我无法模拟这种情况。每当我启动时varnishd
,都会有大约 45 个文件描述符与该模式相关联。当我将线程设置增加到此处共享的参数时,该数字会增加到 80,但不会更多。
但是,我可以通过增加线程设置来模拟大量的文件描述符。
我在正在运行的 Varnish 服务器上运行了以下命令来模拟此问题中提到的设置:
输出为
lsof | grep "varnish" | wc -l
。188918
这意味着有 188918 个文件描述符正在使用中。同时, 的输出
varnishstat -1 -f MAIN.threads
显示3198
工作线程此时已启动。 就是这样12 x 250
。在这些设置下,每个线程池至少有 250 个工作线程。随着流量开始增加,每个池的线程数可以增加到 5000 个,因为 的标准值为
thread_pool_max
。5000
每个工作线程平均有 50-60 个文件描述符。通过拥有大量活动线程,这些文件描述符将以相同的速率增加。其中大部分应链接到
/proc/*
。如上所述,线程池数量增加到 12 个以减少锁争用。我们几乎从不增加 的值
thread_pools
,即使对于大规模系统也是如此。对于 12 个线程池,减少该thread_pool_min
值以减少初始线程创建并减少正在使用的文件描述符可能是有意义的。在基线流量上,查看实际创建的线程数是有意义的
MAIN.threads
。如果该值高于thread_pools x thread_pool_min
,则表明创建的线程数较多,并且该thread_pool_min
设置太低。这与使用的文件描述符数量有直接关系。如果怀疑性能因此成为问题,则可以将
/var/lib/varnish
文件夹挂载到tmpfs
。