<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Nofile on 清尘博客 - 静心</title><link>https://blog.kingbatsoft.top/tags/nofile/</link><description>Recent content in Nofile on 清尘博客 - 静心</description><generator>Hugo -- gohugo.io</generator><language>zh-CN</language><copyright>Kingbatsoft</copyright><lastBuildDate>Thu, 15 Oct 2026 03:21:55 +0800</lastBuildDate><atom:link href="https://blog.kingbatsoft.top/tags/nofile/index.xml" rel="self" type="application/rss+xml"/><item><title>GZCTF 高并发排障：nofile 软上限只有 1024</title><link>https://blog.kingbatsoft.top/p/gzctf-docker-nofile-1024/</link><pubDate>Thu, 15 Oct 2026 00:00:00 +0800</pubDate><guid>https://blog.kingbatsoft.top/p/gzctf-docker-nofile-1024/</guid><description>&lt;p&gt;我在部署比赛的过程中发现，GZCTF 在低并发下运行正常，但超过 100 人同时使用后，常出现页面加载失败、登录异常、Flag 提交超时，或者点击启动题目容器却没有响应的情况。排查时发现，平台容器继承的 &lt;code&gt;nofile&lt;/code&gt; 软上限只有 1024，高并发下很容易碰到这个限制。&lt;/p&gt;
&lt;p&gt;所以遇到这类问题，除了看 CPU、内存和数据库，也要检查一下平台进程的&lt;strong&gt;文件描述符上限&lt;/strong&gt;。HTTP 请求、WebSocket 长连接和后端连接都要占用文件描述符。额度用完后，即使容器还在运行，平台也可能已经无法正常接收请求。&lt;/p&gt;
&lt;h2 id="为什么会影响登录和开题"&gt;&lt;a href="#%e4%b8%ba%e4%bb%80%e4%b9%88%e4%bc%9a%e5%bd%b1%e5%93%8d%e7%99%bb%e5%bd%95%e5%92%8c%e5%bc%80%e9%a2%98" class="header-anchor"&gt;&lt;/a&gt;为什么会影响登录和开题
&lt;/h2&gt;&lt;p&gt;Linux 里的普通文件、网络 socket、管道等都通过文件描述符访问。&lt;code&gt;nofile&lt;/code&gt; 对应进程的 &lt;code&gt;RLIMIT_NOFILE&lt;/code&gt; 限制，达到上限后，继续打开文件或创建 socket 就会失败，常见报错是：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Too many open files
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;对应的错误码是 &lt;code&gt;EMFILE&lt;/code&gt;。&lt;a class="link" href="https://man7.org/linux/man-pages/man2/getrlimit.2.html" target="_blank" rel="noopener"
 &gt;Linux 文档&lt;/a&gt;里有这个限制的具体定义。&lt;/p&gt;
&lt;p&gt;GZCTF 用到文件描述符的地方不少：加载程序集、读写日志、访问题目附件，以及浏览器、数据库、缓存服务和 Docker API 的连接。&lt;/p&gt;
&lt;p&gt;因此，描述符耗尽后，不只是页面可能打不开。平台也可能无法建立数据库连接，或者无法向 Docker 发出创建题目容器的请求。用户看到的就是登录失败、提交超时、开题没有响应，而后台看容器状态却仍然是 running。&lt;/p&gt;
&lt;h2 id="先看看实际限制是多少"&gt;&lt;a href="#%e5%85%88%e7%9c%8b%e7%9c%8b%e5%ae%9e%e9%99%85%e9%99%90%e5%88%b6%e6%98%af%e5%a4%9a%e5%b0%91" class="header-anchor"&gt;&lt;/a&gt;先看看实际限制是多少
&lt;/h2&gt;&lt;p&gt;进入 GZCTF 的 Docker Compose 目录，获取平台容器 ID：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;cid&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;docker compose ps -q gzctf&lt;span class="k"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;这里的 &lt;code&gt;gzctf&lt;/code&gt; 是 Compose 中的服务名。查看平台主进程的限制和当前打开的描述符数量：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$cid&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; sh -c &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;grep &amp;#34;Max open files&amp;#34; /proc/1/limits&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$cid&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; sh -c &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;ls -1 /proc/1/fd | wc -l&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;官方镜像直接运行平台程序时，主进程是 PID 1；如果自己加了启动包装器，就把这里的 &lt;code&gt;1&lt;/code&gt; 换成实际 &lt;code&gt;dotnet&lt;/code&gt; 进程的 PID。&lt;/p&gt;
&lt;p&gt;例如输出：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Max open files 1024 524288 files
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;前面的 &lt;code&gt;1024&lt;/code&gt; 是软上限，也就是当前生效的限制；后面的 &lt;code&gt;524288&lt;/code&gt; 是硬上限。不要只看到硬上限很大，就以为进程已经能使用这么多描述符。&lt;/p&gt;
&lt;p&gt;我检查 GZCTF v1.9.0 时，空载状态就已经打开了 &lt;strong&gt;471&lt;/strong&gt; 个描述符，其中 &lt;strong&gt;448&lt;/strong&gt; 个指向程序集文件，socket 只有 &lt;strong&gt;4&lt;/strong&gt; 个。也就是说，在用户连接进来之前，程序自身就已经占用了接近一半的额度。&lt;/p&gt;
&lt;p&gt;这里的 471 不是 471 条用户连接。文件和 socket 共用同一个上限，不能直接拿 &lt;code&gt;nofile&lt;/code&gt; 的数值当作平台能容纳的用户数。&lt;/p&gt;
&lt;p&gt;再看一下容器有没有单独设置 &lt;code&gt;ulimits&lt;/code&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker inspect &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$cid&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; --format &lt;span class="s1"&gt;&amp;#39;{{json .HostConfig.Ulimits}}&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;如果返回 &lt;code&gt;null&lt;/code&gt;，就是没有显式配置，实际值继续看进程的 &lt;code&gt;limits&lt;/code&gt;。不同机器继承到的默认值可能不同，检查时直接读 &lt;a class="link" href="https://man7.org/linux/man-pages/man5/proc_pid_limits.5.html" target="_blank" rel="noopener"
 &gt;&lt;code&gt;/proc/&amp;lt;PID&amp;gt;/limits&lt;/code&gt;&lt;/a&gt; 即可。&lt;/p&gt;
