根本原因是PHP底层cURL或stream在高并发时反复触发glibc DNS解析器,而其不支持并发缓存,导致大量线程争抢53端口查询卡在“resolving host”阶段。

为什么DNS并发查询会卡住Composer安装
根本原因不是Composer本身,而是PHP底层cURL或stream封装在高并发时反复触发系统DNS解析器,而Linux默认的glibc resolver不支持并发缓存。当composer install开启多个下载线程(比如http-max-concurrent-downloads=8),每个线程都独立调用getaddrinfo(),瞬间打穿本地DNS缓存,导致大量请求卡在“resolving host”阶段——日志里反复出现Could not resolve host或curl: (6) Could not resolve host,但nslookup repo.packagist.org单独跑却正常。
怎么验证是不是DNS并发瓶颈
别猜,直接观测真实行为:
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
- 运行
strace -e trace=connect,openat,sendto,recvfrom -p $(pgrep -f "composer install") 2>&1 | grep -i "resolve\|dns\|getaddr",如果看到密集的sendto(...AF_INET...)打向53端口,且伴随大量connect(3, {sa_family=AF_INET, sin_port=htons(53), ...}, 16) = -1 EINPROGRESS,基本锁定DNS层争抢 - 对比测试:
COMPOSER_MAX_PARALLEL_HTTP_REQUESTS=1 composer install能过,但设成4就失败 → 典型DNS并发击穿 - 临时切到Cloudflare DNS:
echo "nameserver 1.1.1.1" | sudo tee /etc/resolv.conf,再试一次;若明显变快,说明原DNS服务器扛不住并发查询
三种实操有效的防御手段
单一改镜像或降并发都不治本,必须组合出手:
-
强制复用DNS解析结果:在
composer.json里加"config": {"fxp-asset": {"enabled": false}}(避免旧插件干扰),然后全局启用DNS缓存代理:sudo apt install dnsmasq+ 配置/etc/dnsmasq.conf含cache-size=1000和port=5353,再让Composer走它:export PHP_EXTRA_CONFIG="--with-curl --with-openssl" && export COMPOSER_HOME=/tmp/composer-test && COMPOSER_DNS_SERVER=127.0.0.1:5353 composer install -
绕过系统DNS,直连IP:用
nslookup mirrors.aliyun.com 1.1.1.1查出IP(如121.40.129.123),然后在composer.json的repositories中把URL写成https://121.40.129.123/composer/(注意保留/结尾),并确保"canonical": false;这样所有HTTP请求跳过DNS解析 -
限制并发+预热DNS:先执行
for i in $(seq 1 8); do nslookup repo.packagist.org 1.1.1.1 >/dev/null 2>&1 & done; wait,再跑COMPOSER_MAX_PARALLEL_HTTP_REQUESTS=6 composer install;这个“预热”能让glibc的res_init()提前填满缓存,避免安装时临场解析
最容易被忽略的细节
DNS问题常被误判为镜像源故障,但真正卡点往往藏在更底层:
- macOS上
scutil --dns显示的DNS服务器可能和resolv.conf不一致,得优先看前者输出; - 某些CI平台(如GitLab Runner)默认禁用
/etc/resolv.conf写入,必须用--dns=1.1.1.1参数启动Docker容器; - Windows WSL2用户要注意:WSL2的
/etc/resolv.conf是自动生成的,手动改会被覆盖,得改/etc/wsl.conf加[network] generateResolvConf = false再重启; - 哪怕用了
hosts文件绑定IP,如果镜像URL里带重定向(比如阿里云HTTP→HTTPS跳转),302响应头里的Location仍会触发新DNS查询——所以务必确认镜像URL以https://开头且无跳转。

















