16 KiB
16 KiB
Light-Sentry 日志分析系统设计文档
1. 项目概述
1.1 背景
基于用户需求,需要构建一个日志分析系统,支持接收 Sentry 前后端 SDK 的上报,并在 2核2G ECS + 阿里云OSS 的资源限制下稳定运行。
1.2 核心目标
- 兼容性:完全兼容 Sentry SDK 的上报协议(DSN、事件格式)
- 轻量级:适配 2核2G 服务器资源
- 低成本:利用阿里云 OSS 进行冷存储,降低成本
- 可视化:提供友好的日志查询和可视化界面
2. 系统架构
2.1 整体架构图
┌─────────────────────────────────────────────────────────────────────┐
│ 客户端 SDK 层 │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Browser SDK │ │ Node SDK │ │ Python SDK │ │
│ │ @sentry/browser │ @sentry/node │ @sentry/python │ │
│ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │
│ │ │ │ │
│ └─────────────────┼─────────────────┘ │
│ ▼ │
│ ┌───────────────────────┐ │
│ │ Sentry API 网关 │ │
│ │ /api/{project}/store │ │
│ └───────────┬───────────┘ │
└───────────────────────────┼─────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ 服务端处理层 │
│ ┌──────────────────┐ ┌──────────────────┐ │
│ │ 事件处理器 │──▶│ 事件转换器 │ │
│ │ (Event Handler)│ │ (Event Converter)│ │
│ └──────────────────┘ └──────────┬───────┘ │
│ │ │
│ ┌───────────────────────┼───────────────────────┐ │
│ ▼ ▼ ▼ │
│ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ │
│ │ Loki 索引 │ │ Loki 存储 │ │ OSS 持久化 │ │
│ │ (索引元数据) │ │ (近期日志) │ │ (历史归档) │ │
│ └───────────────┘ └───────────────┘ └───────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ 可视化查询层 │
│ ┌───────────────┐ │
│ │ Grafana │ │
│ │ (查询/图表) │ │
│ └───────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
2.2 核心组件说明
| 组件 | 技术选型 | 角色 | 资源占用 |
|---|---|---|---|
| API网关 | Express/FastAPI | 接收Sentry协议上报 | ~100MB |
| 日志存储 | Loki | 索引和近期日志存储 | ~500MB |
| 持久化层 | 阿里云OSS | 历史日志归档 | 按需扩展 |
| 可视化 | Grafana | 日志查询和图表展示 | ~300MB |
总内存预估:~1GB(保留1GB给系统和缓冲)
3. 技术方案
3.1 Sentry 协议兼容层
3.1.1 协议说明
Sentry SDK 使用 DSN (Data Source Name) 配置上报地址:
{PROTOCOL}://{PUBLIC_KEY}@{HOST}/{PATH}/{PROJECT_ID}
SDK 向 /api/{PROJECT_ID}/store/ 端点发送 POST 请求,数据格式为 JSON。
3.1.2 事件数据结构(简化版)
{
"event_id": "abc123...",
"timestamp": "2024-01-01T00:00:00Z",
"level": "error",
"logger": "javascript",
"platform": "javascript",
"message": "Uncaught TypeError: Cannot read property",
"exception": {
"values": [{
"type": "TypeError",
"value": "Cannot read property 'x' of undefined",
"stacktrace": {
"frames": [{
"filename": "app.js",
"lineno": 42,
"function": "doSomething"
}]
}
}]
},
"tags": {
"environment": "production",
"release": "v1.0.0"
},
"contexts": {
"request": {
"url": "https://example.com/page",
"method": "GET"
},
"user": {
"id": "12345",
"email": "user@example.com"
}
}
}
3.1.3 API 网关设计
技术选型:Node.js + Express(轻量级,内存占用低)
核心端点:
| 端点 | 方法 | 功能 |
|---|---|---|
/api/:projectId/store/ |
POST | 接收 Sentry SDK 上报事件 |
/health |
GET | 健康检查 |
设计要点:
- 支持 Sentry 的 DSN 认证(通过
X-Sentry-Auth头或查询参数) - 异步处理,不阻塞请求响应
- 事件格式校验和标准化
- 支持批量上报
3.2 日志存储方案
3.2.1 Loki 配置
为什么选择 Loki:
- 轻量级,内存占用远低于 ELK(Elasticsearch 需要至少 4GB)
- 基于标签索引,查询效率高
- 与 Grafana 无缝集成
- 支持 OSS 作为后端存储
关键配置:
auth_enabled: false
server:
http_listen_port: 3100
ingester:
lifecycler:
address: 127.0.0.1
ring:
kvstore:
store: inmemory
replication_factor: 1
final_sleep: 0s
chunk_idle_period: 1h
chunk_retain_period: 30s
max_transfer_retries: 0
schema_config:
configs:
- from: 2024-01-01
store: boltdb-shipper
object_store: aws
schema: v11
index:
prefix: loki_index_
period: 24h
storage_config:
aws:
s3: s3://{AK}:{SK}@{REGION}/{BUCKET}
s3forcepathstyle: true
boltdb_shipper:
active_index_directory: /data/loki/index
cache_location: /data/loki/cache
shared_store: s3
limits_config:
reject_old_samples: true
reject_old_samples_max_age: 168h
chunk_store_config:
max_look_back_period: 0s
table_manager:
retention_deletes_enabled: true
retention_period: 30d
3.2.2 OSS 存储策略
存储层级:
| 层级 | 用途 | 存储类型 | 成本 |
|---|---|---|---|
| 标准存储 | 近期日志(30天内) | OSS标准 | 0.12元/GB/月 |
| 低频存储 | 中期日志(30-90天) | OSS低频 | 0.07元/GB/月 |
| 归档存储 | 历史日志(90天以上) | OSS归档 | 0.014元/GB/月 |
生命周期管理:
<LifecycleConfiguration>
<Rule>
<ID>transition-to-infrequent-access</ID>
<Filter>
<Prefix>loki/</Prefix>
</Filter>
<Status>Enabled</Status>
<Transition>
<Days>30</Days>
<StorageClass>IA</StorageClass>
</Transition>
<Transition>
<Days>90</Days>
<StorageClass>Archive</StorageClass>
</Transition>
<Expiration>
<Days>365</Days>
</Expiration>
</Rule>
</LifecycleConfiguration>
3.3 事件处理流程
SDK上报 → API网关 → 格式校验 → 标签提取 → Loki写入 → OSS持久化
↓
索引元数据存储
标签提取策略(用于 Loki 查询):
| 标签名 | 来源字段 | 用途 |
|---|---|---|
project |
project_id |
项目隔离 |
environment |
tags.environment |
环境区分 |
level |
level |
日志级别过滤 |
platform |
platform |
平台分类 |
release |
tags.release |
版本追踪 |
logger |
logger |
日志来源 |
3.4 可视化方案
3.4.1 Grafana 配置
数据源配置:
- 类型:Loki
- URL:
http://localhost:3100 - 认证:无
查询示例:
// 查询所有 error 级别日志
{level="error"} |= "error"
// 查询特定项目的日志
{project="my-project", environment="production"}
// 查询包含特定错误信息的日志
{level="error"} |= "TypeError"
// 统计错误数量
count_over_time({level="error"}[1m])
仪表盘设计:
| 面板 | 功能 | 查询 |
|---|---|---|
| 错误趋势 | 实时错误数量折线图 | count_over_time({level="error"}[1m]) |
| 环境分布 | 各环境错误占比饼图 | sum(count_over_time({level="error"}[1h])) by (environment) |
| 平台分布 | 各平台错误占比饼图 | sum(count_over_time({level="error"}[1h])) by (platform) |
| 最新错误 | 最近错误列表 | `{level="error"} |
| Top错误类型 | 错误类型排名 | topk(5, count by (exception_type) (count_over_time({level="error"}[1h]))) |
4. 部署方案
4.1 服务器配置
ECS 规格:2核2G(阿里云 ecs.g6.large 或同等规格)
操作系统:Ubuntu 22.04 LTS
磁盘配置:
- 系统盘:40GB SSD
- 数据盘:20GB SSD(用于 Loki 索引缓存)
4.2 资源分配
| 组件 | CPU | 内存 |
|---|---|---|
| 系统预留 | 0.5核 | 512MB |
| API网关 (Node.js) | 0.5核 | 256MB |
| Loki | 1核 | 768MB |
| Grafana | 0.5核 | 512MB |
4.3 Docker Compose 部署
version: '3.8'
services:
light-sentry-api:
image: light-sentry/api:latest
ports:
- "9000:9000"
environment:
- LOKI_URL=http://loki:3100
- OSS_ENDPOINT=${OSS_ENDPOINT}
- OSS_ACCESS_KEY=${OSS_ACCESS_KEY}
- OSS_SECRET_KEY=${OSS_SECRET_KEY}
- OSS_BUCKET=${OSS_BUCKET}
depends_on:
- loki
restart: unless-stopped
deploy:
resources:
limits:
cpus: '0.5'
memory: 256M
loki:
image: grafana/loki:2.9.0
ports:
- "3100:3100"
volumes:
- ./loki/config:/etc/loki
- ./loki/data:/data/loki
environment:
- AWS_ACCESS_KEY_ID=${OSS_ACCESS_KEY}
- AWS_SECRET_ACCESS_KEY=${OSS_SECRET_KEY}
restart: unless-stopped
deploy:
resources:
limits:
cpus: '1'
memory: 768M
grafana:
image: grafana/grafana:10.2.0
ports:
- "3000:3000"
volumes:
- ./grafana/data:/var/lib/grafana
- ./grafana/provisioning:/etc/grafana/provisioning
environment:
- GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD}
depends_on:
- loki
restart: unless-stopped
deploy:
resources:
limits:
cpus: '0.5'
memory: 512M
4.4 Nginx 反向代理
server {
listen 80;
server_name logs.example.com;
location /api/ {
proxy_pass http://localhost:9000/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
client_max_body_size 10m;
}
location /grafana/ {
proxy_pass http://localhost:3000/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
5. SDK 接入指南
5.1 前端 SDK 配置
import * as Sentry from '@sentry/browser';
Sentry.init({
dsn: 'https://public_key@logs.example.com/api/1/store/',
environment: 'production',
release: 'v1.0.0',
tracesSampleRate: 1.0,
});
5.2 后端 SDK 配置(Node.js)
import * as Sentry from '@sentry/node';
Sentry.init({
dsn: 'https://public_key@logs.example.com/api/2/store/',
environment: 'production',
release: 'v1.0.0',
tracesSampleRate: 1.0,
});
5.3 后端 SDK 配置(Python)
import sentry_sdk
sentry_sdk.init(
dsn="https://public_key@logs.example.com/api/3/store/",
environment="production",
release="v1.0.0",
traces_sample_rate=1.0,
)
6. 性能优化策略
6.1 内存优化
| 策略 | 说明 |
|---|---|
| Loki 使用 OSS 作为后端 | 减少本地磁盘和内存占用 |
| API网关使用流处理 | 避免一次性加载大请求 |
| 限制并发连接数 | 使用 Nginx 限流 |
6.2 存储优化
| 策略 | 说明 |
|---|---|
| OSS 生命周期管理 | 自动降级存储类型 |
| Loki 压缩 | 启用 Snappy 压缩 |
| 日志采样 | 高频日志采样处理 |
6.3 查询优化
| 策略 | 说明 |
|---|---|
| 标签索引 | 使用标签过滤而非全文搜索 |
| 查询缓存 | Grafana 缓存查询结果 |
| 时间范围限制 | 默认查询最近24小时 |
7. 监控与告警
7.1 健康检查
| 检查项 | 端点 | 频率 |
|---|---|---|
| API网关 | /health |
30秒 |
| Loki | /ready |
30秒 |
| Grafana | /api/health |
30秒 |
7.2 告警规则
| 告警项 | 条件 | 通知方式 |
|---|---|---|
| API错误率 | 错误率 > 5% | 钉钉/邮件 |
| 服务不可用 | 健康检查失败 | 钉钉/邮件 |
| 内存使用率 | 内存 > 85% | 钉钉/邮件 |
| OSS存储告警 | 存储 > 80% | 阿里云告警 |
8. 安全策略
8.1 认证授权
- API 网关支持 Sentry DSN 认证
- Grafana 启用基础认证
- Nginx 配置访问控制列表
8.2 数据加密
- 传输层:HTTPS/TLS 1.2+
- 存储层:OSS 服务端加密(SSE-KMS)
8.3 访问日志
- Nginx 访问日志记录
- API 网关请求日志
9. 成本预估
9.1 服务器成本
| 资源 | 规格 | 月费用 |
|---|---|---|
| ECS | 2核2G | ~80元 |
| 数据盘 | 20GB SSD | ~10元 |
| 合计 | - | ~90元/月 |
9.2 OSS 存储成本
假设日日志量:1GB
| 存储类型 | 容量 | 月费用 |
|---|---|---|
| 标准存储 | 30GB | ~3.6元 |
| 低频存储 | 60GB | ~4.2元 |
| 归档存储 | 275GB | ~3.85元 |
| 合计 | - | ~11.65元/月 |
9.3 总成本
~100元/月(含服务器和存储)
10. 扩展规划
10.1 短期(3个月内)
- 完成核心功能开发
- 集成 Sentry 协议
- 部署上线
10.2 中期(6个月内)
- 增加日志采样功能
- 优化查询性能
- 增加告警功能
10.3 长期(1年内)
- 支持更多日志来源
- 增加分布式追踪
- 考虑升级到更强配置
附录:组件版本建议
| 组件 | 推荐版本 | 备注 |
|---|---|---|
| Node.js | 20.x LTS | API网关运行环境 |
| Express | 4.x | API框架 |
| Loki | 2.9.x | 日志存储 |
| Grafana | 10.x | 可视化 |
| Docker | 24.x | 容器化部署 |
文档版本: v1.0
创建日期: 2026-06-16
适用场景: 2核2G ECS + 阿里云OSS 资源受限环境