200GB 文件、24GB SLC 缓存、25°C,页面跑完用了 31 分 47 秒,平均 107.4MB/s。
前 24GB 跑到 2400MB/s,缓存写满后掉到 95MB/s,后半程没再回来。

在线案例与源码:gitcode.com/OPCTeam/dem… 成品是一个 index.html,双击就能打开,不连网,不装依赖。
一、先看结果:标称 2400,平均只剩 107
24GB 缓存只占 200GB 文件的 12%。
剩下 176GB 全走 95MB/s 的缓外直写,平均速度自然被拖到 107.4MB/s。
这不是硬盘坏了,是 SLC 缓存写满后的正常掉速。
| 盘型与缓存 | 缓存覆盖率 | 总耗时 | 平均速度 | 写入放大 |
|---|---|---|---|---|
| 1TB QLC / 12GB | 6% | 31m47s | 107.4MB/s | 1.111x |
| 1TB QLC / 24GB | 12% | 31m47s | 107.4MB/s | 1.111x |
| 1TB QLC / 48GB | 24% | 27m39s | 123.5MB/s | 1.096x |
| 1TB TLC / 24GB | 12% | 6m26s | 531.0MB/s | 1.110x |
12GB 那行和 24GB 一样,是因为 12GB 缓存折完一轮又空出来,第二轮又装了 12GB。
两次 SLC 写入合计 24GB,覆盖率仍然只有 6%。
48GB 缓存只折一轮,省下 4 分 08 秒,平均速度高 15%。

二、为什么值得看:标称速度只对前 12% 生效
搜“SSD 掉速”,出来最多的是跑分截图和“缓外 100MB/s”的结论。
很少有人把 24GB 缓存、200GB 文件、95MB/s 直写放在一条时间轴上,让你看到拐点在哪。
这个页面做的是这件事:你调缓存、文件、温度,曲线和指标当场变。
它不是给某块盘下结论,是把“缓存写满之后发生了什么”拆开给你看。
三、模型怎么跑:两段事件,一条掉速曲线
核心是页面里的 simulate(config) 函数,一个 while 循环。
每次循环算一个事件:持续多久、写多少、前台速度多少、NAND 实际写多少。
slc 阶段按 2400MB/s 写到缓存上限,然后切到 folding。
folding 阶段前台按 95MB/s 直写,后台按 12MB/s 把 SLC 数据折进 QLC。
折叠完成后缓存释放,回到 slc 阶段,继续下一轮。
每个事件里都保存 foldSpeed,画颗粒地图和算写入放大时直接读这个值。
图表按每 200MB 一个采样点绘制,时间轴可以拖到任意时刻。
这样 24GB 缓存写满的那个点,在曲线上就是一条垂直掉速线。
四、验证与踩坑:10 条断言和几处返工
页面右下角有 10 条断言,10/10 PASS 才算跑通。
第一版是 9/10,红的是温度降频那条。
断言取的是第一个 throttled 事件,这个事件前 29.76 秒还是 95MB/s,降频发生在它之后。
改成找速度等于 68.4MB/s 的事件,断言才真正检查到降频因子。
第二个问题更隐蔽。
颗粒地图用 ev.speed === 95 判断盘型,再决定折叠速度用 12 还是 60。
45°C 降频后前台速度是 68.4,这个判断落空,QLC 被当成 TLC,折叠进度和写入放大都偏了。
修法是在生成事件时把 foldSpeed 一起存下来,后面不再猜。
第三个问题是缓存覆盖率。
原来用 SLC 写入总量除以文件大小,12GB 缓存折了两轮,分子变成 24GB,页面显示 12%,实际覆盖率只有 6%。
改成 min(cacheSize, fileSize) / fileSize,标签也从命中率改成覆盖率。
第四个问题是重置不清错误提示。
输入 0 缓存报了错,再点重置,红字还挂在那里。
重置时顺手把 err-msg 的 show 类去掉。
还有两个交互缺口。
自检之外没有入口能触发非法输入,我加了自定义 GB 输入框。
200 倍速下 SLC 阶段只有 0.05 秒,根本看不清,我加了时间轴。
这两处不是逻辑错误,但不补上,读者没法复现截图里的状态。

五、把温度拉到 45°C:平均只剩 77.8
45°C 下,模型在持续写入 40 秒后降频,直写速度乘 0.72,变成 68.4MB/s。
200GB 跑完要 43 分 54 秒,平均 77.8MB/s,比 25°C 慢 38%。
35°C 不会触发降频,因为模型的阈值设在 40°C。
这不是说真实盘 35°C 一定不降频,只是这个模型只模拟了环境温度这一层。
盘型差异更大。
同样 24GB 缓存,TLC 缓外 480MB/s,200GB 跑完 6 分 26 秒,平均 531MB/s。
QLC 是 31 分 47 秒,平均 107.4MB/s,差了 4.9 倍。

