得物新一代可观测性架构:海量数据下的存算分离设计与实践

159 阅读17分钟

得物作为全球领先的潮流网购社区,日益增长的用户和数据带来了巨大的技术挑战。当前,得物的可观测性平台每天生成数PB级Trace数据和数万亿条Span记录,要求平台具备高效的实时处理能力和低成本的数据存储解决方案。

我本身没有对于分布式 Trace 和 Span 数据相关的经验,那么使用 Devv 这个 AI 工具进行学习。

我们使用人工智能来学习,对于有实际经验的,可以查看是否正确。

以下由本人的提问和 AI的回答整理而成。


Q:

得物是一家电商公司,请解析这句话:得物的可观测性平台每天生成数PB级Trace数据和数万亿条Span记录。 问题:Trace 数据具体指哪些,span 记录具体指哪些?


A:

让我来解释Trace数据和Span记录的概念,以及它们在可观测性平台中的作用。

  1. Trace(分布式追踪)数据:
  • Trace是记录请求在分布式系统中传播的完整路径2

  • 具体数据包括:

    • 请求从开始到结束的完整旅程
    • 请求经过的所有服务节点
    • 各个服务之间的调用关系
    • 请求处理的时间信息
    • 请求在各个服务中的状态和结果
  1. Span(跨度)记录:
  • Span是追踪中的基本工作单元,代表一个具体的操作或工作单元2

  • 具体记录包括:

    • 操作名称

    • 开始和结束时间

    • 属性(Attributes)信息,例如:

      • HTTP请求方法(如"GET")
      • 网络协议版本
      • URL路径
      • 服务器地址和端口
      • 响应状态码
      • 客户端信息
      • 用户代理信息
  1. 在得物的场景中:
  • 由于是电商平台,每天会产生海量的用户操作,例如:

    • 用户浏览商品
    • 搜索商品
    • 加入购物车
    • 下单支付
    • 物流追踪
  • 每个操作都会生成对应的Trace,而每个Trace又包含多个Span

  • 这些数据对于:

    • 监控系统性能
    • 排查问题
    • 优化用户体验
    • 提升系统可靠性 都起着关键作用3
  1. 数据规模说明:
  • PB级的Trace数据说明得物的系统规模非常大
  • 数万亿条Span记录表明系统高度分布式,服务间调用非常频繁
  • 这种规模的数据对可观测性平台的存储和分析能力提出了很高的要求1

通过这些数据,得物可以:

  • 快速定位系统问题
  • 分析系统性能瓶颈
  • 优化服务调用链路
  • 提升用户体验
  • 实现系统的自动化运维和智能告警

Q:

比如用户浏览了某个商品,那么对于得物的大型分布式系统来说,会生成哪些 trace,请模拟给出一些 trace 记录


A:

让我模拟一个用户浏览商品的场景,展示可能产生的分布式追踪记录。

以下是一个用户访问商品详情页的完整追踪示例:

  1. 主要Trace记录(从前端到后端的完整链路):
Trace ID: 7b2d1e8f-9c4a-4b5d-8e3a-6f1d2c3b4a5e
请求:访问商品详情页 /product/12345
总耗时:386ms

