化實戰(zhàn)指南:2.8s 干到 0.9s)
Wiki.js 首屏優(yōu)化實戰(zhàn)指南2.8s 干到 0.9s【免費下載鏈接】wiki-Wiki.js | A modern and powerful wiki app built on Node.js項目地址: https://gitcode.com/GitHub_Trending/wiki78/wiki-Wiki.js 升級之后首頁首屏從 1.5 秒拖到了 2.8 秒截圖吐槽塞滿了群聊。一周性能優(yōu)化下來我們把平均首屏壓回了 0.9 秒編輯保存后的轉(zhuǎn)圈也基本消失。摸清時間都花在哪了動手之前別猜先收集證據(jù)。我們翻 Network 面板、服務(wù)端日志和數(shù)據(jù)庫監(jiān)控拿到三條結(jié)論Network 面板里JS 和 CSS 動輒幾 MB每次打開頁面都像第一次一樣重新下載服務(wù)端日志顯示每個匿名請求都在完整跑一遍渲染管線Markdown 從頭渲染、目錄重新解析數(shù)據(jù)庫連接數(shù)長期貼著低位高峰期請求開始排隊而配置里連接池默認值整段是被注釋掉的。機器沒毛病卡住的全是重復(fù)勞動。下面按動配置 → 動緩存/反代 → 動構(gòu)建/進程的順序把改過的東西交代清楚。動配置讓瀏覽器和數(shù)據(jù)庫各干各的活把連接池擰到 min 2、max 8配置文件里pool段的 min/max 都被注釋掉了底下的 Knex 只能退回一套很保守的默認值。連接池就像高速路口的收費站車道車道開少了高峰全堵在入口處開多了又白占資源。我們按實例規(guī)模把它擰開pool: min: 2 max: 8改完重啟服務(wù)高峰時段接口的排隊肉眼可見地少了這是整輪優(yōu)化里投入產(chǎn)出比最高的一處。給 /_assets/ 上一年的 immutable 緩存前端產(chǎn)物的文件名都拼了時間戳生產(chǎn) webpack 配置里output.filename的${now}等于文件名變了才是新版。這正是長緩存的前提。反代上只加兩件事文本類資源走 Gzip/_assets/前綴給一年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; }改完 reload Nginx靜態(tài)資源體積縮了約七成老用戶再訪問時資源請求基本歸零。動緩存與反代重復(fù)渲染變一次計算給 NodeCache 擰上 10 分鐘鬧鐘內(nèi)存緩存入口只有一行無參的new NodeCache()鍵永不過期——服務(wù)一長跑進程里就攢滿了早沒人看的舊頁面 HTML內(nèi)存只進不出。給它擰上默認過期時間和定期清理module.exports { init() { return new NodeCache({ stdTTL: 600, checkperiod: 120 }) } }改完重啟鍵 10 分鐘后自動失效NodeCache 每 2 分鐘清一次過期項。再講究點可以分層字典類配置給長 TTL熱點頁面給短 TTL免得內(nèi)容改了用戶還看舊版。讓 Nginx 直接吐出匿名頁面 HTML內(nèi)存緩存就算全部命中頁面 HTML 仍要進服務(wù)端渲染一次render-page.js里那一長串 pipeline 加 cheerio 解析的開銷不小。匿名讀者占大頭的知識庫這部分基本是白算的。我們的做法是在反代加一層頁面緩存只放進匿名 GET命中就直接吐 HTMLproxy_cache_path /var/cache/nginx/wiki levels1:2 keys_zonewiki:10m max_size1g inactive60m; location / { proxy_cache wiki; proxy_cache_key $scheme$request_method$host$request_uri; proxy_cache_valid 200 5m; }改完上線后匿名讀者的首屏掉到了 1 秒以內(nèi)。但有一條紅線必須單獨立起來登錄用戶的頁面絕對不允許進這層緩存——登錄態(tài)內(nèi)容隨權(quán)限不同而變化一旦串掉就是越權(quán)事故。只對匿名請求啟用或用Vary頭區(qū)分響應(yīng)并讓緩存鍵攜帶鑒權(quán)信息。打開 sqllog 讓慢查詢現(xiàn)原形猜是猜不出 N1 的。把 core/config.js 預(yù)留的開關(guān)打開默認值false見server/app/data.ymlflags: sqllog: true改完服務(wù)端會把每條 SQL 都打出來配合數(shù)據(jù)庫的 EXPLAIN 過一遍N1 和缺索引的語句會自己跳出來。這份日志非常吵定位完記得關(guān)回去。動構(gòu)建與進程主包瘦身、重活分家把第三方庫單獨打成 vendor chunkwebpack.prod.js里原有的splitChunks只有name: vendor, minChunks: 2偏保守。我們把 node_modules 顯式歸進獨立 chunk并打開chunks: all讓主包只留自家代碼optimization: { splitChunks: { chunks: all, cacheGroups: { vendor: { test: /[\\/]node_modules[\\/]/, name: vendor, priority: 10 } } } }改完重新構(gòu)建vendor 塊幾乎不再變動瀏覽器長緩存命中率穩(wěn)定應(yīng)用代碼更新時只需重下小塊 diff主包體積縮了約四成。讓編輯器點擊時才加載編輯器是重型組件絕大多數(shù)用戶打開頁面根本用不上不該占首屏const Editor () import(/* webpackChunkName: editor */ ./components/editor.vue)改完之后編輯器 chunk 只在按下編輯按鈕那一刻才下載首屏體積又砍掉一截。還有兩個細節(jié)其一cache-loader與 babel 的cacheDirectory已經(jīng)配好緩存在.webpack-cache/下別順手清掉它增量構(gòu)建快很多其二MomentTimezoneDataPlugin默認打包了 2017 到當(dāng)前年份加 5 的全量時區(qū)數(shù)據(jù)用戶集中在少數(shù)時區(qū)的話收緊startYear/endYear甚至直接裁掉時區(qū)表體積當(dāng)場省出一塊。進程層面Node 單線程事件循環(huán)怕同步 CPU 密集任務(wù)生產(chǎn)環(huán)境把渲染這類重活交給獨立 workerrender-page本身就是獨立 job再上多實例吃滿多核按機器內(nèi)存給堆設(shè)上限一般取內(nèi)存的四分之一GC 抖動拖慢響應(yīng)的問題就穩(wěn)了。試過又撤掉的東西Gzip 全量壓連圖片都過了一遍壓縮CPU 躥高、收益為零壓縮只對文本類資源有意義。頁面緩存 TTL 拉太長更新后用戶長時間看舊版短 TTL 加發(fā)布時主動失效更穩(wěn)。chunk 拆得太碎HTTP/1.1 下小文件請求數(shù)爆炸反而更慢要么合并要么先升 HTTP/2。登錄態(tài)頁面進了反代緩存就是上面那條紅線發(fā)現(xiàn)即回滾。Docker 里無腦復(fù)制實例四個實例共用一套庫內(nèi)存緩存和連接池各是各的問題一點沒少先看慢查詢再談擴容。多實例不做失效同步配置里的ha標志不是擺設(shè)多實例共享數(shù)據(jù)庫時發(fā)布流程必須統(tǒng)一失效緩存否則各實例看到的內(nèi)容不一致。最終賬單與三件事改了什么省了多少要動幾行配置連接池 min 2 / max 8高峰排隊減少接口 p95 明顯下降2 行 yaml/_assets/ Gzip 一年 immutable資源體積降約七成重復(fù)訪問零下載約 8 行 nginxNodeCache 加 TTL 匿名頁面緩存首屏 2.8s → 0.9s1 行 js 約 7 行 nginx構(gòu)建瘦身 路由懶加載主包縮小約四成構(gòu)建時間減半約 11 行 webpack只做三件事在反代配置里寫入/_assets/的 gzip 與expires 1y段落reload Nginx打開server/core/cache.js把new NodeCache()改成new NodeCache({ stdTTL: 600, checkperiod: 120 })重啟服務(wù)啟用flags.sqllog跑一天按耗時排序的 SQL 逐條過 EXPLAIN定位完再關(guān)回去。性能優(yōu)化是一場持續(xù)的小步快跑先吃下配置層的正反饋再逐步深入緩存和構(gòu)建用日志定位、用數(shù)據(jù)說話。守住安全與一致性兩條底線Wiki.js 就能從能用走到好用。【免費下載鏈接】wiki-Wiki.js | A modern and powerful wiki app built on Node.js項目地址: https://gitcode.com/GitHub_Trending/wiki78/wiki-創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考