Sentry 性能监控 #
什么是性能监控? #
性能监控是 Sentry 的重要功能之一,帮助你了解应用的运行性能,发现性能瓶颈。
text
┌─────────────────────────────────────────────────────────────┐
│ 性能监控价值 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. 发现慢请求 │
│ - API 响应时间过长 │
│ - 页面加载缓慢 │
│ - 数据库查询耗时 │
│ │
│ 2. 定位性能瓶颈 │
│ - 哪个操作最耗时 │
│ - 外部服务调用影响 │
│ - 资源加载问题 │
│ │
│ 3. 分布式追踪 │
│ - 跨服务请求链路 │
│ - 微服务调用分析 │
│ - 端到端性能 │
│ │
└─────────────────────────────────────────────────────────────┘
核心概念 #
Transaction(事务) #
事务是性能监控的基本单位,代表一个完整的操作流程。
text
┌─────────────────────────────────────────────────────────────┐
│ Transaction 结构 │
├─────────────────────────────────────────────────────────────┤
│ │
│ Transaction: GET /api/users │
│ ├── Span: db.query (50ms) │
│ ├── Span: http.request (100ms) │
│ └── Span: cache.set (5ms) │
│ │
│ 总耗时: 155ms │
│ │
└─────────────────────────────────────────────────────────────┘
Span(跨度) #
Span 是事务中的具体操作,记录单个步骤的执行时间。
text
┌─────────────────────────────────────────────────────────────┐
│ Span 属性 │
├─────────────────────────────────────────────────────────────┤
│ │
│ op - 操作类型(如 db.query, http.request) │
│ description - 操作描述 │
│ start_timestamp - 开始时间 │
│ timestamp - 结束时间 │
│ data - 额外数据 │
│ status - 状态(ok, error, cancelled...) │
│ │
└─────────────────────────────────────────────────────────────┘
操作类型(Operation Types) #
| 操作类型 | 描述 |
|---|---|
http.server |
HTTP 服务端请求 |
http.client |
HTTP 客户端请求 |
db.query |
数据库查询 |
db.transaction |
数据库事务 |
cache |
缓存操作 |
queue |
队列操作 |
ui.render |
UI 渲染 |
ui.load |
UI 加载 |
启用性能监控 #
前端配置 #
javascript
import * as Sentry from "@sentry/react";
Sentry.init({
dsn: "https://xxxxxxxx@o123456.ingest.sentry.io/1234567",
integrations: [
Sentry.browserTracingIntegration(),
],
// 采样率(0.0 - 1.0)
tracesSampleRate: 0.1, // 10% 的事务会被上报
// 或者使用动态采样
tracesSampler: (samplingContext) => {
// 健康检查不追踪
if (samplingContext.name === "GET /health") {
return 0;
}
// 重要接口全量追踪
if (samplingContext.name.startsWith("POST /api/orders")) {
return 1.0;
}
// 其他接口 10% 采样
return 0.1;
},
});
后端配置 #
python
import sentry_sdk
sentry_sdk.init(
dsn="https://xxxxxxxx@o123456.ingest.sentry.io/1234567",
traces_sample_rate=0.1,
# 动态采样
traces_sampler=lambda sampling_context: (
0 if sampling_context["transaction_context"]["name"] == "GET /health"
else 0.1
),
)
javascript
// Node.js
const Sentry = require("@sentry/node");
Sentry.init({
dsn: "https://xxxxxxxx@o123456.ingest.sentry.io/1234567",
integrations: [
new Sentry.Integrations.Http({ tracing: true }),
],
tracesSampleRate: 0.1,
});
创建事务 #
自动事务 #
框架集成会自动创建事务:
javascript
// Express 自动追踪
const Sentry = require("@sentry/node");
Sentry.init({
dsn: "https://xxxxxxxx@o123456.ingest.sentry.io/1234567",
integrations: [
new Sentry.Integrations.Express({ app }),
],
tracesSampleRate: 0.1,
});
app.use(Sentry.Handlers.tracingHandler());
手动创建事务 #
javascript
// JavaScript
const transaction = Sentry.startTransaction({
name: "processOrder",
op: "task",
});
try {
// 执行操作
await processOrder(orderId);
transaction.setStatus("ok");
} catch (error) {
transaction.setStatus("internal_error");
throw error;
} finally {
transaction.finish();
}
python
# Python
import sentry_sdk
with sentry_sdk.start_transaction(
op="task",
name="process_order",
) as transaction:
process_order(order_id)
transaction.set_status("ok")
go
// Go
transaction := sentry.StartTransaction(
context.TODO(),
"processOrder",
sentry.OpName("task"),
)
defer transaction.Finish()
processOrder(orderId)
transaction.Status = sentry.SpanStatusOK
创建 Span #
手动创建 Span #
javascript
// JavaScript
const transaction = Sentry.startTransaction({
name: "checkout",
op: "task",
});
// 创建子 Span
const dbSpan = transaction.startChild({
op: "db.query",
description: "SELECT * FROM orders WHERE id = ?",
});
const order = await db.query("SELECT * FROM orders WHERE id = ?", [orderId]);
dbSpan.finish();
const paymentSpan = transaction.startChild({
op: "http.client",
description: "POST /api/payment",
});
const result = await fetch("/api/payment", { method: "POST" });
paymentSpan.finish();
transaction.finish();
python
# Python
import sentry_sdk
with sentry_sdk.start_transaction(op="task", name="checkout") as transaction:
with transaction.start_child(
op="db.query",
description="SELECT * FROM orders",
) as span:
order = db.query("SELECT * FROM orders WHERE id = %s", [order_id])
with transaction.start_child(
op="http.client",
description="POST /api/payment",
) as span:
result = requests.post("/api/payment")
使用装饰器(Python) #
python
import sentry_sdk
from functools import wraps
def traced(op, description=None):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
with sentry_sdk.start_span(op=op, description=description or func.__name__):
return func(*args, **kwargs)
return wrapper
return decorator
@traced(op="db.query", description="fetch_user")
def fetch_user(user_id):
return db.query("SELECT * FROM users WHERE id = %s", [user_id])
@traced(op="http.client")
def call_external_api(url):
return requests.get(url)
分布式追踪 #
追踪上下文传播 #
分布式追踪需要在服务之间传播追踪上下文:
text
┌─────────────────────────────────────────────────────────────┐
│ 分布式追踪流程 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 服务 A 服务 B 服务 C │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐
│ │ Trans A │─────────────>│ Trans B │─────────────>│ Trans C │
│ │ │ Headers: │ │ Headers: │ │
│ │ Span 1 │ sentry- │ Span 2 │ sentry- │ Span 3 │
│ │ │ trace │ │ trace │ │
│ └─────────┘ └─────────┘ └─────────┘
│ │
│ 同一个 Trace ID 贯穿整个请求链 │
│ │
└─────────────────────────────────────────────────────────────┘
HTTP 传播 #
javascript
// 发送请求时携带追踪头
import * as Sentry from "@sentry/node";
async function callExternalService(url) {
const span = Sentry.startInactiveSpan({
op: "http.client",
name: `GET ${url}`,
});
const headers = {};
// 添加追踪头
span?.toTraceTraceContext();
if (span) {
const traceContext = span.toTraceTraceContext();
headers["sentry-trace"] = traceContext["sentry-trace"];
headers["baggage"] = traceContext.baggage;
}
const response = await fetch(url, { headers });
span?.finish();
return response;
}
python
# Python - Flask
import sentry_sdk
import requests
from flask import request
@app.route("/api/proxy")
def proxy():
# 获取传入的追踪头
sentry_trace = request.headers.get("sentry-trace")
baggage = request.headers.get("baggage")
# 继续追踪
with sentry_sdk.continue_trace({
"sentry-trace": sentry_trace,
"baggage": baggage,
}):
# 调用外部服务
response = requests.get("https://external-api.com/data")
return response.json()
微服务追踪示例 #
text
┌─────────────────────────────────────────────────────────────┐
│ 电商下单追踪示例 │
├─────────────────────────────────────────────────────────────┤
│ │
│ Trace ID: abc123 │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Transaction: POST /api/orders │ │
│ │ Service: api-gateway │ │
│ │ Duration: 500ms │ │
│ │ │ │
│ │ ├── Span: auth.validate (10ms) │ │
│ │ ├── Span: http.client -> order-service (200ms) │ │
│ │ │ └── Transaction: create-order │ │
│ │ │ ├── Span: db.query (50ms) │ │
│ │ │ ├── Span: http.client -> inventory (100ms) │ │
│ │ │ │ └── Transaction: check-inventory │ │
│ │ │ │ └── Span: db.query (80ms) │ │
│ │ │ └── Span: http.client -> payment (40ms) │ │
│ │ │ └── Transaction: process-payment │ │
│ │ │ └── Span: http.client -> stripe │ │
│ │ └── Span: cache.update (5ms) │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
性能指标 #
Web Vitals(前端) #
Sentry 自动捕获以下 Web Vitals:
| 指标 | 名称 | 描述 |
|---|---|---|
| LCP | Largest Contentful Paint | 最大内容绘制时间 |
| FID | First Input Delay | 首次输入延迟 |
| CLS | Cumulative Layout Shift | 累积布局偏移 |
| FCP | First Contentful Paint | 首次内容绘制 |
| TTFB | Time to First Byte | 首字节时间 |
javascript
// 查看性能指标
Sentry.init({
dsn: "https://xxxxxxxx@o123456.ingest.sentry.io/1234567",
integrations: [
Sentry.browserTracingIntegration(),
],
tracesSampleRate: 0.1,
// 设置性能阈值
_experiments: {
recordLongTasks: true,
},
});
自定义指标 #
javascript
// 记录自定义指标
const transaction = Sentry.startTransaction({
name: "checkout",
op: "task",
});
// 添加指标数据
transaction.setMeasurement("order_value", 99.99, "currency");
transaction.setMeasurement("items_count", 5, "none");
transaction.setMeasurement("processing_time", 150, "millisecond");
transaction.finish();
python
# Python
import sentry_sdk
with sentry_sdk.start_transaction(op="task", name="checkout") as transaction:
transaction.set_measurement("order_value", 99.99, "currency")
transaction.set_measurement("items_count", 5, "none")
transaction.set_measurement("processing_time", 150, "millisecond")
性能分析 #
查看事务性能 #
在 Sentry 控制台中:
- 进入 Performance 页面
- 选择要分析的事务
- 查看事务详情:
- 响应时间分布
- Span 时间线
- 错误关联
- 用户影响
识别性能瓶颈 #
text
┌─────────────────────────────────────────────────────────────┐
│ 性能瓶颈分析 │
├─────────────────────────────────────────────────────────────┤
│ │
│ Transaction: GET /api/dashboard │
│ Total Duration: 2000ms │
│ │
│ Span Breakdown: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ db.query (1500ms) ████████████████████████ 75% │ │
│ │ http.client (400ms) ████████ 20% │ │
│ │ cache.get (50ms) ██ 2.5% │ │
│ │ other (50ms) ██ 2.5% │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 瓶颈: db.query 占用 75% 时间 │
│ │
└─────────────────────────────────────────────────────────────┘
性能告警 #
yaml
# 性能告警规则
rules:
- name: "Slow API Response"
conditions:
- type: transaction_duration
threshold: 1000 # 1秒
comparison: greater_than
actions:
- type: email
targets: ["dev-team@example.com"]
- type: slack
channel: "#performance-alerts"
性能优化建议 #
1. 数据库查询优化 #
python
import sentry_sdk
# 追踪数据库查询
with sentry_sdk.start_span(
op="db.query",
description="SELECT * FROM orders",
) as span:
span.set_data("db.system", "postgresql")
span.set_data("db.statement", "SELECT * FROM orders WHERE user_id = %s")
span.set_data("db.rows_affected", len(orders))
orders = db.query("SELECT * FROM orders WHERE user_id = %s", [user_id])
2. 缓存策略 #
python
import sentry_sdk
def get_user(user_id):
# 先查缓存
with sentry_sdk.start_span(op="cache.get", description=f"user:{user_id}") as span:
user = cache.get(f"user:{user_id}")
span.set_data("cache.hit", user is not None)
if user:
return user
# 缓存未命中,查数据库
with sentry_sdk.start_span(op="db.query", description="SELECT * FROM users"):
user = db.query("SELECT * FROM users WHERE id = %s", [user_id])
# 写入缓存
with sentry_sdk.start_span(op="cache.set", description=f"user:{user_id}"):
cache.set(f"user:{user_id}", user, ttl=3600)
return user
3. 并行处理 #
javascript
// 并行执行多个操作
const transaction = Sentry.startTransaction({
name: "loadDashboard",
op: "task",
});
// 并行加载数据
const [users, orders, stats] = await Promise.all([
(async () => {
const span = transaction.startChild({ op: "db.query", description: "fetch users" });
const result = await fetchUsers();
span.finish();
return result;
})(),
(async () => {
const span = transaction.startChild({ op: "db.query", description: "fetch orders" });
const result = await fetchOrders();
span.finish();
return result;
})(),
(async () => {
const span = transaction.startChild({ op: "db.query", description: "fetch stats" });
const result = await fetchStats();
span.finish();
return result;
})(),
]);
transaction.finish();
4. 懒加载 #
javascript
// 懒加载非关键数据
const transaction = Sentry.startTransaction({
name: "loadPage",
op: "pageload",
});
// 立即加载关键数据
const criticalData = await fetchCriticalData();
// 延迟加载非关键数据
setTimeout(async () => {
const span = transaction.startChild({ op: "lazy.load", description: "fetch recommendations" });
await fetchRecommendations();
span.finish();
}, 1000);
transaction.finish();
性能监控最佳实践 #
1. 合理设置采样率 #
javascript
Sentry.init({
// 生产环境使用较低采样率
tracesSampleRate: process.env.NODE_ENV === "production" ? 0.1 : 1.0,
// 或者根据事务类型动态采样
tracesSampler: (context) => {
// 关键事务全量追踪
if (context.name.includes("checkout") || context.name.includes("payment")) {
return 1.0;
}
// 健康检查不追踪
if (context.name.includes("health")) {
return 0;
}
// 其他事务 10% 采样
return 0.1;
},
});
2. 命名规范 #
javascript
// ✅ 好的命名
transaction.name = "GET /api/users/:id";
transaction.op = "http.server";
span.op = "db.query";
span.description = "SELECT * FROM users WHERE id = ?";
// ❌ 不好的命名
transaction.name = "GET /api/users/123"; // 包含动态 ID
span.description = "query"; // 太模糊
3. 添加有意义的上下文 #
javascript
const transaction = Sentry.startTransaction({
name: "processOrder",
op: "task",
});
// 添加业务上下文
transaction.setTag("order_type", "subscription");
transaction.setTag("payment_method", "credit_card");
transaction.setData("order_id", orderId);
transaction.setData("user_id", userId);
4. 正确处理错误 #
javascript
const transaction = Sentry.startTransaction({
name: "processOrder",
op: "task",
});
try {
await processOrder(orderId);
transaction.setStatus("ok");
} catch (error) {
// 记录错误状态
transaction.setStatus("internal_error");
// 关联错误到事务
Sentry.captureException(error);
throw error;
} finally {
transaction.finish();
}
下一步 #
现在你已经掌握了性能监控的知识,接下来学习 Release 追踪 了解如何追踪版本发布!
最后更新:2026-03-29