├── [Span 1] Frontend Request (89ms)
│   ├── 用户点击商品链接
│   ├── 前端路由解析
│   └── 发起API请求
│
├── [Span 2] API Gateway (45ms)
│   ├── 请求认证
│   ├── 流量控制检查
│   └── 路由转发
│
├── [Span 3] Product Service (120ms)
│   ├── 查询商品基础信息
│   ├── 查询商品库存
│   └── 查询商品价格
│
├── [Span 4] Inventory Service (35ms)
│   └── 实时库存查询
│
├── [Span 5] Price Service (48ms)
│   ├── 基础价格查询
│   └── 促销价格计算
│
├── [Span 6] User Preference Service (25ms)
│   └── 获取用户偏好数据
│
└── [Span 7] Cache Service (24ms)
    └── 写入商品访问缓存
  1. 每个Span的详细属性示例:
{
  "span_1": {
    "name": "Frontend Request",
    "trace_id": "7b2d1e8f-9c4a-4b5d-8e3a-6f1d2c3b4a5e",
    "span_id": "1a2b3c4d5e6f",
    "parent_span_id": null,
    "start_time": "2024-01-20T10:15:23.021Z",
    "end_time": "2024-01-20T10:15:23.110Z",
    "attributes": {
      "user_id": "u123456",
      "device_type": "mobile",
      "os": "iOS 17.2",
      "app_version": "5.4.0",
      "network_type": "5G"
    }
  },

  "span_3": {
    "name": "Product Service",
    "trace_id": "7b2d1e8f-9c4a-4b5d-8e3a-6f1d2c3b4a5e",
    "span_id": "3c4d5e6f7g8h",
    "parent_span_id": "1a2b3c4d5e6f",
    "start_time": "2024-01-20T10:15:23.155Z",
    "end_time": "2024-01-20T10:15:23.275Z",
    "attributes": {
      "product_id": "12345",
      "service_name": "product-service",
      "service_version": "2.1.0",
      "host": "prod-service-pod-abc123",
      "db_operation": "select",
      "cache_hit": false
    }
  },

  "span_5": {
    "name": "Price Service",
    "trace_id": "7b2d1e8f-9c4a-4b5d-8e3a-6f1d2c3b4a5e",
    "span_id": "5e6f7g8h9i0j",
    "parent_span_id": "3c4d5e6f7g8h",
    "start_time": "2024-01-20T10:15:23.310Z",
    "end_time": "2024-01-20T10:15:23.358Z",
    "attributes": {
      "product_id": "12345",
      "service_name": "price-service",
      "price_type": "dynamic",
      "promotion_active": true,
      "region": "CN-EAST",
      "cache_hit": true
    }
  }
}
  1. 这些Trace记录的特点和作用:
  • 完整性:

    • 记录了从用户点击到最终渲染的完整链路 1
    • 包含了所有相关服务的调用信息
  • 层级关系:

    • 通过parent_span_id体现服务调用的父子关系
    • 可以清晰地看到服务间的依赖关系 2
  • 性能分析:

    • 记录每个环节的具体耗时
    • 可以识别性能瓶颈(如Product Service耗时较长)
    • 帮助优化系统性能 4
  • 问题诊断:

    • 可以快速定位错误发生的具体服务和环节
    • 包含详细的上下文信息,便于问题复现和分析
    • 支持跨服务的问题追踪 5
  • 业务分析:

    • 记录用户行为和业务属性
    • 可用于分析用户访问模式
    • 支持业务监控和决策

Q:

这些 trace 记录如何实时监控系统健康状况?原理是什么?


A:

实时监控系统健康状况的原理主要依赖于分布式追踪(Distributed Tracing)和可观测性平台的结合。以下是其工作原理和关键步骤:

1. 数据收集

  • Trace和Span生成:每当用户进行操作(如浏览商品),系统会自动生成Trace和Span记录。这些记录包含了请求的路径、耗时、状态等详细信息。
  • 分布式收集:Trace和Span数据会从各个服务节点收集到一个集中式的可观测性平台。

2. 数据传输

  • 实时传输:使用高效的传输协议(如gRPC、HTTP)将数据实时传输到监控平台。
  • 数据缓冲:在高流量情况下,使用缓冲机制(如Kafka)来确保数据传输的稳定性和可靠性。

3. 数据存储与处理

  • 存储:将Trace和Span数据存储在高性能数据库中(如Elasticsearch),以便快速查询和分析。
  • 处理:使用流处理框架(如Apache Flink、Apache Storm)对数据进行实时处理,提取关键指标和异常信息。

4. 数据分析与可视化

  • 实时分析:通过分析Trace数据,监控平台可以实时计算系统的关键性能指标(KPI),如请求延迟、错误率、吞吐量等。
  • 异常检测:使用机器学习算法或规则引擎检测异常模式,如响应时间突然增加、错误率上升等。
  • 可视化:将分析结果以图表、仪表盘等形式展示,帮助运维人员快速了解系统健康状况。

5. 告警与响应

  • 自动告警:当检测到异常或指标超出阈值时,系统会自动发送告警通知(如邮件、短信、Slack消息)。
  • 响应机制:运维团队可以根据告警信息快速定位问题根源,并采取相应措施(如扩容、修复故障)。

6. 反馈与优化

  • 持续反馈:通过分析历史Trace数据,识别系统瓶颈和优化机会。
  • 优化策略:根据反馈结果,调整系统架构、优化代码性能、改进服务配置等。

实时监控的优势

  • 快速响应:实时监控使得问题能够在发生时立即被发现,缩短了故障响应时间。
  • 全面覆盖:分布式追踪提供了系统全局视图,能够覆盖所有服务和组件。
  • 数据驱动:通过数据分析,支持基于事实的决策和优化。

这些步骤和机制共同构成了一个高效的实时监控系统,使得得物能够保持系统的高可用性和稳定性。


