From 27c91bcdc246c186a429d910e021bca16a0874b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B4=AE=E7=94=9F=EF=BC=88=E5=AD=90=E8=99=9A=EF=BC=89?= <2234839456@qq.com> Date: Sun, 26 Jul 2026 10:39:31 +0800 Subject: [PATCH] =?UTF-8?q?perf(observability):=20/api=20subset=20?= =?UTF-8?q?=E5=93=8D=E5=BA=94=E5=A4=B4=E5=8A=A0=20X-Timing-*=20=E5=88=86?= =?UTF-8?q?=E9=98=B6=E6=AE=B5=E8=80=97=E6=97=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 38ms 请求定位用:X-Timing-Find/Read/Subset/Total 分别对应 findFontPath、 readFontBuffer、fontSubset、总计。本地实测 60ms 中 58ms 在读字体文件、 裁剪仅 1ms,证伪「裁剪慢」假设。缓存命中只返回 X-Timing-Total。 Co-Authored-By: Claude Opus 5 (1M context) --- backend/routes/subset.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/backend/routes/subset.ts b/backend/routes/subset.ts index 28638fd..669b1cd 100644 --- a/backend/routes/subset.ts +++ b/backend/routes/subset.ts @@ -25,6 +25,8 @@ const SUBSET_CACHE_KEY = `${PACKAGE_VERSION}:${PROCESS_START_TIME}`; /** GET /api?font=...&text=... — 字体裁剪 */ export async function handleFontSubset(req: Request, res: Response) { + /** 入口时间戳,用于响应头 X-Timing-* 分阶段耗时排查 */ + const t0 = Date.now(); const url = parseUrl(req); const params = new URLSearchParams(url.search); const font = params.get("font") || ""; @@ -34,6 +36,8 @@ export async function handleFontSubset(req: Request, res: Response) { } const fontPath = await findFontPath(font); + /** findFontPath 结束时间戳(含可能的 readdir 遍历字体目录) */ + const t1 = Date.now(); if (!fontPath) { return { req, @@ -67,6 +71,8 @@ export async function handleFontSubset(req: Request, res: Response) { "Content-Type": contentTypes[outType] || "font/ttf", "Cache-Control": "public, max-age=86400", "X-Cache": "HIT", + /** 缓存命中时仅 findFontPath + cache.get 耗时(毫秒) */ + "X-Timing-Total": `${t1 - t0}`, }, }), }; @@ -85,11 +91,15 @@ export async function handleFontSubset(req: Request, res: Response) { }), }; } + /** readFontBuffer 结束时间戳(磁盘 IO / buffer 缓存命中) */ + const t2 = Date.now(); const newFont = await fontSubset(oldFontBuffer, text, { outType: outType, sourceType: fontType, }); + /** fontSubset 结束时间戳(实际裁剪,亚毫秒级应在此体现) */ + const t3 = Date.now(); /** 写入裁剪结果缓存 */ subsetCache.set(cacheKey, newFont as ArrayBuffer); @@ -104,6 +114,11 @@ export async function handleFontSubset(req: Request, res: Response) { "Content-Type": contentTypes[outType] || "font/ttf", "Cache-Control": "public, max-age=86400", "X-Cache": "MISS", + /** 分阶段耗时(毫秒),供排查服务端处理时间分布 */ + "X-Timing-Find": `${t1 - t0}`, + "X-Timing-Read": `${t2 - t1}`, + "X-Timing-Subset": `${t3 - t2}`, + "X-Timing-Total": `${t3 - t0}`, }, }), };