站点可靠性工程 SRE 最佳实践 -- 黄金监控信号

本文涉及的产品
可观测可视化 Grafana 版,10个用户账号 1个月
简介: 站点可靠性工程 SRE 最佳实践 -- 黄金监控信号

延迟、流量、错误率、饱和度这四大黄金信号是 SRE 的最佳实践,可用来帮助 SRE 团队快速评估系统状态,在异常情况下及时介入,保证系统始终工作在健康状态。原文: Four Golden Signals Of Monitoring: Site Reliability Engineering (SRE) Metrics


黄金信号(Golden Signals)最初是谷歌在站点可靠性工程(SRE)实践的背景下引入的,由谷歌软件工程师 Dave Rensin 和 Kevin Smathers 在 2016 年 O 'Reilly Velocity Conference 上的一次演讲中提出,其背后的想法是提供一组关键性能指标(KPI),用于测量和监控复杂分布式系统的运行状况。


引入黄金信号是为了帮助 SRE 团队关注系统可靠性和性能方面真正重要的东西。黄金信号不依赖于难以解释的大量指标和告警,而是提供一组简单且易于理解的指标,用于快速评估系统健康状况。


自从这一概念提出以来,黄金信号已在 SRE 社区中得到广泛采用,并被认为是监控和管理分布式系统运行状况的最佳实践。虽然最初黄金信号专注于延迟、流量、错误和饱和指标,但一些组织已经调整了这个概念,引入了特定于其系统和用例的附加指标。不过,通过一组 KPI 来度量和监控系统健康的核心思想仍然是黄金信号概念的核心。

什么是黄金信号?

黄金信号是 SRE 用来衡量其系统健康状况的一组四个关键指标,包括:


  1. 延迟(Latency) —— 延迟用来度量系统响应请求所需的时间,延迟高表明系统可能过载或遇到其他性能问题。


延迟


Prometheus 查询histogram_quantile(0.95, sum(rate(http_request_duration_seconds_bucket{job="fastapi-app"}[5m])) by (le, method, endpoint))通过直方图指标(histogram metric)度量来检测 FastAPI 应用程序 HTTP 请求的 P95 延迟。


该查询计算过去 5 分钟内 http_request_duration_seconds_bucket 度量值(表示落入特定延迟桶的请求数量)的速率总和,并按延迟(le)、HTTP 方法和端点分组。然后,histogram_quantile函数使用这些值计算每个 HTTP 方法和端点组合的 P95 延迟。


  1. 流量(Traffic) —— 流量衡量流经系统的数据或请求的数量,流量高表明系统可能正在处理大量请求,或者系统容量存在问题。


流量


Prometheus 查询rate(http_requests_total{job="fastapi-app"}[$__rate_interval])通过计数器指标(counter metric)度量 FastAPI 应用程序每秒 HTTP 请求的速率。


该查询使用rate函数来计算http_requests_total计数器指标的每秒增长率,计算向 FastAPI 应用程序发出的 HTTP 请求总数。job="fastapi-app"标签选择器过滤度量数据,使其只包含来自 FastAPI 的数据。


$__rate_interval变量是模板变量,表示计算速率的持续时间,该变量值由用户在 Prometheus 查询界面中设置,用于确定计算速率的时间范围。


例如,如果用户将$__rate_interval设置为5m,查询将计算过去 5 分钟内 HTTP 请求的每秒速率。此查询可用于监控 FastAPI 应用程序的流量,并识别请求量随时间变化的模式或异常情况。


  1. 错误(Errors) —— 错误度量系统中发生的错误数量,错误率高表明系统中可能存在 bug 或其他问题。


错误数


Prometheus 查询http_requests_total {endpoint="/generate_error", http_status="500"}检索 web 应用程序的"/generate_error"端点的 HTTP 请求并且 HTTP 状态码为 500(内部服务器错误)的数量。


该查询使用http_requests_total计数器指标,计算向 web 应用程序发出的 HTTP 请求总数。查询通过指定endpoint="/generate_error"标签选择器过滤度量数据,使其只包括对"/generate_error"端点的请求。此外,查询通过指定http_status="500"标签选择器过滤数据,只包括 HTTP 状态码为 500 的请求。