Q:

在数据收集这一步,收集的数据一般是什么样子,仍然以得物这个电商公司举例子,给出一些收集的数据的格式样例。

(关于数据举例的,AI 给的数据比较单一,我想要更为丰富的数据样例,因此多了几步提问)

Q:

我们只关注于商品详情页的访问的数据收集,请给出一个更加丰富的样例。

Q:

parent_span_id为空,表示这是顶级请求。不要只给出顶级请求,给出三个样例。


A:

好的,让我们扩展这个场景,提供三个不同的Span样例,展示从顶级请求到子请求的完整链路。

商品详情页访问的详细数据收集样例

{
  "resource": {
    "service.name": "dewu-product-service",
    "service.version": "1.5.0",
    "host.name": "prod-pod-east-1",
    "deployment.environment": "production"
  },
  "trace_id": "abcdef0123456789",
  "spans": [
    {
      "span_id": "span_001",
      "parent_span_id": null,
      "name": "GET /api/v1/products/12345",
      "kind": "SERVER",
      "start_time_unix_nano": 1674183600000000000,
      "end_time_unix_nano": 1674183600150000000,
      "attributes": {
        "http.method": "GET",
        "http.url": "/api/v1/products/12345",
        "http.status_code": 200,
        "http.user_agent": "Dewu/5.4.0 (iPhone; iOS 17.2)",
        "user.id": "u789012",
        "product.id": "12345",
        "client.ip": "101.23.45.67"
      },
      "events": [
        {
          "name": "cache.lookup.start",
          "timestamp": 1674183600020000000
        },
        {
          "name": "cache.lookup.end",
          "timestamp": 1674183600030000000,
          "attributes": {
            "cache.result": "miss"
          }
        }
      ]
    },
    {
      "span_id": "span_002",
      "parent_span_id": "span_001",
      "name": "DB Query - Product Details",
      "kind": "CLIENT",
      "start_time_unix_nano": 1674183600040000000,
      "end_time_unix_nano": 1674183600100000000,
      "attributes": {
        "db.system": "mysql",
        "db.statement": "SELECT * FROM products WHERE id = 12345",
        "db.response_time_ms": 6,
        "db.rows_returned": 1
      },
      "events": [
        {
          "name": "db.query.start",
          "timestamp": 1674183600040000000
        },
        {
          "name": "db.query.end",
          "timestamp": 1674183600100000000
        }
      ]
    },
    {
      "span_id": "span_003",
      "parent_span_id": "span_001",
      "name": "Render Product Page",
      "kind": "SERVER",
      "start_time_unix_nano": 1674183600110000000,
      "end_time_unix_nano": 1674183600140000000,
      "attributes": {
        "render.engine": "React",
        "render.template": "product_detail",
        "render.time_ms": 3
      },
      "events": [
        {
          "name": "render.start",
          "timestamp": 1674183600110000000
        },
        {
          "name": "render.end",
          "timestamp": 1674183600140000000
        }
      ]
    }
  ]
}

详细说明

  1. 顶级请求(Span 1)

    • Span ID: span_001
    • Parent Span ID: null(表示这是顶级请求)
    • 描述: 处理用户请求访问商品详情页。
    • 关键属性: HTTP方法、URL、状态码、用户代理、用户ID、产品ID、客户端IP。
    • 事件: 缓存查找的开始和结束。
  2. 数据库查询(Span 2)

    • Span ID: span_002
    • Parent Span ID: span_001(表示这是顶级请求的子请求)
    • 描述: 查询数据库以获取商品详细信息。
    • 关键属性: 数据库系统、查询语句、响应时间、返回行数。
    • 事件: 数据库查询的开始和结束。
  3. 页面渲染(Span 3)

    • Span ID: span_003
    • Parent Span ID: span_001(表示这是顶级请求的子请求)
    • 描述: 渲染商品详情页。
    • 关键属性: 渲染引擎、模板名称、渲染时间。
    • 事件: 渲染过程的开始和结束。

应用场景

  • 性能分析:通过分析每个Span的耗时,识别性能瓶颈。
  • 故障排查:通过事件和属性信息,快速定位问题根源。
  • 系统优化:通过分析数据库查询和渲染时间,优化系统性能。

这种详细的Span记录能够帮助开发和运维团队全面了解请求的处理过程,从而更好地监控和优化系统。


Q:

