← 中文资源

简体中文版本

选择服务水平指标

选择正确的服务水平指标意味着度量用户体验,例如成功请求延迟,而非便利的内部计数或进程存活时间。

阅读英文原文

概念概述

选择服务水平指标(Selecting Service Level Indicators)指的是:选择正确的服务水平指标意味着度量用户体验,例如成功请求延迟,而非便利的内部计数或进程存活时间。

从更严格的定义看,Service level indicator selection is the process of choosing the specific measured ratio, such as the proportion of requests served correctly within a latency threshold, that will represent service quality. 该概念在工程实践中的价值,在于它能帮助团队用统一的语言描述一个具体的质量属性或设计约束,从而在评审与协作中减少歧义。

为什么需要它

It precedes setting an objective, because a target on the wrong indicator incentivises the wrong behaviour. 它与 On-Call Rotation Design、Incident Timeline Reconstruction、Heap Profiling 等概念经常一起出现,用于解决相近的工程问题。理解它的适用场景,有助于在多种备选方案之间做出有依据的取舍,而不是凭直觉选择技术方案。

常见误解

  • any available metric can serve as an indicator
  • an indicator based on server CPU reflects user experience

需要避免的反模式

  • defining availability as process uptime rather than request success
  • choosing an indicator the team cannot influence directly

实践要点

  1. A strong indicator is a ratio of good events to valid events at the point users interact, so it captures partial failures that uptime checks miss.
  2. The indicator should be something the team can influence and measure consistently, using the same definitions in dashboards, alerts, and reports.
  3. Starting with a small number of indicators covering availability and latency keeps attention focused rather than diluting on dozens of near-metrics.

参考来源

https://sre.google/sre-book/service-level-objectives/

代码示例

import promClient from 'prom-client';
import express from 'express';

const registry = new promClient.Registry();
promClient.collectDefaultMetrics({ register: registry, prefix: 'svc_' });

const ordersTotal = new promClient.Counter({
  name: 'orders_created_total',
  help: 'Total orders created',
  labelNames: ['tenant', 'channel'],
  registers: [registry],
});

const requestDuration = new promClient.Histogram({
  name: 'http_request_duration_seconds',
  help: 'Request latency distribution',
  buckets: [0.01, 0.05, 0.1, 0.25, 0.5, 1, 2.5],
  labelNames: ['route', 'method'],
  registers: [registry],
});

async function handleCheckout(req, res) {
  const end = requestDuration.startTimer({ route: '/checkout', method: 'POST' });
  try {
    ordersTotal.inc({ tenant: 'acme', channel: 'web' });
    res.json({ ok: true });
  } finally {
    end();
  }
}

const app = express();
app.post('/checkout', handleCheckout);
app.get('/metrics', async (req, res) => {
  res.set('content-type', registry.contentType);
  res.end(await registry.metrics());
});

app.listen(3000);