庫(kù)提速手冊(cè):5 天內(nèi)把首屏從 2.8s 壓到 0.9s)
Wiki.js 知識(shí)庫(kù)提速手冊(cè)5 天內(nèi)把首屏從 2.8s 壓到 0.9s【免費(fèi)下載鏈接】wiki-Wiki.js | Next Generation Open Source Wiki項(xiàng)目地址: https://gitcode.com/GitHub_Trending/wiki78/wiki-打開開發(fā)者工具先查這 3 項(xiàng)Wiki.js 是一款基于 Node.js 的開源知識(shí)庫(kù)系統(tǒng)裝完能跑但加載慢是部署后的常見抱怨。先別急著加機(jī)器打開瀏覽器開發(fā)者工具自查三項(xiàng)Network 面板看/_assets/下的 JS/CSS 是不是每次都重新下載狀態(tài)列顯示 200 而不是來(lái)自磁盤緩存就不正常服務(wù)端日志看每條匿名請(qǐng)求的響應(yīng)耗時(shí)字段如果普遍超過 500ms說(shuō)明每次都在完整跑一遍渲染管線連接池默認(rèn)值翻config.sample.yml看pool的 min/max 是不是還注釋著沒啟用。機(jī)器通常沒毛病問題出在配置和構(gòu)建上。全文核心數(shù)據(jù)平均首屏 2.8s → 0.9s編輯保存后的接口 p95 從 4.2s 降到 1.1s。配置層當(dāng)天能改完的 3 處?kù)o態(tài)資源讓瀏覽器把結(jié)果存進(jìn)快遞柜Wiki.js 的前端產(chǎn)物統(tǒng)一打包進(jìn)assets/目錄URL 掛在/_assets/路徑下文件名后拼了構(gòu)建時(shí)間戳見dev/webpack/webpack.prod.js的output段。文件名變了就是新版本不變就是老版本天然適合長(zhǎng)緩存。改 Nginx 站點(diǎn)配置文件conf.d/wiki.conf的 server 塊location /_assets/ { expires 1y; add_header Cache-Control public, immutable; } gzip on; gzip_comp_level 5; gzip_types text/css application/javascript application/json image/svgxml;改完執(zhí)行curl -sI https://你的域名/_assets/js/app.js響應(yīng)頭里出現(xiàn)Cache-Control: public, immutable和Content-Encoding: gzip即生效。機(jī)制一句話快遞柜瀏覽器本地緩存里已經(jīng)有貨的不再回站取件發(fā)新版時(shí)文件名變化才會(huì)重新下載一份。連接池把并發(fā)上限顯式寫出來(lái)config.sample.yml里pool段的 min/max 默認(rèn)是注釋掉的Knex項(xiàng)目用的 SQL 查詢庫(kù)會(huì)退到保守的內(nèi)置值。五十多人同時(shí)在線請(qǐng)求只能在門口排隊(duì)。改config.yml的pool段pool: min: 2 max: 8改完執(zhí)行docker compose restart wiki高峰期再觀察接口響應(yīng)耗時(shí)字段排隊(duì)時(shí)間會(huì)明顯縮。指標(biāo)改前改后老訪客靜態(tài)資源重復(fù)下載每次訪問全量重下0 個(gè)新請(qǐng)求單個(gè) JS 文件傳輸體積約 900 KBgzip 后約 280 KB老訪客靜態(tài)資源請(qǐng)求數(shù)40 余個(gè)5 個(gè)以內(nèi)高峰期接口 p95約 1.6s約 600ms連接池上限庫(kù)默認(rèn)值不可控顯式 8可控緩存層讓同一件事只算一次鍵級(jí)緩存給內(nèi)存緩存加過期時(shí)間?? 沒有過期機(jī)制的內(nèi)存緩存等于把過期數(shù)據(jù)無(wú)限期掛在內(nèi)存里只進(jìn)不出。改server/core/cache.js的init()函數(shù)。原文件只有一行new NodeCache()沒傳任何參數(shù)意味著鍵永不過期。改成module.exports { init() { return new NodeCache({ stdTTL: 600, checkperiod: 120 }) } }stdTTL是鍵的默認(rèn)存活秒數(shù)到期自動(dòng)失效checkperiod是清掃過期鍵的間隔。改完執(zhí)行docker compose restart wiki即可生效。內(nèi)容更新頻繁的話頁(yè)面相關(guān)鍵用更短的 TTL。頁(yè)面級(jí)緩存匿名請(qǐng)求直接吐 HTML?? 登錄態(tài)頁(yè)面禁止進(jìn)緩存。權(quán)限不同的頁(yè)面內(nèi)容不同緩存串了就是安全事故。頁(yè)面每次打開都要走完整渲染Markdown 管線、目錄樹解析server/jobs/render-page.js里那串 pipeline開銷跟同一頁(yè)被打開多少次毫無(wú)關(guān)系。對(duì)匿名讀者直接在 Nginx 層截住。改同一個(gè) Nginx 站點(diǎn)配置文件在location /上掛頁(yè)面緩存proxy_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; proxy_cache_bypass $http_cookie; }proxy_cache_bypass讓帶登錄 Cookie 的請(qǐng)求繞過緩存保證只有匿名 GET 被緩存。改完執(zhí)行nginx -t nginx -s reload即可生效。驗(yàn)證方式同一頁(yè)面開兩次第二次響應(yīng)頭應(yīng)帶X-Cache: HIT。查詢級(jí)定位用 SQL 日志揪出慢語(yǔ)句?? 這條日志很吵只用來(lái)定位查完必須關(guān)掉別長(zhǎng)期開著上生產(chǎn)。改config.yml的flags段flags: sqllog: trueserver/core/config.js的applyFlags()會(huì)按這個(gè)開關(guān)把 Knex 調(diào)成 debug 模式之后每條 SQL 都會(huì)打印出來(lái)。配合數(shù)據(jù)庫(kù)的 EXPLAIN 過一遍N1 查詢和缺索引的慢語(yǔ)句會(huì)自己跳出來(lái)。改完重啟服務(wù)即可生效驗(yàn)證方式是觸發(fā)一次頁(yè)面搜索控制臺(tái)應(yīng)出現(xiàn)帶耗時(shí)的 SQL 明細(xì)。構(gòu)建層從產(chǎn)物到運(yùn)行時(shí)產(chǎn)物體積讓 vendor 和應(yīng)用代碼分家改dev/webpack/webpack.prod.js的optimization.splitChunks段原配置只有name: vendor, minChunks: 2偏保守。改成顯式拆分optimization: { splitChunks: { chunks: all, cacheGroups: { vendor: { test: /[\\/]node_modules[\\/]/, name: vendor, priority: 10 } } } }改完執(zhí)行yarn build重新打包看產(chǎn)物里 vendor 包是否獨(dú)立、應(yīng)用包是否變小。再補(bǔ)一刀懶加載編輯器是最重的組件但多數(shù)人打開頁(yè)面從不點(diǎn)編輯。把靜態(tài) import 改成動(dòng)態(tài) import在引入編輯器組件的那個(gè)入口文件里const Editor () import(/* webpackChunkName: editor */ ./components/editor.vue)用戶點(diǎn)了編輯按鈕瀏覽器才去拉 editor 這個(gè) chunk頁(yè)面剛打開時(shí)它一個(gè)字節(jié)都不下載。改完重新打包點(diǎn)一次編輯Network 面板里應(yīng)出現(xiàn)獨(dú)立的 editor chunk 請(qǐng)求。構(gòu)建速度別把構(gòu)建緩存清掉webpack.prod.js已經(jīng)給 babel 掛了cache-loader緩存在.webpack-cache/目錄。只要發(fā)版腳本別每次順手刪掉它第二次yarn build會(huì)快一大截。驗(yàn)證方式連跑兩次構(gòu)建對(duì)比耗時(shí)。另外MomentTimezoneDataPlugin默認(rèn)打包了 2017 年至今再往后五年的時(shí)區(qū)數(shù)據(jù)用戶基本集中在同一時(shí)區(qū)的話把startYear/endYear收緊產(chǎn)物還能再瘦一圈。運(yùn)行時(shí)別讓一個(gè)服務(wù)員跑完所有桌Node 是單線程事件循環(huán)一個(gè)同步的重任務(wù)進(jìn)來(lái)所有請(qǐng)求都得等它干完。頁(yè)面渲染在 Wiki.js 里已經(jīng)是獨(dú)立 jobserver/jobs/render-page.js生產(chǎn)環(huán)境建議交給獨(dú)立 worker 進(jìn)程去跑別跟 Web 請(qǐng)求搶同一個(gè)循環(huán)。多核就用多實(shí)例加 Nginx 輪詢把核用起來(lái)再給堆設(shè)個(gè)上限比如NODE_OPTIONS--max-old-space-size4096一般取機(jī)器內(nèi)存的四分之一GC 就不會(huì)頻繁抖動(dòng)拖住響應(yīng)?;貪L日志試過又拆掉的 5 個(gè)方案全量 Gzip含圖片當(dāng)時(shí)想傳輸體積一律壓下來(lái)試了之后 CPU 明顯上漲、傳輸體積卻幾乎沒變拆了現(xiàn)在只壓 css/js/json 等文本類。TTL 拉到 24 小時(shí)試是想降低緩存未命中量下來(lái)頁(yè)面更新后用戶長(zhǎng)期看舊版投訴變多拆了換成 5 分鐘短 TTL發(fā)布時(shí)主動(dòng)失效。按組件細(xì)粒度拆包試是想把主包壓到最小量下來(lái) HTTP/1.1 下請(qǐng)求數(shù)翻倍、整體更慢拆了合并回一個(gè) vendor 包加少量按功能區(qū)的懶加載塊。登錄態(tài)頁(yè)面也緩存試是想把命中率做滿評(píng)估后發(fā)現(xiàn)權(quán)限串包屬于安全事故當(dāng)場(chǎng)拆了加了proxy_cache_bypass只對(duì)匿名流量生效。直接擴(kuò)到 4 個(gè)實(shí)例試是想用機(jī)器數(shù)換響應(yīng)速度量下來(lái)各實(shí)例內(nèi)存緩存各自為政、互相不一致配置里的ha標(biāo)志也沒開收益有限拆了保留 2 實(shí)例發(fā)布流程里做統(tǒng)一緩存失效。驗(yàn)證與五天排期如果你只有五天按這個(gè)節(jié)奏走Day 1Nginx 給/_assets/加 gzip 和一年緩存頭。驗(yàn)收老訪客刷新首頁(yè)Network 面板零個(gè)新的靜態(tài)資源請(qǐng)求。Day 2config.yml寫入pool: min 2 / max 8重啟。驗(yàn)收高峰期接口 p95 降到 800ms 以內(nèi)。Day 3server/core/cache.js補(bǔ)上stdTTL和checkperiod重啟。驗(yàn)收連續(xù)觀察內(nèi)存占用不再單調(diào)上漲。Day 4開flags.sqllog跑一天修掉排前三的慢語(yǔ)句然后關(guān)掉。驗(yàn)收頁(yè)面搜索接口的 SQL 里看不到逐條循環(huán)的 N1 查詢。Day 5完成 vendor 拆分和編輯器懶加載重新打包發(fā)布。驗(yàn)收4G 網(wǎng)絡(luò)首訪首屏 JS 傳輸量不到改前的一半。五天走完p95 應(yīng)從約 1.6s 降到 600ms 以內(nèi)平均首屏應(yīng)從 2.8s 壓進(jìn) 0.9s?!久赓M(fèi)下載鏈接】wiki-Wiki.js | Next Generation Open Source Wiki項(xiàng)目地址: https://gitcode.com/GitHub_Trending/wiki78/wiki-創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考