现在我们已经拿到了数据,并且存到了Elasticsearch 中,接下来我们研究一下数据处理部分,处理:使用流处理框架(如Apache Flink、Apache Storm)对数据进行实时处理,提取关键指标和异常信息。 假如我们使用Apache Flink来对数据进行处理,我们一般会对数据做怎样的处理呢?

(感觉回答的没什么价值,应该跟我的提问方式有关。)

Q:

**``` 实时分析:通过分析Trace数据,监控平台可以实时计算系统的关键性能指标(KPI),如请求延迟、错误率、吞吐量等。

对于这句话,假如我们已经使用Apache Flink 处理了数据,接下来我们该如何进行分析呢?**

---

**A:**

在使用Apache Flink处理完Trace数据后,接下来进行分析的步骤通常包括以下几个方面:

### 1. 数据存储

首先,将处理后的数据存储到适合分析的存储系统中,例如:

- **时序数据库**(如InfluxDB、Prometheus):适合存储和查询时间序列数据,如请求延迟和吞吐量。
- **数据仓库**(如Amazon Redshift、Google BigQuery):适合进行复杂的分析查询和报表生成。
- **Elasticsearch**:适合全文搜索和分析。

### 2. 数据可视化

使用数据可视化工具来展示关键性能指标(KPI),例如:

- **Grafana**:与时序数据库集成,实时展示指标图表。
- **Kibana**:与Elasticsearch集成,提供强大的搜索和可视化功能。
- **Tableau**:适合生成复杂的商业智能报表。

### 3. 实时告警

设置告警系统来监控关键指标的变化:

- **Prometheus Alertmanager**:用于监控Prometheus中的指标,并在指标超出阈值时发送告警。
- **ElastAlert**:用于监控Elasticsearch中的数据,并在检测到异常时发送告警。
- **PagerDuty****OpsGenie**:用于接收告警并通知相关人员。

### 4. 数据分析

进行深入的数据分析,以识别趋势和异常:

- **SQL查询**:在数据仓库中执行复杂的SQL查询,分析历史数据。
- **机器学习**:使用机器学习模型进行预测和异常检测。
- **自定义分析脚本**:编写Python或R脚本,进行特定的分析任务。

### 5. 生成报告

定期生成分析报告,以总结系统性能和业务指标:

- **自动化报表生成**:使用工具(如Jupyter Notebook、Apache Zeppelin)生成可视化报告。
- **定期邮件报告**:将分析结果定期发送给相关团队。

### 示例:使用Grafana进行可视化

假设我们将处理后的数据存储在InfluxDB中,可以使用Grafana进行可视化:

1. **配置数据源**    - 在Grafana中添加InfluxDB作为数据源。
2. **创建仪表板**    - 创建一个新的仪表板,添加多个面板来展示不同的KPI。
3. **添加面板**    - **请求延迟**:展示每分钟的平均请求延迟。
    - **错误率**:展示每分钟的错误请求比例。
    - **吞吐量**:展示每秒的请求数量。
4. **设置告警**    - 在Grafana中为关键指标设置告警规则,当指标超出阈值时触发告警。

### 示例:使用SQL进行分析

假设我们将数据存储在Amazon Redshift中,可以使用SQL进行分析:

```sql
-- 计算过去一小时的平均请求延迟
SELECT
    AVG(latency) AS avg_latency
FROM
    trace_data
WHERE
    timestamp >= NOW() - INTERVAL '1 hour';

-- 计算过去一小时的错误率
SELECT
    COUNT(*) FILTER (WHERE status_code >= 500) * 100.0 / COUNT(*) AS error_rate
FROM
    trace_data
WHERE
    timestamp >= NOW() - INTERVAL '1 hour';

-- 计算过去一小时的吞吐量
SELECT
    COUNT(*) / 3600.0 AS throughput_per_second
FROM
    trace_data
WHERE
    timestamp >= NOW() - INTERVAL '1 hour';

通过这些步骤,我们可以全面分析和监控系统的关键性能指标,确保系统的稳定性和高效性。


Q:

如果我想将数据存储到Prometheus,那么一般我的数据结构是怎样的?


Prometheus的数据模型有其特定的结构。让我详细解释Prometheus的数据模型和具体示例:

1. Prometheus数据模型的基本结构

Prometheus的数据模型主要包含以下几个要素 1:

<metric_name>{<label_name>=<label_value>, ...} value timestamp

2. 四种主要的指标类型

  1. Counter(计数器)
# 计数器示例 - 记录商品详情页的总访问次数
product_page_views_total{product_id="12345", category="sneakers"} 1234

# HTTP请求总数
http_requests_total{method="GET", path="/api/v1/products", status="200"} 5678

