Files
makemd/docs/02_Backend/06_Observability.md
wurenzhi eafa1bbe94 feat: 添加货币和汇率管理功能
refactor: 重构前端路由和登录逻辑

docs: 更新业务闭环、任务和架构文档

style: 调整代码格式和文件结构

chore: 更新依赖项和配置文件
2026-03-19 19:08:15 +08:00

8.9 KiB
Raw Blame History

可观测性文档 (Crawlful Hub)

定位Crawlful Hub 可观测性设计文档 - 确保系统的可观测性,便于问题排查和系统优化。 更新日期: 2026-03-18 最高优先级参考: Service_Design.md


1. 可观测性概述

1.1 定义

可观测性是指通过系统的外部输出(如日志、指标、追踪)来了解系统内部状态的能力。

1.2 重要性

良好的可观测性可以:

  • 快速定位和解决问题
  • 预测和预防系统故障
  • 优化系统性能
  • 提高系统可靠性
  • 降低运维成本

1.3 核心组成

  • 业务日志:记录业务操作的详细信息
  • 链路追踪:追踪请求在系统中的完整路径
  • 指标监控:监控系统的各种指标

2. 业务日志

2.1 定义

业务日志是指记录业务操作的详细信息,包括操作人、操作时间、操作类型、操作对象、操作结果等。

2.2 实现方法

2.2.1 日志级别

  • DEBUG:详细的调试信息
  • INFO:一般的信息
  • WARN:警告信息
  • ERROR:错误信息
  • FATAL:致命错误信息

2.2.2 日志格式

{
  "timestamp": "2026-03-18T10:00:00Z",
  "level": "INFO",
  "service": "ProductService",
  "method": "updatePrice",
  "traceId": "1234567890",
  "tenantId": "tenant-001",
  "shopId": "shop-001",
  "businessType": "TOC",
  "message": "Updating price for product 123 to 99.99",
  "data": {
    "productId": "123",
    "oldPrice": 89.99,
    "newPrice": 99.99,
    "roi": 1.5
  }
}

2.2.3 日志框架

推荐

  • Node.jswinston, bunyan
  • Javalog4j, logback
  • Pythonlogging, structlog

示例

// Node.js/winston 示例
import winston from 'winston';

const logger = winston.createLogger({
  level: process.env.LOG_LEVEL || 'info',
  format: winston.format.json(),
  transports: [
    new winston.transports.Console(),
    new winston.transports.File({ filename: 'error.log', level: 'error' }),
    new winston.transports.File({ filename: 'combined.log' })
  ]
});

// 使用
logger.info('Updating price for product', {
  productId: '123',
  oldPrice: 89.99,
  newPrice: 99.99,
  traceId: '1234567890',
  tenantId: 'tenant-001',
  shopId: 'shop-001',
  businessType: 'TOC'
});

2.3 最佳实践

  • 结构化日志:使用 JSON 格式,便于分析和查询
  • 统一日志格式:所有服务使用相同的日志格式
  • 包含必要字段时间戳、级别、服务名、方法名、追踪ID、租户ID、店铺ID、业务类型等
  • 适当的日志级别:根据信息的重要性选择合适的级别
  • 日志轮转:定期轮转日志文件,防止日志文件过大
  • 日志存储:使用 ELK Stack、Splunk 等工具存储和分析日志

3. 链路追踪

3.1 定义

链路追踪是指追踪请求在系统中的完整路径,包括请求经过的所有服务和操作。

3.2 实现方法

3.2.1 追踪ID

定义:一个唯一的标识符,用于关联同一个请求的所有操作

实现

  • 生成唯一的 traceId
  • 在请求开始时创建 traceId
  • 在所有相关操作中传递 traceId

示例

// 中间件生成 traceId
const traceMiddleware = (req, res, next) => {
  const traceId = req.headers['x-trace-id'] || uuidv4();
  req.traceId = traceId;
  res.setHeader('x-trace-id', traceId);
  next();
};

// 使用
app.use(traceMiddleware);

// 在服务中使用
async updatePrice(productId: string, price: number, traceId: string): Promise<Product> {
  logger.info('Updating price', { traceId, productId, price });
  // 业务逻辑
  return product;
}

3.2.2 分布式追踪系统

推荐

  • Jaeger
  • Zipkin
  • OpenTelemetry

示例

// 使用 OpenTelemetry
import { trace } from '@opentelemetry/api';
import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node';
import { JaegerExporter } from '@opentelemetry/exporter-jaeger';

// 初始化追踪器
const provider = new NodeTracerProvider();
const exporter = new JaegerExporter({
  serviceName: 'product-service'
});

