
最近有位同事跑来跟我说他在 VMware 里装的 Ubuntu 22.04用 wget 下载一个安装脚本速度只有几 KB/s有时候干脆卡在 0% 不动。我一开始也以为是目标服务器选得不好后来自己动手复现了一遍才发现这类问题在虚拟机环境里太典型了——wget 本身只是一个普通下载工具但虚拟机里的网络栈、DNS、MTU、磁盘 IO任何一个环节掉链子都会让下载慢得离谱。比如很多人装 ROS 时习惯用wget http://fishros.com/install -O fishros . fishros这条命令如果卡住不动问题往往不在脚本本身而在你脚下这张网。这篇文章我会从下载链路分析讲起给你一套完整的排查顺序再给出六个实测有效的提速方案。无论你是刚接触 Ubuntu 和虚拟机的新手还是部署环境时反复踩坑的老手下面这些内容都能让你少走弯路直接照做就行。1. 先把问题拆开wget 慢问题可能出在整条链路上1.1 一次下载不是一个动作而是一条流水线很多人觉得 wget 下载慢就是服务器限速或者网速不行其实一次下载在底层是一条完整的流水线大致可以分为六个阶段DNS 解析把域名解析成 IP 地址。TCP 三次握手与服务器建立连接。TLS 握手如果 URL 是 HTTPS还要做证书校验和密钥协商。HTTP 请求与响应客户端发请求服务端返回状态码和文件信息。数据传输数据分块传输到本机。落盘写入内核把收到的数据写入文件系统。这六个阶段里任何一个环节出问题你的体感都是下载慢。比如 DNS 解析如果耗时 8 秒你看到 wget 一开始就卡住几秒以为它在连接其实只是在等域名解析。再比如 TLS 握手如果因为虚拟机的 CPU 性能太弱而慢那 HTTPS 文件下载就会整体被拖慢但同一台物理机上可能完全没感觉。我在排查这类问题时有个习惯先不急着优化而是把链路拆开逐段测。只有知道慢在哪个阶段后面所有方案才不会是无头苍蝇。1.2 虚拟化环境下多出来的三个隐形瓶颈虚拟机环境和物理机相比有三个方面会额外拖慢 wget 下载第一是网络转发模式。VMware 默认用 NAT 模式虚拟机的流量要先到虚拟网卡 VMnet8再由宿主机做 NAT 转发到物理网络。这个转发过程依赖宿主机的 CPU 和内存如果宿主机本身负载高、内存吃紧或者杀毒软件在实时扫描流量NAT 转发的吞吐量会大幅下降。桥接模式则让虚拟机直接接入物理局域网网络路径更短但同样依赖宿主机 CPU 对虚拟网卡的中断处理。第二是虚拟网卡驱动的差异。VMware 默认给 Ubuntu 配置的网卡类型可能是 e1000/e1000e这是一种纯软件模拟的百兆/千兆网卡CPU 开销大吞吐量上限也低。而 VMware 自家优化的半虚拟化网卡 VMXNET3性能和 CPU 开销都明显更好但需要提前安装 open-vm-tools 或者 VMware Tools 才能生效。第三是磁盘 I/O 瓶颈。wget 下载的数据最终要写入虚拟磁盘如果虚拟磁盘放在机械硬盘上或者宿主机磁盘空间紧张、碎片严重那即便网络速度很快落盘速度也跟不上命令看起来就会慢。搞清楚这三个隐形瓶颈你就能理解为什么同样的 wget 命令在物理机上飞快换到虚拟机里就慢得像蜗牛。接下来要做的是用五分钟量化定位确认到底卡在哪一段。2. 五分钟定位慢的源头2.1 对照实验物理机 vs 虚拟机排查这类问题我强烈建议先做一个对照实验在宿主机物理机上也执行同样的 wget 命令和虚拟机里的结果做对比。假设你要下载的地址是https://example.com/bigfile.tar.gz那么在宿主机上先跑一遍time wget -4 https://example.com/bigfile.tar.gz记下总耗时和平均速度。然后在虚拟机里跑同样的命令time wget -4 https://example.com/bigfile.tar.gz如果宿主机速度正常只有虚拟机慢那问题大概率出在虚拟化层——网卡驱动、NAT 转发、磁盘 IO直接跳到后面的方案四去调配置。如果宿主机本身也慢说明问题出在网络链路或者目标服务器这时候重点考虑换源、多线程下载。另外提醒一句加不加-4区别很大。Ubuntu 默认会优先尝试 IPv6 连接如果你的宿主机或者路由器 IPv6 环境不稳定wget 会先花很长一段时间等 IPv6 连接超时然后才回退到 IPv4。这一步经常让人误以为服务器没响应实际上是在傻等。2.2 DNS 解析拖慢第一步很多时候 wget 慢并不是下载慢而是解析域名慢。Ubuntu 默认用的是 systemd-resolved 管理的 DNS 服务配置解析顺序比较复杂一旦上游 DNS 服务器响应慢整个下载的第一步就会卡住。我自己常用的检查方法是直接看解析耗时。先确认本机用的 DNS 地址cat /etc/resolv.conf resolvectl status | grep -A 4 DNS Servers如果看到 DNS 服务器地址不是你期望的公共 DNS而是某个很慢的网关地址就基本可以断定解析环节有问题。再用dig或者nslookup分别测一下不同 DNS 的解析耗时dig 223.5.5.5 www.baidu.com 2/dev/null | grep Query time dig 8.8.8.8 www.baidu.com 2/dev/null | grep Query time正常情况解析耗时应该在几十毫秒以内。如果某个 DNS 动辄几百毫秒甚至超时说明该换了。Ubuntu 22.04 及以后版本建议直接修改 netplan 配置来指定 DNS比手动改/etc/resolv.conf更稳定因为 systemd-resolved 会随时覆盖手动修改。2.3 用 curl 把每一段耗时量出来对照实验只能判断快不快要精确定位慢在哪一段我用 curl 的-w参数输出详细的耗时分段curl -w DNS: %{time_namelookup}s\nConnect: %{time_connect}s\nTLS: %{time_appconnect}s\nStartTransfer: %{time_starttransfer}s\nTotal: %{time_total}s\n -o /dev/null -L https://example.com/bigfile.tar.gz这个命令会输出四组时间DNS域名解析耗时。Connect建立 TCP 连接耗时。TLSHTTPS 握手耗时。StartTransfer从发出请求到收到第一个字节的耗时这一步通常包含服务器处理时间。Total总耗时。如果 DNS 耗时长重点检查 DNS 配置如果 Connect 耗时长可能和网络路径、防火墙策略有关如果 StartTransfer 耗时特别长说明服务器响应慢或者请求被限速如果 Total 长但 StartTransfer 正常说明是传输阶段慢单连接被限速的可能性大。这套数据拿到手后面的方案选择就清晰了。3. 六个提速方案从简单到进阶3.1 第一优先级换成速度快且稳定的镜像源如果说这么多方案里哪个性价比最高我首推换源。很多慢的问题根本不是虚拟机的问题而是你访问的目标服务器本身离你太远、带宽不够或者限速严重。国内有大量高质量的开源镜像站比如阿里云、清华 TUNA、中科大 USTC、华为云针对 Ubuntu 软件源、Python pip 包、Docker 镜像都有稳定加速。先看 Ubuntu 软件源。Ubuntu 22.04 及更早版本配置文件在/etc/apt/sources.list直接用 sed 一键替换成阿里云源sudo sed -i shttp://.*archive.ubuntu.comhttp://mirrors.aliyun.comg /etc/apt/sources.list sudo sed -i shttp://security.ubuntu.comhttp://mirrors.aliyun.comg /etc/apt/sources.list sudo apt updateUbuntu 24.04 开始改用了 deb822 格式配置文件在/etc/apt/sources.list.d/ubuntu.sources替换方式稍有不同sudo sed -i s//.*archive.ubuntu.com//mirrors.tuna.tsinghua.edu.cng /etc/apt/sources.list.d/ubuntu.sources sudo apt update这里有个细节如果报错提示无法验证签名或者拉取失败很可能是源地址的版本代号不匹配检查一下镜像站是否支持你的 Ubuntu 版本。pip 的配置更简单一条命令全局生效pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simpleDocker 镜像加速稍微特殊一点需要给 Docker 守护进程配置 registry-mirrorssudo mkdir -p /etc/docker sudo tee /etc/docker/daemon.json EOF { registry-mirrors: [https://docker.mirrors.ustc.edu.cn] } EOF sudo systemctl restart docker特别注意Docker 镜像加速地址的有效性会随时间变化很多公共镜像加速器已经停止服务。配置后可以先执行docker pull alpine测试一下如果拉取失败就换别的可用地址或者检查一下你的 Docker 版本是否支持该配置格式。3.2 给 wget 上正确的参数别让它傻等wget 默认的容错策略很保守它不会主动处理连接超时、IPv6 回退、断点续传这些问题。很多下载慢、卡住、失败的场景加几个参数就能缓解。我现在下载文件标准命令长这样wget -4 -c -t 5 --timeout30 --dns-timeout10 -O myfile.tar.gz https://example.com/myfile.tar.gz这几个参数各有讲究-4强制走 IPv4避免 IPv6 连接失败导致长时间等待。-c断点续传。如果下载中断下次执行会从断点继续不用从头再来。-t 5失败重试 5 次。网络抖动时很管用。--timeout30设置连接和读取超时时间防止卡死。--dns-timeout10DNS 解析超时避免域名解析阶段卡很久。-O指定输出文件名避免下载回来一堆乱起八糟的文件名。还有一个容易被误解的参数--limit-rate。很多人以为它能加速其实它是限速用的比如--limit-rate100k是限制下载速度为 100KB/s。如果你在某个配置脚本里看到这个参数恰恰会导致下载变慢要注意别被误导。如果你遇到某些网站对 wget 默认的User-Agent做了限制下载回来的是一个 HTML 报错页面可以显式指定浏览器标识wget -U Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0 Safari/537.36 https://example.com/file这个方法在处理部分软件站、文档站时特别有效因为它们会区分爬虫和正常用户。3.3 单线程变多线程aria2 和 axelwget 默认是单连接下载很多服务器的单连接带宽限制很严格即便你网速再好单个连接也只能跑到几百 KB/s。这种情况最直接的办法是换多线程下载工具。我常用的两个是 aria2 和 axel它们都能把一个文件分成多段并行下载速度提升非常明显。安装都很简单sudo apt update sudo apt install aria2 axelaria2 的多线程下载命令aria2c -x 16 -s 16 -k 1M -o myfile.tar.gz https://example.com/myfile.tar.gz参数含义是-x 16表示单服务器最多开 16 个连接-s 16表示把文件分成 16 段-k 1M表示每段最小切片大小。实测下来对于单连接限速的服务器同样的文件从一两百 KB/s 提升到几 MB/s 是常有的事。axel 更轻量axel -n 8 -o myfile.tar.gz https://example.com/myfile.tar.gz-n 8表示开 8 个连接。axel 的界面比较简洁适合快速下载。需要提醒的是多线程下载是把双刃剑。如果目标服务器有比较严格的访问控制短时间内大量并发连接可能触发封 IP 或者验证码如果服务器不支持 Range 请求aria2 和 axel 也可能退化成单线程甚至失败。所以遇到重要资源先用 wget 看一下是否支持断点续传再上多线程工具。3.4 调整 VMware 网络与硬件配置如果排除了目标服务器的问题虚拟机的网络配置就是重点。我在 VMware 里实测过默认的 NAT 模式加 e1000 网卡组合和大流量下载场景其实不太搭。优先做两个调整第一个是网卡类型换成 VMXNET3。具体操作是关闭虚拟机在 VMware 虚拟机设置里找到网络适配器把设备类型从E1000E或默认改成VMXNET 3。改完之后进入 Ubuntu确认open-vm-tools已经安装sudo apt install open-vm-tools ip link show如果一切正常你会看到网卡名称和速率都有变化。VMXNET3 是半虚拟化网卡中断次数少吞吐量高对大文件下载特别友好。第二个是网络模式的选择。NAT 模式适合普通上网场景配置简单不用管 IP。但如果你经常下载大文件尤其是有 NAS、局域网内互相传输需求建议改成桥接模式。桥接模式下虚拟机和宿主机处于同一局域网流量不再经过额外的 NAT 转换效率更高。改完桥接后Ubuntu 需要重新获取 IP如果是 DHCP 通常会自动处理实在不行就重启一下网络服务。另外别忘了检查 VMware 分配给虚拟机的 CPU 和内存。wget 本身不占资源但 TLS 加解密需要 CPUDocker、编译等高负载场景同时进行时虚拟机如果只有 1 核 1G 内存下载速度很容易被拖累。我给开发用虚拟机的底线配置是 2 核 4G如果要做数据下载、模型训练之类的活建议直接 4 核 8G。3.5 MTU 和 IPv6 引发的假死还有一种很隐蔽的情况下载不报错但速度极慢或者经常卡住不动。这往往是 MTU最大传输单元不匹配导致的。家用宽带常见的光猫拨号 PPPoE 场景MTU 通常要降到 1492而虚拟机网卡默认 MTU 是 1500。当虚拟机访问外网时数据包超过链路允许的大小就需要分片分片处理会显著增加延迟和丢包率表现就是下载速度时快时慢甚至某些大文件一直卡住。在 Ubuntu 里检测 MTU 是否合适最常用的方法是 ping 加-M do参数禁止分片地发送指定大小的包ping -M do -s 1472 -c 4 baidu.com如果返回正常说明 1500 的 MTU 没问题如果提示需要分片就把数值往下调。1472 是测试载荷加上 28 字节的 IP 头刚好等于 1500。你可以在 1400、1450、1472 几个值之间多测几次找到能稳定 ping 通的最大值。临时修改网卡 MTU 可以直接用 ip 命令sudo ip link set dev ens33 mtu 1400如果要永久生效Ubuntu 通常通过 netplan 配置。编辑/etc/netplan/*.yaml在网卡节点下加一行network: version: 2 ethernets: ens33: mtu: 1400然后执行sudo netplan apply生效。这里注意网卡名称要以实际ip link输出为准很多系统里叫ens33也有叫ens160或者eth0的。至于 IPv6如果你并不需要它最简单的办法是让 wget 强制走 IPv4或者直接 sysctl 关闭 IPv6sudo sysctl -w net.ipv6.conf.all.disable_ipv61这个方法治标不治本但作为排查手段非常有效——如果关掉 IPv6 之后下载恢复正常那基本可以确定是 IPv6 路由不稳导致的。3.6 大文件下载的工程化管理下载几百 MB 甚至几个 GB 的大文件时我建议不要只是敲一条 wget 然后干等。一个是终端会话断开会导致下载中断另一个是下载过程中看不到进度细节出问题不好排查。我习惯用 tmux 或者 screen 把下载任务放到后台会话里执行tmux new -s download wget -c -4 -O bigfile.iso https://example.com/bigfile.iso这样即使 SSH 断开下载也会继续。需要查看进度时重新 attach 回去就行tmux attach -t download如果你希望下载日志持久化方便后续排查用--progressdot:gauge加输出重定向wget -c -4 --progressdot:gauge -O bigfile.iso https://example.com/bigfile.iso wget.log 21另外下载完成后建议顺手校验一下文件完整性。大部分正规下载源会提供.md5或.sha256校验文件下载完用 sha256sum 核对sha256sum bigfile.iso这一步能避免很多下完了但解压失败的尴尬情况尤其是大文件网络波动可能没让 wget 报错但文件已经损坏。4. 常见问题速查与避坑实录4.1 一张速查表先救急我把这段时间在 Ubuntu 虚拟机上遇到过的 wget 下载问题整理成一张速查表先照着查总能解决大部分情况症状可能原因推荐解法wget 长时间停在 0% 不动IPv6 连接失败等待回退、DNS 解析慢加-4参数检查 DNS换镜像源下载速度只有几十 KB/s服务器单连接限速用 aria2/axel 多线程下载下载速度忽快忽慢、卡顿MTU 分片、网络拥塞调整 MTU改用桥接模式虚拟机明显比物理机慢虚拟网卡驱动、NAT 转发瓶颈换 VMXNET3 网卡宿主机关闭占资源的软件下载回来的文件是 HTML服务器返回错误页或需要指定 UA加-U指定浏览器标识确认 URL下载中断后无法续传服务器不支持 Range 请求换源或使用浏览器/多线程工具重试磁盘空间充足但速度越来越慢虚拟磁盘宿主机碎片、IO 瓶颈检查宿主机磁盘健康避免同时跑高 IO 任务这张表里的绝大多数问题我都在实际环境里碰到过。尤其是卡在 0%和H T M L 文件两个情况几乎每个月都会有人来问。4.2 我踩过的三个坑第一个坑DNS 配了但没生效。有段时间我直接改了/etc/resolv.conf发现过一会儿又被 systemd-resolved 覆盖回原来的配置。后来才意识到 Ubuntu 22.04 里这个文件是软链接正确做法是改 netplan 或者用resolvectl管理。所以如果你手动改了 DNS 发现没效果先ls -l /etc/resolv.conf看一下是不是软链接。第二个坑VMXNET3 网卡改完没有 IP。有一次在 VMware 里改了网卡类型重启后 Ubuntu 直接没有网了。原因是我用的 Ubuntu 镜像没有预装 open-vm-toolsVMXNET3 驱动没加载。解决办法是先保持旧网卡能联网装好open-vm-tools再去切换网卡类型或者用 VMware 的虚拟机设置界面把网卡临时配置为连接时连接保证能进系统补救。第三个坑为了追求速度把并发数拉满结果被服务器限流。用 aria2 时我把-x和-s都设为 32结果下载刚开始很快十几秒后服务器把所有连接全部重置反而不如 8 并发稳定。现在我的经验是普通服务器 8 到 16 并发足够如果目标服务器数据源在国外或访问量大先用 4 并发试探一下再逐步增加。4.3 顺手分享一个我常用的下载脚本最后分享一个我现在常用的下载脚本逻辑算是给上面所有方案做个小结#!/bin/bash # usage: fastwget.sh url [output] URL$1 OUT${2:-$(basename $URL)} # 首选 aria2 多线程下载失败则回退 wget if command -v aria2c /dev/null; then aria2c -x 8 -s 8 -k 1M -c -o $OUT $URL else wget -4 -c -t 5 --timeout30 -O $OUT $URL fi # 下载完成后提示校验 echo Downloaded $OUT. Consider verifying checksum with sha256sum.这个脚本不复杂但结合了多线程、断点续传、超时处理和最后的校验提醒覆盖了前面讲的大部分优化点。实际使用时如果源地址需要登录或者带临时 token直接在 URL 参数里拼好再传给脚本就行。结合我自己的经验Ubuntu 虚拟机里 wget 慢九成是网络路径和虚拟化配置的问题而不是 wget 本身的毛病。下载不同来源的文件多准备几套方案该换镜像换镜像该上多线程上多线程虚拟机网络配置该调就调问题基本都能解决。排查的时候保持先测后改的习惯你也能很快找到那只拖后腿的木桶短板。