六、它不是真实硬盘测试
这个页面没有跑 fio,也没有读 SMART。
所有数字来自一个离散事件模型,参数是公开评测里常见的 QLC/TLC 量级。
真实盘受主控、固件、SLC 策略、垃圾回收和文件系统影响,曲线不会这么整齐。
不同盘的缓外速度可能从 80 到 150MB/s,SLC 缓存也可能随剩余空间变化。
把它当成理解“缓存写满后为什么掉速”的教具可以,别拿它给某块盘下结论。
模型还有一条简化:折叠期间前台按缓外速度算,后台折叠速度固定。
真实盘会更复杂。
七、准备环境:进入码道 Web 与本地复现
浏览器打开码道 Web 版:devcloud.cn-north-4.huaweicloud.com/chat?source…
码道有三种使用方式:WebUI(浏览器对话)、TUI(终端命令行)和桌面 IDE(IDE 插件)。本文用 WebUI 版演示。
下载 index.html 后,在文件所在目录起一个静态服务:python -m http.server 8000,再打开 http://localhost:8000/index.html。
按这个顺序点,能复现本文的数字:
- 保持 1TB QLC、24GB 缓存、200GB、25°C,点开始。
- 把时间轴拖到 6 秒,看 SLC 阶段 2400MB/s。
- 拖到 22 分 15 秒,看速度掉到 95MB/s。
- 点“跑 200GB 对比”,看 12/24/48GB 三条曲线。
- 在自定义文件大小里输入 2048,点开始,看红字报错。
自检面板 10/10 PASS。
失败提示原文:错误:文件大小(2048GB)超过盘容量(1024GB)。

八、直接下载试玩
这个 Demo 已经完整开源,源代码、本文档和全部截图都在公开仓库:
- Demo Park 仓库:gitcode.com/OPCTeam/dem…
- 本案例目录:gitcode.com/OPCTeam/dem…
进入 codearts-ssd-slc-cache-lab 文件夹,把 index.html 下载到本地,用浏览器打开即可运行。
九、使用码道体会
需求里我把参数、公式、断言和失败路径都写死了。
码道第一版把模型和界面都搭出来了,自检也写了 10 条,但温度那条断言是假绿。
它找错了事件,看起来 PASS,实际没检查到降频。
这类错误自己跑一遍就能看见。
我做的事不是替它写循环,而是把验收条件写成可执行的断言:平均速度要在 105 到 110,覆盖率要是 12%,降频后速度要是 68.4。
条件写清楚,返工就少。
十、下一步
还缺三块:真实盘的 fio 曲线导入、垃圾回收后的再次掉速,以及 SLC 缓存随剩余空间变化的策略。
补上这三块,它会更接近一块真实 QLC 盘。
仓库地址在文章开头,拿去改。
附录:可复制的需求原文
下面是我在码道 Web 对话框里贴的原文,可以直接复制复现:
用单文件 index.html 做一个中文的「SSD 写入掉速实验室」,纯前端、无任何外部依赖和 CDN,用 Canvas 或 SVG 绘图,深色科技风,桌面 1600x1000 好看。
核心功能:模拟一块 1TB QLC SSD 的 SLC 缓存写入。控件包括:盘型(1TB QLC、1TB TLC、2TB TLC)、SLC 缓存大小(12GB、24GB、48GB)、写入文件大小(50GB、100GB、200GB、400GB)、环境温度(25、35、45 摄氏度)、开始/暂停/重置。
模型参数:SLC 缓存写入 2400MB/s;QLC 缓外直写 95MB/s;TLC 缓外直写 480MB/s;缓存写满后需要把数据折叠进 QLC/TLC,折叠期间前台写入速度按缓外速度计算;环境温度大于等于 40 摄氏度时,持续写入 60 秒后主控降频,速度再乘 0.72;45 摄氏度更早降频。200GB 文件、24GB 缓存、25 摄氏度时,最终平均速度应接近 105 到 110MB/s,总耗时约 30 到 32 分钟。
界面布局:左侧参数面板;中间上方是 SSD 颗粒地图,SLC 缓存区块逐格填充,写满后变成折叠中的 QLC 区块,用颜色区分;中间下方是实时速度曲线,横轴是已写入 GB,纵轴是 MB/s,标出缓存阶段、掉速拐点、热降频区间;右侧是指标卡,显示已写入、瞬时速度、平均速度、缓存命中率、已用时间、写入放大和温度。
还要有:一键「跑 200GB 对比」,同屏对比 12GB、24GB、48GB 缓存的三条速度曲线和平均速度;一个 10 条断言的自检面板,例如 200GB/24GB 缓存理论耗时、平均速度、缓存命中率 12%、缓外阶段速度、总写入量守恒,每条显示 PASS 或 FAIL 和实际值;非法输入(文件大于盘容量、缓存为 0)显示中文错误提示并拒绝开始。
交互要顺滑,数字用等宽字体,所有文案中文。完成后打开预览,让我直接看到运行效果。