给自用博客做一份性能账本

给自用博客做性能优化,我想先回答一个具体问题:读者打开一篇文章时,服务端究竟要去云数据库取几次数据?先弄清楚这条路,通常比直接更换框架更容易得到可解释的结果。
本篇记录的是这版博客实际完成的一次改动。测试环境为本机 Vinext 开发预览与远程 MySQL,结果用于比较同一条链路的前后变化,不等同于线上生产环境的用户体验评分。
把比较条件固定下来
优化前后都使用同一批 14 条示例内容。每个地址先预热一次,再顺序采样七次,记录中位数和本次采样的第 95 百分位。七次样本很少,因此这里的尾延迟只用来观察这组请求,不能据此宣称稳定的容量上限。
| 地址 | 改动前中位数 | 优化后中位数 |
|---|---|---|
| 内容 API | 353ms | 84ms |
| 首页 | 623ms | 170ms |
| 文章列表 | 609ms | 150ms |
| 文章详情 | 631ms | 166ms |
| 手记详情 | 628ms | 182ms |
这些数字来自逐次采样记录。记录同时保留了中间版本,部分采样会有波动,因此不把单次最低值当作最终结论。后来换成原创内容和新图片的数据版本,需要另做一组测试;不能把不同数据集的结果混在一起,声称所有改善都来自同一处代码修改。
减少读取往返
原来的页面通过几个独立函数分别获取设置、文章和资源。这些函数各自检查初始化状态,还会读取文章附加信息。生成页面元数据时,也需要同样的公共内容。
改动后的读取器把公共设置、已发布文章和资源放进同一个批次,再把附加信息组织成按文章编号查询的 Map。正常情况下,公共快照只需要一次网关批处理。数据库尚未初始化时,才进入初始化与重读流程。公共内容 API 也移除了重复的初始化读取;公开媒体字节直接从对象存储获取,不再为每张图片额外查询云库。
const [settingsRows, entryRows, resourceRows] = await db.batch([
publicSettingsQuery,
publishedEntriesQuery,
orderedResourcesQuery,
])
这是结构示意,真实实现保留了未初始化检查、私密内容过滤与数据库错误处理。少一次网络往返,是一次可以直接观察的收益;少一次错误检查,却可能只是把问题藏起来。
缓存要有清楚的寿命
页面和元数据共享公共读取时,使用的是 React 的请求内缓存。没有增加一个跨请求长期保留正文的全局缓存,因此下一次请求仍然可以看到刚保存的修改或数据库切换结果。
为了检查这一点,回归用例会连续读取两个不同版本的正文,并验证私密条目与所有者信息不会出现在公共快照中。只测“变快了”,却不测“还能看到新内容”,不是一个完整的优化验收。
图片也要进入预算
这一版先保留原始生成图,再构建适合网页的 WebP 派生文件。横版图片提供多个宽度,头像也有独立尺寸。页面需要记录图片的宽高,并按实际显示区域选取资源,避免一开始就下载整张原图。
图片文件变小之后,仍要检查角色细节是否可读、封面有没有错误裁切,以及弱网下页面结构是否稳定。压缩数字与阅读体验,是两份需要一起看的证据。
为下一次修改留下基线
每份性能记录都保存数据条数、正文总字符数、测试环境、原始采样和响应体大小。响应体的离线 gzip 估算也会明确标注,它不是浏览器实际网络传输量。
这次改动没有回答所有性能问题。它给项目留下了一条可重复的路径:找到重复工作,固定比较条件,修改实现,再用相同场景验证正确性与耗时。下一次内容增长时,可以沿着这条路重新测量。
给自用博客做一份性能账本 · LovelyCat · 2026-10-21
个人学习与创作札记 · 设计参考 Yohaku