通过运行这个查询,可以深入了解 web 应用中错误发生率,以及哪些端点容易出错。这些信息可以帮助识别和修复应用中的问题,提高可靠性,并确保为用户提供更好的体验。


  1. 饱和度(Saturation) —— 饱和度衡量系统的资源利用率,饱和度高表明系统资源(例如 CPU 或内存)可能正在被耗尽。


饱和度


Prometheus 查询clamp_max(active_requests{job="fastapi-app"} / 10, 1)用于计算活动请求与最大并发请求数的比率,并将该比率的值限制为不超过 1。


该查询使用active_requests度量(gauge)指标检索 FastAPI 应用程序中的当前活动请求数。job="fastapi-app"标签选择器过滤度量数据,使其只包含来自 FastAPI 的数据。


然后,查询将活动请求数除以 10,表示系统可以处理的最大并发请求数。然后使用clamp_max函数将该比率的值限制为不超过 1。这意味着,如果活动请求与最大并发请求数之比大于 1,则查询将返回值 1。


通过这个查询,可以监控系统饱和情况,并确定系统何时因请求而过载。如果活动请求与最大并发请求数之比接近 1,可能需要扩容系统以处理增加的请求。此查询可以帮助我们确保系统在高负载下仍可保持可靠和高性能。

为什么黄金信号很重要?

因为黄金信号使 SRE 们可以清楚了解系统的运行情况,因此非常重要。通过测量和监控这些关键指标,SRE 可以快速识别问题,并在问题变得严重之前采取纠正措施,即使这么做增加了系统复杂性,也可以有助于确保系统的可靠性、可伸缩性和高性能。

如何使用黄金信号来提高系统可靠性?

黄金信号可以通过几种方式来提高系统可靠性:


  1. 主动监控(Proactive Monitoring) —— 通过持续监控黄金信号,SRE 可以在问题变得严重之前识别问题,从而能够采取主动措施来防止停机或其他性能问题。
  2. 容量规划(Capacity Planning) —— 黄金信号可用于识别系统何时达到其容量限制。通过监控流量和饱和度指标,SRE 可以做出明智决定,决定何时升级或扩容系统以满足需求。
  3. 根因分析(Root Cause Analysis) —— 当系统出现问题时,SRE 可以使用黄金信号来帮助确定问题的根本原因。通过查看延迟、流量、错误和饱和度指标,SRE 可以深入了解出了什么问题,并采取措施防止将来发生类似问题。


了解如何在实践中实现这些指标也很重要。实现黄金信号的一种方法是使用内置对其支持的监控工具和库,比如 Prometheus。在下面代码示例中,Python FastAPI 应用程序通过 Prometheus 来实现黄金信号。


from fastapi import FastAPI, Request, HTTPException, Response
from prometheus_client import Counter, Gauge, Histogram, generate_latest, CONTENT_TYPE_LATEST
from starlette.responses import StreamingResponse
import time
app = FastAPI()
# Define Prometheus metrics
http_requests_total = Counter(
    "http_requests_total",
    "Total number of HTTP requests",
    ["method", "endpoint", "http_status"]
)
http_request_duration_seconds = Histogram(
    "http_request_duration_seconds",
    "HTTP request duration in seconds",
    ["method", "endpoint"]
)
http_request_size_bytes = Histogram(
    "http_request_size_bytes",
    "HTTP request size in bytes",
    ["method", "endpoint"]
)
http_response_size_bytes = Histogram(
    "http_response_size_bytes",
    "HTTP response size in bytes",
    ["method", "endpoint"]
)
active_requests = Gauge(
    "active_requests",
    "Number of active requests"
)
error_counter = Counter(
    "error_counter",
    "Total number of HTTP errors",
    ["method", "endpoint", "http_status"]
)
@app.middleware("http")
async def record_request_start_time(request: Request, call_next):
    request.state.start_time = time.time()
    response = await call_next(request)
    return response
@app.middleware("http")
async def record_request_end_time(request: Request, call_next):
    response = await call_next(request)
    latency = time.time() - request.state.start_time
    http_request_duration_seconds.labels(
        request.method, request.url.path
    ).observe(latency)
    http_request_size_bytes.labels(
        request.method, request.url.path
    ).observe(request.headers.get("Content-Length", 0))
    if isinstance(response, StreamingResponse):
        response_size = 0
    else:
        response_size = len(response.content)
    http_response_size_bytes.labels(
        request.method, request.url.path
    ).observe(response_size)
    http_requests_total.labels(
        request.method, request.url.path, response.status_code
    ).inc()
    return response
