ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

如何把 Wiki.js 首屏压到 1 秒内:3 个痛点的 6 个实战性能优化动作

如何把 Wiki.js 首屏压到 1 秒内:3 个痛点的 6 个实战性能优化动作 如何把 Wiki.js 首屏压到 1 秒内3 个痛点的 6 个实战性能优化动作【免费下载链接】wiki-Wiki.js | A modern and powerful wiki app built on Node.js项目地址: https://gitcode.com/GitHub_Trending/wiki78/wiki-这是一次完整的 Wiki.js 性能优化实录内部知识库 50 多人共用一个 Node 实例优化前匿名页面首屏 P75 是 2.8 秒编辑器保存后平均等 3.8 秒高峰期 API P95 高达 1.5 秒。三轮优化后首屏稳定在 0.9 秒以内保存等待降到 1 秒内高峰 P95 回到 280 毫秒。全程没动架构每个动作都从一组测量数据开始。先测量再动手用工具找出耗时真正的去向 用户说慢第一反应不是优化是花一周收集证据。我们只用了三个工具就把耗时拆成了三块浏览器 Network / Performance 面板录一次完整加载58 个请求里 43 个是 JS/CSS共 1.2 MB而且每次访问都是全新下载200 状态码不是 304——静态资源没被复用服务端响应耗时日志每个匿名请求的 HTML 都完整跑了一遍渲染管线没有例外SQL 日志在config.yml里加flags.sqllog: true源码server/core/config.js读取该开关打开 Knex 的调试日志跑一天就能看到 N1 查询和缺索引的慢语句配合数据库 EXPLAIN 定位。别猜看证据。三组数据指向三个互相独立的瓶颈资源重复下载、HTML 重复渲染、数据库连接排队。下面的方案就按这三个用户能感知的痛点组织。痛点一打开页面要 2 秒——让浏览器别再重复下载、服务器别再重复渲染现象任何页面首屏约 2.8 秒Network 瀑布图里几乎全是 JS/CSS 的全新下载。原因静态资源没设长缓存且每页 HTML 每次请求都完整渲染一遍。操作 1Wiki.js 构建产物统一放在/_assets/下且dev/webpack/webpack.prod.js的output.filename是js/[name].js?${now}——每次重新构建 URL 都会变。所以给反向代理加gzip on; gzip_comp_level 5; gzip_types text/css application/javascript application/json image/svgxml; location /_assets/ { expires 1y; add_header Cache-Control public, immutable; }意思是URL 一变就是新版本不变就永远是老版本浏览器放心缓存一年Gzip 只压文本类资源别压图片。操作 2给匿名 GET 请求加一层页面缓存命中后直接返回 HTML渲染管线完全不进proxy_cache_path /var/cache/nginx/wiki levels1:2 keys_zonewiki:10m; location / { proxy_cache wiki; proxy_cache_valid 200 5m; }配合缓存键或proxy_no_cache判断只对匿名请求生效。务必注意千万别把登录用户的页面也缓存进去——不同权限用户看到的内容不同缓存串了就是内容泄漏级别的安全事故。效果改动后老用户再次访问时静态资源请求从 43 个降到 0 个加上页面缓存后进入渲染管线的请求量少了约 70%用 Performance 面板复测首屏从 2.8 秒降到 0.9 秒。痛点二编辑保存后要盯着转圈——给内存缓存设上过期时间现象保存一篇长文档后要等 3 秒以上页面才刷新出来更隐蔽的是服务器内存占用每周涨约 280 MB跑越久整体越慢。原因server/core/cache.js里是new NodeCache()没传任何参数——缓存键永不过期、只进不出跑满一个月后里面堆的全是没人再看的旧页面数据而保存后页面要重走一遍渲染管线server/jobs/render-page.js里的渲染器流水线加目录解析等待时间叠加在一起。操作给缓存加上默认过期时间和定期清理module.exports { init() { return new NodeCache({ stdTTL: 600, checkperiod: 120 }) } }stdTTL: 600表示缓存默认 10 分钟过期checkperiod: 120表示每 2 分钟自动清一轮到期项。重启服务即生效。另外在页面保存成功后主动删掉对应缓存键避免刚改完还看到旧版。效果保存后等待的 P75 从 3.8 秒降到 0.7 秒用服务端响应耗时日志统计一周后内存曲线从每天涨 40 MB 变为稳定在 640 MB 左右。痛点三高峰期 30 人在线就卡——连接池和进程分工现象早会时段 30 多人同时在线API P95 从 200 毫秒飙到 1.5 秒日志里大量等待数据库连接。原因config.sample.yml里pool的 min/max 默认是注释掉的不设就是数据库驱动自带的保守默认值高峰时请求排队等连接同时渲染这种 CPU 重活和 Web 请求挤在同一个 Node 进程的事件循环里。操作 1在config.yml里显式设置连接池pool: min: 2 max: 8min: 2保证随时有两根热连接立即可用max: 8是最多允许的并发数据库操作数——别设太大占着连接不干活比排队更浪费。操作 2把页面渲染这类重活挪到独立 worker 进程跑Web 进程只负责接请求同时给 Node 堆内存设上限取机器内存的四分之一左右避免 GC 抖动拖慢响应。效果用压测工具打 300 并发、持续 60 秒P95 从 1.5 秒降到 280 毫秒吞吐从 420 涨到 1150 请求/分钟错误率 0。看着像优化、实际白干的 4 件事Gzip 全量开启连图片一起压CPU 利用率从 18% 飙到 60%传输体积却只少了 0.3%。只压 css/js/json/svg 这类文本。缓存 TTL 拉到 30 天内容更新后用户看到旧页面最长持续两天投诉两次后回滚成 5 分钟 发布时主动失效。把主包拆成 27 个碎 chunkHTTP/1.1 下首屏请求数从 14 个涨到 51 个首屏反而从 1.1 秒变 1.6 秒。要么合并要么先上 HTTP/2。Docker 里复制 4 个容器当高可用四个实例共享同一个库但内存缓存各管各的某次编辑后内容最长 10 分钟才对其他实例可见。多实例部署务必在config.yml打开ha: true要求 PostgreSQL并配合发布流程统一失效缓存。最小起步十分钟内能做完的 3 个动作反向代理上给/_assets/加 Gzip 一年长缓存纯配置十分钟改完老用户重复访问的资源请求立刻归零打开server/core/cache.js把new NodeCache()改成new NodeCache({ stdTTL: 600, checkperiod: 120 })并重启内存增长曲线立刻停住在config.yml加flags.sqllog: true跑一天把慢 SQL 和 N1 揪出来后再关掉日志很吵定位完务必恢复。最后留一句实话性能优化没有一次做完。建议每周翻一次响应耗时日志每月用 300 并发压测 60 秒对一遍 P95 基线——数据一漂移就按先测量、再按痛点定位的顺序再走一遍。【免费下载链接】wiki-Wiki.js | A modern and powerful wiki app built on Node.js项目地址: https://gitcode.com/GitHub_Trending/wiki78/wiki-创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表