provider.addSpanProcessor(new SimpleSpanProcessor(exporter));
provider.register();

// 创建 span
const tracer = trace.getTracer('product-service');

async updatePrice(productId: string, price: number): Promise<Product> {
  const span = tracer.startSpan('updatePrice');
  
  try {
    // 业务逻辑
    const product = await this.productRepository.findById(productId);
    
    // 创建子 span
    const calculateRoiSpan = tracer.startSpan('calculateROI', { 
      parent: span 
    });
    const roi = await this.pricingService.calculateROI(product, price);
    calculateRoiSpan.end();
    
    product.price = price;
    product.roi = roi;
    const updatedProduct = await this.productRepository.save(product);
    
    return updatedProduct;
  } finally {
    span.end();
  }
}

3.3 最佳实践

  • 统一的追踪ID所有服务使用相同的追踪ID格式
  • 完整的链路:追踪请求的完整路径,包括所有服务和操作
  • 适当的 span:为重要操作创建 span
  • 添加上下文信息:在 span 中添加业务相关的上下文信息
  • 集成监控系统:将追踪数据与监控系统集成

4. 指标监控

4.1 定义

指标监控是指监控系统的各种指标,如响应时间、调用次数、错误率等。

4.2 实现方法

4.2.1 核心指标

  • 响应时间:请求的处理时间
  • 调用次数:服务的调用次数
  • 错误率:错误请求的比例
  • 资源使用CPU、内存、磁盘、网络等资源的使用情况
  • 业务指标:订单量、销售额、利润率等

4.2.2 监控系统

推荐

  • Prometheus
  • Grafana
  • Datadog
  • New Relic

示例

// 使用 Prometheus
import prometheus from 'prom-client';

// 定义指标
const requestCounter = new prometheus.Counter({
  name: 'http_requests_total',
  help: 'Total number of HTTP requests',
  labelNames: ['method', 'endpoint', 'status']
});

const requestDuration = new prometheus.Histogram({
  name: 'http_request_duration_seconds',
  help: 'HTTP request duration in seconds',
  labelNames: ['method', 'endpoint'],
  buckets: [0.1, 0.5, 1, 2, 5]
});

// 中间件
const metricsMiddleware = (req, res, next) => {
  const start = process.hrtime();
  
  res.on('finish', () => {
    const duration = process.hrtime(start);
    const seconds = duration[0] + duration[1] / 1e9;
    
    requestCounter.inc({
      method: req.method,
      endpoint: req.path,
      status: res.statusCode
    });
    
    requestDuration.observe({
      method: req.method,
      endpoint: req.path
    }, seconds);
  });
  
  next();
};

// 使用
app.use(metricsMiddleware);
app.get('/metrics', (req, res) => {
  res.set('Content-Type', prometheus.register.contentType);
  res.end(prometheus.register.metrics());
});

4.3 最佳实践

  • 定义关键指标:根据业务需求定义关键指标
  • 设置合理的告警:为重要指标设置告警
  • 可视化:使用 Grafana 等工具可视化指标
  • 定期分析:定期分析指标数据,发现问题和优化机会
  • 集成业务指标:将业务指标与技术指标结合

5. 可观测性集成

5.1 日志、追踪和指标的关联

  • 使用相同的 traceId:将日志、追踪和指标关联起来
  • 统一的上下文:在所有可观测性数据中包含相同的上下文信息
  • 集成平台:使用 ELK Stack、Grafana 等平台集成所有可观测性数据

5.2 监控仪表盘

推荐仪表盘

  • 系统健康仪表盘:显示系统的整体健康状态
  • 服务性能仪表盘:显示各个服务的性能指标
  • 业务指标仪表盘:显示业务相关的指标
  • 告警仪表盘:显示当前的告警状态

5.3 告警策略

  • 设置合理的阈值:根据业务需求设置合理的告警阈值
  • 分级告警:根据问题的严重程度设置不同级别的告警
  • 告警通知通过邮件、短信、Slack 等渠道发送告警通知
  • 告警抑制:避免告警风暴

6. 最佳实践

6.1 设计原则

  • 可观测性优先:在系统设计阶段就考虑可观测性
  • 统一标准:所有服务使用相同的可观测性标准
  • 适度采集:采集足够的数据,但不过度采集
  • 数据保留:设置合理的数据保留策略

6.2 实现建议

  • 使用开源工具:如 ELK Stack、Prometheus、Grafana、Jaeger 等
  • 自动化部署:自动化可观测性工具的部署和配置
  • 定期演练:定期演练故障排查和恢复流程
  • 持续优化:根据实际情况持续优化可观测性方案

7. 相关文档


本文档基于服务设计文档,最后更新: 2026-03-18