@app.middleware("http")
async def increment_counter(request: Request, call_next):
    active_requests.inc()
    response = await call_next(request)
    active_requests.dec()
    return response
@app.middleware("http")
async def log_saturation(request: Request, call_next):
    max_concurrent_requests = 10  # set the maximum number of concurrent requests
    saturation_ratio = active_requests._value._value / max_concurrent_requests
    print(f"Saturation: {saturation_ratio}")
    return await call_next(request)
@app.middleware("http")
async def increment_error_counter(request: Request, call_next):
    try:
        response = await call_next(request)
        return response
    except HTTPException as e:
        error_counter.labels(
            request.method, request.url.path, e.status_code
        ).inc()
        print(f"Incremented error counter for {request.method} {request.url.path} {e.status_code}")
        raise e
@app.get("/")
async def root():
    return {"message": "Hello, World!"}
@app.get("/generate_traffic")
async def generate_traffic():
    for i in range(100):
        response = await root()
        print(response)
    return {"message": "Generated traffic successfully."}
@app.get("/generate_error")
async def generate_error():
    raise HTTPException(status_code=500, detail="Generated an error.")
@app.get("/metrics")
async def metrics():
    return Response(content=generate_latest(), media_type=CONTENT_TYPE_LATEST)

复制代码


requirements.txt:


anyio==3.6.2
click==8.1.3
fastapi==0.92.0
h11==0.14.0
idna==3.4
prometheus-client==0.16.0
pydantic==1.10.5
sniffio==1.3.0
starlette==0.25.0
typing_extensions==4.5.0
uvicorn==0.20.0

复制代码

在 K8S 上部署

使用 Prometheus 在 FastAPI 应用程序中实现了黄金信号后,可能希望将其部署到 Kubernetes 集群中,以确保可伸缩性和高可用性。下面的 Kubernetes 清单文件可以用来部署 FastAPI 应用程序和 Grafana 仪表板:


fastapi-app.yaml


# @format
apiVersion: apps/v1
kind: Deployment
metadata:
  name: fastapi-app
spec:
  selector:
    matchLabels:
      app: fastapi-app
  replicas: 2
  template:
    metadata:
      labels:
        app: fastapi-app
      annotations:
        prometheus.io/scrape: "true"
        prometheus.io/path: "/"
        prometheus.io/port: "80"
    spec:
      containers:
        - name: fastapi-app
          image: rtiwariops/fastapi-app:v1
          ports:
            - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: fastapi-app
spec:
  selector:
    app: fastapi-app
  ports:
    - name: http
      protocol: TCP
      port: 80
      targetPort: 80

复制代码


grafana.yaml


# @format
apiVersion: apps/v1
kind: Deployment
metadata:
  name: grafana
spec:
  selector:
    matchLabels:
      app: grafana
  replicas: 1
  template:
    metadata:
      labels:
        app: grafana
    spec:
      containers:
        - name: grafana
          image: grafana/grafana:latest
          ports:
            - containerPort: 3000
---
apiVersion: v1
kind: Service
metadata:
  name: grafana
spec:
  selector:
    app: grafana
  ports:
    - name: http
      protocol: TCP
      port: 3000
      targetPort: 3000

复制代码


prometheus.yaml


apiVersion: v1
kind: Service
metadata:
  name: prometheus
spec:
  selector:
    app: prometheus
  ports:
    - name: web
      port: 9090
      targetPort: 9090
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: prometheus
spec:
  selector:
    matchLabels:
      app: prometheus
  replicas: 1
  template:
    metadata:
      labels:
        app: prometheus
    spec:
      containers:
      - name: prometheus
        image: prom/prometheus:v2.28.1
        ports:
        - name: web
          containerPort: 9090
        command:
        - "/bin/prometheus"
        args:
        - "--config.file=/etc/prometheus/prometheus.yml"
        volumeMounts:
        - name: config-volume
          mountPath: /etc/prometheus
      volumes:
      - name: config-volume
        configMap:
          name: prometheus-config

复制代码