# 错误计数
error_count_total{service="product-service", error_type="timeout"} 50
  1. Gauge(仪表盘)
# 仪表盘示例 - 当前活跃用户数
active_users{service="product-service"} 150

# 当前系统内存使用量
memory_usage_bytes{instance="prod-1"} 1048576

# 当前商品库存量
product_stock{product_id="12345", warehouse="shanghai"} 42
  1. Histogram(直方图)
# 直方图示例 - 请求延迟分布
http_request_duration_seconds_bucket{le="0.1", path="/api/products"} 1000
http_request_duration_seconds_bucket{le="0.2", path="/api/products"} 1500
http_request_duration_seconds_bucket{le="0.5", path="/api/products"} 2000
http_request_duration_seconds_bucket{le="+Inf", path="/api/products"} 2200
http_request_duration_seconds_sum{path="/api/products"} 1234.5
http_request_duration_seconds_count{path="/api/products"} 2200

# 商品页面加载时间分布
page_load_time_seconds_bucket{le="1.0", page="product_detail"} 800
page_load_time_seconds_bucket{le="2.0", page="product_detail"} 1200
page_load_time_seconds_bucket{le="5.0", page="product_detail"} 1400
page_load_time_seconds_bucket{le="+Inf", page="product_detail"} 1500
page_load_time_seconds_sum{page="product_detail"} 2500.0
page_load_time_seconds_count{page="product_detail"} 1500
  1. Summary(摘要)
# 摘要示例 - API响应时间分位数
api_response_time_seconds{quantile="0.5"} 0.05
api_response_time_seconds{quantile="0.9"} 0.1
api_response_time_seconds{quantile="0.99"} 0.2
api_response_time_seconds_sum 1234.5
api_response_time_seconds_count 1000

# 商品搜索延迟分位数
search_latency_seconds{quantile="0.5", service="search"} 0.02
search_latency_seconds{quantile="0.9", service="search"} 0.05
search_latency_seconds{quantile="0.99", service="search"} 0.1
search_latency_seconds_sum{service="search"} 500.0
search_latency_seconds_count{service="search"} 10000

3. 实际应用示例

以电商平台的商品详情页为例,我们可能需要监控以下指标:

# 1. 访问量统计(Counter)
product_page_views_total{product_id="12345", category="sneakers", brand="nike"} 1000

# 2. 响应时间分布(Histogram)
product_page_response_time_bucket{le="0.1", product_id="12345"} 800
product_page_response_time_bucket{le="0.2", product_id="12345"} 900
product_page_response_time_bucket{le="0.5", product_id="12345"} 950
product_page_response_time_bucket{le="+Inf", product_id="12345"} 1000
product_page_response_time_sum{product_id="12345"} 150.0
product_page_response_time_count{product_id="12345"} 1000

# 3. 当前并发用户数(Gauge)
product_page_concurrent_users{product_id="12345"} 42

# 4. 错误率统计(Counter)
product_page_errors_total{product_id="12345", error_type="timeout"} 5
product_page_errors_total{product_id="12345", error_type="500"} 2

# 5. 缓存命中率(Gauge)
product_page_cache_hit_ratio{product_id="12345"} 0.95

# 6. 数据库查询时间(Summary)
product_page_db_query_time_seconds{quantile="0.5", query_type="product_info"} 0.01
product_page_db_query_time_seconds{quantile="0.9", query_type="product_info"} 0.05
product_page_db_query_time_seconds{quantile="0.99", query_type="product_info"} 0.10
product_page_db_query_time_seconds_sum{query_type="product_info"} 100.0
product_page_db_query_time_seconds_count{query_type="product_info"} 5000

4. 最佳实践

  1. 命名规范

    • 使用有意义的前缀(如http_product_
    • 使用下划线分隔单词
    • 在Counter类型指标末尾添加_total后缀
    • 在时间类指标中添加单位(如_seconds
  2. 标签使用

    • 使用有意义的标签名
    • 避免标签值过多
    • 保持标签一致性
    • 使用标准化的标签值
  3. 数据粒度

    • 根据实际需求选择合适的时间粒度
    • 考虑存储成本和查询性能
    • 合理设置数据保留时间

通过这样的数据结构,我们可以:

  • 实时监控系统性能
  • 进行趋势分析
  • 设置告警规则
  • 生成可视化报表

以上就是我通过 AI 来学习分布式环境下 Trace 和 Span 等相关信息的过程。

Update: 以上由 devv 整理而来。