这两天 ChatGPT 桌面版(Microsoft Store 版)弹出「正在安装更新」,说装完会自动重启,结果进度条好几个小时才挪一点。前一天的那个版本更离谱,下了 11 个半小时,下完一个多小时后还没安装就被系统丢掉了,新版本又从 0 开始下。
折腾了一晚上,绕了好几个弯,最后在传递优化(Delivery Optimization)自己的日志里找到了原因:它在给「用户启动」的下载自动限速。全速跑几秒,然后切到「Limited」等 2~4 分钟,再全速几秒,一直循环。设置里的活动监视器也能看出来:这个月用户启动的下载平均只有 1.1 Mbps,后台下载却有 271 Mbps。
解决办法很简单:在传递优化的高级选项里,给前台下载设一个「绝对带宽」上限,填一个比实际网速大的值。改完之后,卡在 45% 二十分钟的更新几秒钟就下完装好了。改 DNS、写 hosts、屏蔽「慢」的 IP 都没用。下面记一下排查过程。
问题现象
- ChatGPT 弹窗「正在安装更新 / 安装完成后,ChatGPT 将重新启动。」,进度条几乎不动。
- 任务管理器里找不到安装程序,磁盘和 CPU 都很闲。
- 前一天的 26.1016.8120 下了 11.6 小时,下完大约一小时后还没安装就被系统删掉了;新出的 26.1016.8622 又从头开始下。
是谁在下载
Store 版 ChatGPT 的包名其实叫 OpenAI.Codex。它的更新不是 ChatGPT 自己下的:Store 的安装服务把下载交给传递优化服务(DoSvc),AppX 部署服务(AppXSvc)一边收数据一边解包到 C:\Program Files\WindowsApps,所以任务管理器里看不到安装程序。
AppX 部署日志 Microsoft-Windows-AppXDeploymentServer/Operational 里,每次部署结束都会写一条性能摘要(事件 613):
1 2 | Get-WinEvent -FilterHashtable @{LogName='Microsoft-Windows-AppXDeploymentServer/Operational'; Id=613} | Where-Object Message -match 'OpenAI' | Select-Object -First 1 -ExpandProperty Message |
1 2 3 4 | 程序包 OpenAI.Codex_26.1016.8120.0_x64__2p2nqsd0c76g0 上的部署 Stage 操作的性能摘要: Overall time: 41876219 ms (Active time: 41876203 ms) …… Stage required cost: 41855813 ms ← 11.6 小时几乎全花在这一步(边下载边解包) |
下载进度用 Get-DeliveryOptimizationStatus 看(地址里的签名删掉了):
1 2 3 4 5 6 7 8 9 10 11 | FileId : 07e4a976049575e194de6e0a135f23b79c9bfbb1 FileSize : 968540851 TotalBytesDownloaded : 445301427 Status : Downloading Priority : Foreground DownloadMode : CdnOnly SourceURL : http://tlu.dl.delivery.mp.microsoft.com/filestreamingservice/files/d6e6fc57-……?P1=……&P4=…… CacheHost : 74.177.135.22 BytesFromCacheServer : 445301427 DownloadDuration : 02:18:01 PredefinedCallerApplication : WU Client Download |
924 MB 的包,2 小时 18 分钟下了 425 MB。CacheHost 是 DO 分配的一台微软缓存服务器,数据全是从它那来的。注意 Priority: Foreground,后面会用到。
弯路一:网络、DNS、屏蔽 IP
第一反应是缓存服务器或 CDN 节点太慢,想改 DNS、写 hosts,或者把这台缓存服务器屏蔽掉。动手之前先测了一下:拿 SourceURL 里的地址,对不同 DNS 解析出来的节点,各下同一个文件的前 20 MB:
1 2 3 4 5 6 7 | URL='http://tlu.dl.delivery.mp.microsoft.com/filestreamingservice/files/……' # SourceURL 原样复制 HOST=tlu.dl.delivery.mp.microsoft.com for ip in 2.18.27.142 2.16.168.47 146.75.30.172 199.232.210.172; do curl -s -o /dev/null -r 0-20971519 --resolve "$HOST:80:$ip" -w "$ip %{time_total}s %{speed_download} B/s\n" "$URL" done # 缓存服务器:主机换成 CacheHost,地址末尾加上 &cacheHostOrigin=$HOST curl -s -o /dev/null -r 0-20971519 -w "cache %{time_total}s %{speed_download} B/s\n" "http://74.177.135.22${URL#http://$HOST}&cacheHostOrigin=$HOST" |
| 节点 | 来源 | 20 MB 用时 | 速度 |
|---|---|---|---|
| 74.177.135.22 | DO 分配的缓存服务器 | 0.36 s | 56 MB/s |
| 2.18.27.142 / .178 | 本地 DNS(Akamai) | 0.33~0.36 s | 56~61 MB/s |
| 2.16.168.47 / 2.20.245.169 | DNSPod(Akamai) | 0.44~0.47 s | 42~46 MB/s |
| 146.75.30.172 | 阿里 DNS(Fastly) | 1.27 s | 16 MB/s |
| 199.232.210.172 / .214.172 | Google、Cloudflare DNS(Fastly) | 0.29 s | 70 MB/s |
文件末尾还没人请求过的部分也一样快。再用 BITS(同样是系统服务)把整个包下一遍,924 MB 用了 12 秒。
后来又注意到,每次都是先很快下到 400 MB 左右然后卡住,怀疑是不是下了 400 MB 以后被限速。于是用一个连接从缓存服务器下了整个文件:9 秒,全程 100 MB/s 左右,过了 400 MB 也没变慢。
网络、CDN、缓存服务器都没问题,改 DNS、hosts、屏蔽 IP 都不会有用。
弯路二:文件占用、IDM
每秒记一次 DO 的下载量,发现它隔两三分钟才跳一下,每次 1~4 MB,中间全是 0。WindowsApps 下新版本的目录普通用户就能列出来,已解包文件的写入时间也是隔 145 秒左右一批。磁盘 97% 空闲,AppXSvc 基本不占 CPU,看着像是在等什么。
先怀疑文件占用。AppX 部署日志里每 6 分钟就有一组「错误 0x12C: 删除文件 …\WindowsApps\Deleted\OpenAI.Codex_26.1016.8120.0…\app\icudtl.dat 失败」。用 fsutil hardlink list 一看,AppX 把新旧版本里相同的文件做成了硬链接,被丢弃的那个版本里的 icudtl.dat 和正在运行的版本是同一个文件,ChatGPT 开着就删不掉:
1 2 3 4 | > fsutil hardlink list "C:\Program Files\WindowsApps\OpenAI.Codex_26.1016.8622.0_x64__2p2nqsd0c76g0\app\icudtl.dat" \Program Files\WindowsApps\OpenAI.Codex_26.1013.4894.0_x64__2p2nqsd0c76g0\app\icudtl.dat \Program Files\WindowsApps\Deleted\OpenAI.Codex_26.1016.8120.0_x64__2p2nqsd0c76g0……\app\icudtl.dat \Program Files\WindowsApps\OpenAI.Codex_26.1016.8622.0_x64__2p2nqsd0c76g0\app\icudtl.dat |
这个无害,关掉 ChatGPT 后就清掉了,但和慢没关系:完全退出 ChatGPT 之后,下载还是一样隔几分钟跳一下。
然后怀疑 IDM,它装了个 WFP 驱动 IDMWFP,在系统层面监视下载。退出 IDM,还是一样。
原因:传递优化在给自己限速
最后去看 DO 自己的日志。要管理员权限,日志里的时间是 UTC:
1 2 | Get-DeliveryOptimizationLog -Flush | Where-Object Function -like 'CDownloadRateStrategy*' | Select-Object -Last 20 TimeCreated, Message |
这是新版本 26.1021.2667 开始下载之后的记录(只留了相关的行):
1 2 3 4 5 6 7 8 9 10 11 12 | 22:17:34 Piece stats: Pending: [#Incomplete: 837, #In-order: 837], Completed: 2 22:17:38 progressPct = 25 22:17:40 DownloadRateStrategy: Unlimited to Limited, next unlimited phase in 101686 ms 22:19:04 No progress(last seen bytes = 416724071) seen for ca2435e6…… 22:19:22 DownloadRateStrategy: Limited to Unlimited 22:19:29 DownloadRateStrategy: Unlimited to Limited, next unlimited phase in 188987 ms 22:20:34 No progress(last seen bytes = 419869799) seen for ca2435e6…… 22:22:04 No progress(last seen bytes = 420918375) seen for ca2435e6…… 22:22:39 DownloadRateStrategy: Limited to Unlimited 22:22:46 DownloadRateStrategy: Unlimited to Limited, next unlimited phase in 119488 ms 22:24:50 DownloadRateStrategy: Limited to Unlimited 22:24:58 DownloadRateStrategy: Unlimited to Limited, next unlimited phase in 245051 ms |
一下就清楚了:
- DO 只在「Unlimited」阶段全速下载,每次只有 6~8 秒;然后切到「Limited」,等 100~245 秒,中间一直报「No progress」。下载量每隔几分钟跳一下,正好对上每次 Unlimited 的那几秒。
- 「先很快下到 400 MB 再卡住」也不是什么 400 MB 的限制:开头第一个 Unlimited 阶段有 6 秒,按 70 MB/s 算正好能下 400 MB 左右。
- 日志里最早的记录是 10 月 18 日,从那时起就一直这样,「Unlimited to Limited」一共出现了 154 次。
为什么 Limited 阶段几乎是 0?日志里 DO 记录的「最大测得速度」只有一行:
1 | 22:12:33 DownloadRateStrategy: max = 9526, priv = 9526, perfCtr = 0 |
单位日志里没写,如果是 B/s 的话也就 9.5 KB/s。前台下载默认限制为「测得带宽的 90%」,如果 DO 一直拿这个离谱的估计值来限速,自己限着速,测出来的速度自然也高不了,就这么卡住了。这部分是我的推测,但和下面的结果对得上。
另外,DO 从微软服务器拿到的配置里有这么两项,看起来自动限速是云端下发的开关(可能是最近才在一部分机器上打开的,所以以前没遇到过):
1 2 | "Client_DownloadRateAutoLimit":"1", "Client_DownloadRateBackgroundAutoLimit":"2", |
其实设置里也能直接看到:设置 → Windows 更新 → 高级选项 → 传递优化 → 活动监视器,这个月「平均下载速度(用户启动)」只有 1.1 Mbps,「平均下载速度(后台)」却有 271.0 Mbps。在 Store 里点更新、应用自己触发的更新,都算「用户启动」(前台)下载。
解决办法:给前台下载设一个绝对带宽上限
- 打开「设置 → Windows 更新 → 高级选项 → 传递优化 → 高级选项」。
- 在「下载设置」里选「绝对带宽」。
- 勾选「限制用于在前台下载更新的带宽大小」,填一个比自己实际网速大的值,比如 999 Mbps。后台那项可以一起设。
设好后可以用 Get-DOConfig 确认,DownloadForegroundLimitBps 的来源变成了 SettingsProvider:
1 2 | DownloadForegroundLimitBps : 130940928 DownloadForegroundLimitBpsProvider : SettingsProvider |
这样 DO 就按这个固定值来限速,不再用那个测出来的速度。效果立竿见影:卡在 45% 左右二十分钟的更新,改完设置后几秒钟就下完了(811 MB → 完成),AppX 随即完成部署,ChatGPT 更新到了 26.1021.2667。这个设置要一直保持,改回「测得带宽的百分比」大概率又会变慢。
备用办法:手动下载 MSIX 安装
找到原因之前,我先用这个办法装上了一个版本。不需要管理员权限,前提是 Store 的更新还在下载(DO 里能看到地址):
1 2 3 4 5 6 7 8 9 10 11 | # 1. 拿到系统正在下载的地址(列出多个的话,按 FileSize 挑出 ChatGPT 那个) $job = Get-DeliveryOptimizationStatus | Where-Object { $_.Status -eq 'Downloading' -and $_.SourceURL -like '*filestreamingservice*' } $job | Format-List FileId, FileSize, SourceURL # 2. 用 BITS 下载(不经过 DO,几十秒就下完) $pkg = "$env:USERPROFILE\Downloads\ChatGPT.msix" Start-BitsTransfer -Source $job.SourceURL -Destination $pkg -Priority Foreground # 3. 校验:签名应为 Valid,颁发者是 Microsoft Marketplace CA;DO 的 FileId 就是文件的 SHA1 Get-AuthenticodeSignature $pkg | Format-List Status, @{n='Issuer';e={$_.SignerCertificate.Issuer}} (Get-FileHash $pkg -Algorithm SHA1).Hash -eq $job.FileId |
然后彻底退出 ChatGPT(托盘图标右键退出),用 Windows PowerShell(powershell.exe,PowerShell 7 加载不了这个 WinRT 类型)取消 Store 里卡住的更新,再安装:
1 2 3 4 5 6 7 8 | $null = [Windows.ApplicationModel.Store.Preview.InstallControl.AppInstallManager, Windows.ApplicationModel.Store.Preview, ContentType=WindowsRuntime] $mgr = New-Object Windows.ApplicationModel.Store.Preview.InstallControl.AppInstallManager $mgr.AppInstallItems | Where-Object PackageFamilyName -like 'OpenAI.Codex*' | Select-Object ProductId, PackageFamilyName $mgr.Cancel('9PLM9XGG6VKS') # ChatGPT 在 Store 里的 ID $pkg = "$env:USERPROFILE\Downloads\ChatGPT.msix" Add-AppxPackage -Path $pkg -ForceApplicationShutdown Get-AppxPackage OpenAI.Codex | Select-Object Name, Version |
整个安装用了 25 秒。注意只用系统自己给出的下载地址,地址带签名和有效期,过一段时间就会失效;不要从第三方网站下 MSIX。
如果你也遇到了
- 先看「设置 → Windows 更新 → 高级选项 → 传递优化 → 活动监视器」:如果「用户启动」的平均下载速度比「后台」低很多,大概率就是这个问题。
- 想确认的话,管理员运行
Get-DeliveryOptimizationLog,找DownloadRateStrategy: Unlimited to Limited。 - 在传递优化的高级选项里给前台下载设绝对带宽,填一个比网速大的值。
- 改 DNS、hosts、屏蔽 IP 都没用,网络本身没问题。

0 评论