&lt;p&gt;另外，宿主机终端里的 &lt;code&gt;ulimit -n&lt;/code&gt; 查的是当前 shell。修改它，不会改变已经运行的容器进程。&lt;/p&gt;
&lt;h2 id="配合日志检查"&gt;&lt;a href="#%e9%85%8d%e5%90%88%e6%97%a5%e5%bf%97%e6%a3%80%e6%9f%a5" class="header-anchor"&gt;&lt;/a&gt;配合日志检查
&lt;/h2&gt;&lt;p&gt;出现访问异常时，可以同时看描述符数量和最近的错误日志：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$cid&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; sh -c &lt;span class="s1"&gt;&amp;#39;ls -1 /proc/1/fd | wc -l&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker logs --since 30m &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$cid&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; 2&amp;gt;&lt;span class="p"&gt;&amp;amp;&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;|&lt;/span&gt; grep -Ei &lt;span class="s1"&gt;&amp;#39;too many open files|EMFILE&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;如果描述符数量已经逼近软上限，日志又出现了 &lt;code&gt;Too many open files&lt;/code&gt;，就可以沿着这个方向处理。比赛期间最好连续记录一段时间，看看是开赛后连接集中进入时上涨，还是运行过程中一直累积。&lt;/p&gt;
&lt;h2 id="修改-docker-compose-配置"&gt;&lt;a href="#%e4%bf%ae%e6%94%b9-docker-compose-%e9%85%8d%e7%bd%ae" class="header-anchor"&gt;&lt;/a&gt;修改 Docker Compose 配置
&lt;/h2&gt;&lt;p&gt;先备份现有文件：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cp compose.yml &lt;span class="s2"&gt;&amp;#34;compose.yml.bak.&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;date +%Y%m%d-%H%M%S&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;在原来的 &lt;code&gt;gzctf&lt;/code&gt; 服务下添加 &lt;code&gt;ulimits&lt;/code&gt;，其他配置保留：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;services&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;gzctf&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# 原有的 image、environment、ports、volumes 等配置放在这里&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ulimits&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;nofile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;soft&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;65536&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;hard&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;524288&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;这里把软上限调到 &lt;strong&gt;65536&lt;/strong&gt;，硬上限沿用前面查到的 &lt;strong&gt;524288&lt;/strong&gt;。如果原来的硬上限不同，就按实际环境填写，保证 &lt;code&gt;hard&lt;/code&gt; 不低于 &lt;code&gt;soft&lt;/code&gt;。配置格式可以参考 &lt;a class="link" href="https://docs.docker.com/reference/compose-file/services/#ulimits" target="_blank" rel="noopener"
 &gt;Docker Compose 的 ulimits 文档&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;提高上限不会马上创建 65536 个连接，也不会预先分配这么多文件句柄，只是允许进程在需要时使用更多描述符。&lt;/p&gt;
&lt;p&gt;改完先检查配置，再重建平台容器：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker compose config --quiet
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker compose up -d --no-deps --force-recreate gzctf
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;code&gt;ulimits&lt;/code&gt; 是容器创建参数，所以这里要&lt;strong&gt;重建容器&lt;/strong&gt;，单独执行 &lt;code&gt;docker compose restart&lt;/code&gt; 不会应用新配置。上面的命令只重建平台服务，不重启依赖的数据库；平台会短暂中断，放在赛前操作即可。&lt;/p&gt;
&lt;h2 id="重建后再检查一次"&gt;&lt;a href="#%e9%87%8d%e5%bb%ba%e5%90%8e%e5%86%8d%e6%a3%80%e6%9f%a5%e4%b8%80%e6%ac%a1" class="header-anchor"&gt;&lt;/a&gt;重建后再检查一次
&lt;/h2&gt;&lt;p&gt;容器 ID 会变化，需要重新获取：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;cid&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;docker compose ps -q gzctf&lt;span class="k"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$cid&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; sh -c &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;grep &amp;#34;Max open files&amp;#34; /proc/1/limits&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker compose ps
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker stats --no-stream &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$cid&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;按前面的配置，应该能看到：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Max open files 65536 524288 files
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;接着实际走一遍登录、打开题目列表、查看排行榜、提交 Flag、创建和销毁题目容器。赛前压测也尽量覆盖这些操作和 WebSocket 长连接，光测静态首页看不出完整的业务压力。&lt;/p&gt;
&lt;p&gt;压测时一起记录描述符数量、内存、数据库连接数、错误率和响应时间。访问量降下来后，再看看描述符数量有没有随着连接关闭而回落。如果一直上涨，就继续检查哪些连接或文件没有释放。&lt;/p&gt;
&lt;p&gt;以后部署比赛平台，我会把这两项放进检查清单：&lt;strong&gt;进程的文件描述符软上限，以及高峰时实际用了多少。&lt;/strong&gt; 容器显示 running，并不代表平台还能正常处理新的连接。&lt;/p&gt;</description></item></channel></rss>