Docker

Windows 10 Docker 基于 WSL 2 时读写性能的坑

Windows 10 启用 WSL 2
Windows 10 启用 Hyper-V 虚拟机

首先到 Docker 官网下载一个 Docker Desktop Windows 安装包
https://www.docker.com/get-started

这有官方的安装教程 https://docs.docker.com/docker-for-windows/install/
安装过程中你会发现它一直在引导你启用 WSL 2,并表示基于 WSL 2 的 Docker 相比基于 Hyper-V 而言拥有各种各样的好处
就连微软官方也在 WSL 2 文档中强调 WSL 2 拥有更好的文件性能等等

ebd179a9a529a38a6b7812fe49c97f89.png

那既然两个官方都这么说了,那就启用吧。启用完毕后,根据自己的需求部署了 php 和 nginx 容器,准备作为本地开发环境,将 Windows 下的代码目录挂载到容器中,试着访问了一下项目

吃惊地发现原本几百ms就能执行完的代码,现在竟要好几秒钟
这还是在代码已经放到 SSD 里的情况下。如果是在 HDD 里甚至一度逼近 8s

经过几个小时的苦苦排障,最后找到了微软官方的这篇文档《比较 WSL 1 和 WSL 2

f0ba92daf38b543c051e6b683bf0e6b3.png

我们直接看最后一行,可以看到,WSL 1 的跨 OS 文件性能是要好于 WSL 2 的
好家伙,感情之前说 WSL 2 更好的文件性能是指不跨 OS 的情况下?

又是一番搜索,看了看 WSL 项目 下的几个 issues(具体链接找不到了),大致都是说由于 Windows 和 Linux 的跨系统文件兼容性问题无法得到很好的解决,WSL 2 下访问 Windows 文件性能会非常差

于是,我关闭了Use the WSL 2 based engine,重启 Docker,此时自动切换到基于 Hyper-V 的模式。再次启动相关容器,尝试访问项目

速度一下子就恢复到可以忍受的范围了,性能竟相差 8 倍有多

也就是说,如果你也像我一样在 Windows 中写代码又在 docker 中运行的话,要么放弃使用 WSL 2,要么忍受龟速文件 IO。好在日常 PHP 的开发并不依赖 WSL 2 的各种完整 Linux 特性

这时可能有人会想到,我把代码文件放在 WSL 2 中挂载到容器里不就没有性能问题了吗?至于 Windows 下如何开发,用 IDE 打开 \\wsl$\ 不就行了吗?

这个办法我已经尝试过了。虽然文件都在本地,但由于 WSL 2 虚拟磁盘的原因,\\wsl$\ 依然走的是 SMB 协议,不仅性能稀烂,而且 IDE 无法获取到文件变更的事件。具体来说就是你 composer 随便依赖一个包,IDE 可能十几二十分钟都缓不过来。这同样是我无法忍受的

但如果你日常开发中使用 VSCode,那么一切又变得简单起来。只要把代码放在 WSL 2 系统中即可解决。至于 Windows 下如何开发,安装一个 Remote – WSL 插件即可。Docker 的官方文档《Develop with Docker and WSL 2》中也有提到这一点
我尝试过这个插件,真的是非常舒服,是真正的云开发。不像 JetBrains 家 IDEs 里所谓的 remote,本质上只是个自动上传的功能而已

7 条评论

昵称
  1. 观察者

    其实一句话就可以解释清楚的事情。WSL1用了翻译层,跨系统走的还是native的文件带调用,WSL2跨系统走的是网络IO,9P协议。

  2. 某亚瑟

    这个WSL2就是逊啦,开启之后连模拟器都没得用

    1. haozi23333

      确实麻烦, docker 也要依赖 wsl, 模拟器和docker不可得兼

  3. aofall

    WSL的磁盘性能一直被诟病,还是不太建议使用。
    (想问问为啥不用Windows下的nginx+PHP呢)

    1. mokeyjay

      目前而言跟在本地差别不大了,能用
      不用 Win 是希望尽可能减小与线上环境的差异。其次 Win 下多版本 php 切换老要去改环境变量,麻烦

  4. Kenvix

    WSL2访问Windows文件不只是速度的问题,CPU占用都非常高。如果你甚至还在用vscode连接wsl2编辑Windows下面的工程,还会持续占用大量CPU,造成电脑电量急剧减少(我的yoga duet板子因为这玩意一节课就耗了60%的电)

    1. mokeyjay

      噫,要是 phpStorm 有像样的 remote 就好了