程式碼執行效能分析
對請求的每個階段進行計時可以用證據代替直覺。一旦持續時間是結構化事件,您就可以比較執行、發布和輸入大小類別的功能。
持續時間設定檔案會告訴您哪個功能值得首先最佳化。
設定專案
npm init -y
npm install telemetry-sh
儀器每個已完成的步驟
每個步驟使用一個事件,以便相同的列跨工作流程工作。 run_id 連線屬於一個請求或作業的步驟。
const telemetry = require("telemetry-sh");
const { randomUUID } = require("node:crypto");
telemetry.init(process.env.TELEMETRY_API_KEY);
async function measureStep({ runId, stepName }, operation) {
const startedAt = Date.now();
try {
const result = await operation();
await telemetry.log("profile_step_completed", {
run_id: runId,
step_name: stepName,
status: "success",
duration_ms: Date.now() - startedAt,
release: process.env.APP_RELEASE ?? "unknown",
});
return result;
} catch (error) {
await telemetry.log("profile_step_completed", {
run_id: runId,
step_name: stepName,
status: "error",
duration_ms: Date.now() - startedAt,
error_type: error.constructor?.name ?? "Error",
release: process.env.APP_RELEASE ?? "unknown",
});
throw error;
}
}
async function profileRequest() {
const runId = randomUUID();
const project = await measureStep(
{ runId, stepName: "load_project" },
() => loadProject()
);
return measureStep(
{ runId, stepName: "generate_report" },
() => generateReport(project)
);
}
預設情況下避免記錄函式參數、資料庫記錄或異常訊息。 input_size_bucket、cache_status 或 query_name 等安全類別可以在不儲存原始內容的情況下解釋效能。
查詢平均和尾部持續時間
SELECT
step_name,
COUNT(*) AS runs,
ROUND(AVG(duration_ms), 0) AS avg_duration_ms,
ROUND(approx_percentile_cont(duration_ms, 0.95), 0) AS p95_duration_ms,
ROUND(
100.0 * SUM(CASE WHEN status = 'error' THEN 1 ELSE 0 END)
/ NULLIF(COUNT(*), 0),
2
) AS error_rate_pct
FROM profile_step_completed
WHERE timestamp_utc >= now() - INTERVAL '7 days'
GROUP BY step_name
ORDER BY p95_duration_ms DESC;
使用 p95 而不是僅使用平均值,這樣間歇性的緩慢步驟仍然可見。部署後按 release 進行拆分,並在多個慢速步驟屬於同一請求時檢查各個 run_id 值。
建置績效檢視
從以下開始:
- p95 持續時間的條形圖(按步驟);
- p95 隨著時間變化的折線圖,顯示最慢的步驟;
- 按版本劃分的結果資料表;
- 過濾為錯誤或極端持續時間行的最近事件資料表。
在有用的邊界處進行輪廓分析。不要為熱迴圈中的每個小函式發出事件;這會增加開銷併產生難以解釋的資料集。
後續步驟
當測量的工作流程是 API 請求時,使用 API 延遲百分位數配方 進行完整的結果視覺化、儀表板佈局和警示設計。