总之,黄金信号是 SRE 工具箱中的关键工具。通过测量和监控延迟、流量、错误和饱和度指标,即使面对日益增加的复杂性和需求,SRE 也可以确保其系统保持可靠、可扩展和高性能。


完整代码示例: https://github.com/PolyCloudNative/Golden-Rule-Demo




你好,我是俞凡,在 Motorola 做过研发,现在在 Mavenir 做技术工作,对通信、网络、后端架构、云原生、DevOps、CICD、区块链、AI 等技术始终保持着浓厚的兴趣,平时喜欢阅读、思考,相信持续学习、终身成长,欢迎一起交流学习。

微信公众号:DeepNoMind

目录
相关文章
|
3月前
|
人工智能 监控 安全
《机器人流程自动化能力评估体系 第1部分:系统和工具》行标发布
《机器人流程自动化能力评估体系 第1部分:系统和工具》(YD/T 4391.1-2023)是国内首部正式发布的RPA行业标准,标准的发布实施填补了我国RPA行业产品标准的空白,在相关行业发展中具有里程碑意义。
58 0
|
9月前
|
存储 网络性能优化 调度
开源代码分享(2)—综合能源系统零碳优化调度
在PDN的最优运行中需要制定电压、无功功率和相应的无功补偿器以维持无功功率平衡和电压质量。此外,大多数现有的联合供热和电力系统使用CHP作为PDN和DHN之间的接口,这无疑与零碳排放的要求背道而驰。因此,我们打算为提出的ZCE-MEI综合NSF-CAES开发一个短期日前调度模型来减少风能的削减和节约系统运行成本。
|
10月前
|
API Python
  SleeFi睡眠链游开发部署规则【分析】
最近出来的边睡边赚(Sleep to Earn),其实是类似gamefi概念的变体,Sleep to Earn让玩家用户透过睡觉作为玩游戏的方式,或完成游戏内任务的替代方式来赚钱。
|
11月前
|
存储 人工智能 自然语言处理
|
11月前
|
机器学习/深度学习 运维 监控
《云上大型赛事保障白皮书》——第六章 云产品稳定性治理与风险管控——6.2 北京冬奥稳定性治理实践——6.2.2 智能风险管控工具--Aspara ServiceStack-CloudDoc
《云上大型赛事保障白皮书》——第六章 云产品稳定性治理与风险管控——6.2 北京冬奥稳定性治理实践——6.2.2 智能风险管控工具--Aspara ServiceStack-CloudDoc
|
11月前
|
监控 算法 Cloud Native
《云原生网络数据面可观测性最佳实践》——五、 典型问题华山论剑——3. 某客户反馈pod偶发性健康检查失败
《云原生网络数据面可观测性最佳实践》——五、 典型问题华山论剑——3. 某客户反馈pod偶发性健康检查失败
|
存储 监控 安全
【SRE】什么是站点可靠性工程?
站点可靠性工程 (SRE) 是将 IT 运营职责与软件开发相结合的结果。对于 SRE,有责任满足为他们管理的服务设定的服务水平目标 (SLO) 和我们在合同中承诺的服务水平协议 (SLA)。
|
消息中间件 缓存 监控
四个步骤,教你落地稳定性保障工作
本文将稳定性保障工作归纳为 梳理异常情况->配置监控告警->评估影响面->预定解决方案 四个步骤。从四个步骤详细介绍稳定性保障工作的落地方法。
49660 1
四个步骤,教你落地稳定性保障工作
|
消息中间件 资源调度 分布式计算
项目环境稳定性指标建设之路
本文通过梳理项目环境生命周期内创建、部署、重启、删除等任务的特点后,去除了流程引擎对消息的依赖,使用分布式分片任务,分布式锁实现任务的分布式运行。通过使用工厂模式,责任链模式,以及领域驱动设计的思路对流程引擎进行重构。最终实现在环境数量翻数百倍以上的情况下,日常以及预发环境平均创建成功率达到 99% 以上,单个环境创建时间由数百秒以上降低至 100秒 以下。工单量每秒并行执行翻近百倍的情况下,系统异常率低于 1% ,单次任务执行时间均值降低 8x%。
674 2
项目环境稳定性指标建设之路
|
运维 供应链 监控
【上新】场景化能力包|业务系统流程协同
场景化能力包——业务系统流程协同
【上新】场景化能力包|业务系统流程协同