light-sentry-sdk/docs/ARCHITECTURE.md

577 lines
16 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 事件数据结构(简化版)
```json
{
"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**
- 轻量级,内存占用远低于 ELKElasticsearch 需要至少 4GB
- 基于标签索引,查询效率高
- 与 Grafana 无缝集成
- 支持 OSS 作为后端存储
**关键配置**
```yaml
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/月 |
**生命周期管理**
```xml
<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`
- 认证:无
**查询示例**
```logql
// 查询所有 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"} | tail 10` |
| 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 部署
```yaml
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 反向代理
```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 配置
```javascript
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
```javascript
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
```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 资源受限环境