name: sre-engineer description: “专家级网站可靠性工程师,专注于SLOs、错误预算和可靠性工程实践。精通事故管理、事后分析、容量规划和构建可扩展、弹性系统,重点放在可靠性、可用性和性能上。”
网站可靠性工程师
目的
提供专家级的网站可靠性工程专业知识,用于构建和维护高可用性、可扩展性和弹性系统。专注于SLOs、错误预算、事故管理、混沌工程、容量规划和可观测性平台,重点放在可靠性、可用性和性能上。
何时使用
- 定义和实施SLOs(服务水平目标)和错误预算
- 从检测到解决再到事后分析的事故管理
- 构建高可用性架构(多区域、容错)
- 进行混沌工程实验(故障注入、弹性测试)
- 容量规划和自动扩展策略
- 实施可观测性平台(指标、日志、追踪)
- 设计减少劳作和自动化策略
快速开始
在以下情况下调用此技能:
- 定义和实施SLOs(服务水平目标)和错误预算
- 从检测到解决再到事后分析的事故管理
- 构建高可用性架构(多区域、容错)
- 进行混沌工程实验(故障注入、弹性测试)
- 容量规划和自动扩展策略
- 实施可观测性平台(指标、日志、追踪)
不要在以下情况下调用:
- 仅需要DevOps自动化(CI/CD流水线使用devops-engineer)
- 应用级调试(使用debugger技能)
- 没有可靠性上下文的基础设施配置(使用cloud-architect)
- 数据库性能调优(使用database-optimizer)
- 安全事故响应(使用incident-responder进行安全)
核心工作流程
工作流程1: 定义和实施SLOs
**用例:**新微服务需要SLO定义和监控
步骤1: SLI(服务水平指标)选择
# 服务: 用户认证API
# 关键用户旅程: 登录流程
SLI候选:
1. 可用性(请求成功率):
定义: (successful_requests / total_requests) * 100
测量: HTTP 2xx响应与5xx错误
理由: 服务健康的核心指标
2. 延迟(响应时间):
定义: P99响应时间 < 500ms
测量: 从请求接收到响应发送的时间
理由: 用户体验直接受慢登录影响
3. 正确性(认证准确性):
定义: 有效令牌发行/认证尝试
测量: 发行后1小时内JWT验证失败
理由: 安全性和功能正确性
SLO的选定SLIs:
- 可用性: 99.9%(主要SLO)
- 延迟P99: 500ms(次要SLO)
步骤2: SLO定义文档
# 认证服务SLO
## 服务概览
- **服务**: 用户认证API
- **所有者**: 平台团队
- **重要性**: Tier 1(阻止所有用户操作)
## SLO承诺
### 主要SLO: 可用性
- **目标**: 28天滚动窗口内99.9%可用性
- **错误预算**: 0.1% = 每28天40.3分钟停机时间
- **测量**: `(count(http_response_code=2xx) / count(http_requests)) >= 0.999`
- **排除**: 计划维护窗口,客户端错误(4xx)
### 次要SLO: 延迟
- **目标**: P99延迟 < 500ms
- **错误预算**: 1%的请求可以超过500ms
- **测量**: `histogram_quantile(0.99, http_request_duration_seconds) < 0.5`
- **测量窗口**: 5分钟滑动窗口
## 错误预算政策
### 预算剩余行动:
- **> 50%**: 正常开发速度,允许功能发布
- **25-50%**: 减缓功能发布,优先考虑可靠性
- **10-25%**: 功能冻结,专注于SLO改进
- **<10%**: 事故声明,全力以赴可靠性
### 预算耗尽(0%):
- 立即冻结功能
- 回滚最近更改
- 需要根本原因分析
- 需要执行通知
## 监控和警报
**Prometheus警报规则:**
```yaml
groups:
- name: auth_service_slo
interval: 30s
rules:
# 可用性SLO警报
- alert: AuthServiceSLOBreach
expr: |
(
sum(rate(http_requests_total{service="auth",code=~"2.."}[5m]))
/
sum(rate(http_requests_total{service="auth"}[5m]))
) < 0.999
for: 5m
labels:
severity: critical
service: auth
annotations:
summary: "认证服务可用性低于SLO"
description: "当前可用性: {{ $value | humanizePercentage }}"
# 错误预算快速消耗警报(快速消耗)
- alert: AuthServiceErrorBudgetFastBurn
expr: |
(
1 - (
sum(rate(http_requests_total{service="auth",code=~"2.."}[1h]))
/
sum(rate(http_requests_total{service="auth"}[1h]))
)
) > 14.4 * (1 - 0.999) # 1小时内消耗2%的月度预算
for: 5m
labels:
severity: critical
service: auth
annotations:
summary: "认证服务以14.4倍速度消耗错误预算"
description: "按此速度,月度预算将在2天内耗尽"
# 延迟SLO警报
- alert: AuthServiceLatencySLOBreach
expr: |
histogram_quantile(0.99,
sum(rate(http_request_duration_seconds_bucket{service="auth"}[5m])) by (le)
) > 0.5
for: 5m
labels:
severity: warning
service: auth
annotations:
summary: "认证服务P99延迟超过SLO"
description: "当前P99: {{ $value }}s (SLO: 0.5s)"
步骤3: Grafana仪表板
{
"dashboard": {
"title": "认证服务SLO仪表板",
"panels": [
{
"title": "30天可用性SLO",
"targets": [{
"expr": "avg_over_time((sum(rate(http_requests_total{service=\"auth\",code=~\"2..\"}[5m])) / sum(rate(http_requests_total{service=\"auth\"}[5m])))[30d:5m])"
}],
"thresholds": [
{"value": 0.999, "color": "green"},
{"value": 0.995, "color": "yellow"},
{"value": 0, "color": "red"}
]
},
{
"title": "错误预算剩余",
"targets": [{
"expr": "1 - ((1 - avg_over_time((sum(rate(http_requests_total{service=\"auth\",code=~\"2..\"}[5m])) / sum(rate(http_requests_total{service=\"auth\"}[5m])))[30d:5m])) / (1 - 0.999))"
}],
"visualization": "gauge",
"thresholds": [
{"value": 0.5, "color": "green"},
{"value": 0.25, "color": "yellow"},
{"value": 0, "color": "red"}
]
}
]
}
}
工作流程3: 混沌工程实验
**用例:**验证对数据库故障转移的弹性
实验设计:
# chaos-experiment-db-failover.yaml
apiVersion: chaos-mesh.org/v1alpha1
kind: PodChaos
metadata:
name: database-primary-kill
namespace: chaos-testing
spec:
action: pod-kill
mode: one
selector:
namespaces:
- production
labelSelectors:
app: postgresql
role: primary
scheduler:
cron: "@every 2h" # 每2小时运行实验
duration: "0s" # 立即杀死
假设:
## 假设
**稳态**:
- 应用程序保持99.9%可用性
- P99延迟 < 500ms
- 数据库查询成功,自动故障转移到副本
**干扰**:
- 杀死主数据库pod(模拟AZ故障)
**预期行为**:
- Kubernetes在10秒内检测到pod故障
- 副本在30秒内提升为主
- 应用程序在5秒内重新连接到新主
- 总影响:<45秒的提高错误率(<5%)
- 无数据丢失(同步复制)
**中止条件**:
- 错误率> 20%超过60秒
- 发出手动回滚命令
- 客户投诉激增>10倍正常
执行步骤:
#!/bin/bash
# chaos-experiment-runner.sh
set -e
echo "=== 混沌实验:数据库故障转移 ==="
echo "开始时间: $(date)"
# 第1步:基线指标(5分钟)
echo "[1/7] 收集基线指标..."
START_TIME=$(date -u +%s)
sleep 300
BASELINE_ERROR_RATE=$(promtool query instant \
'sum(rate(http_requests_total{code=~"5.."}[5m])) / sum(rate(http_requests_total[5m]))' \
| jq -r '.data.result[0].value[1]')
echo "基线错误率: ${BASELINE_ERROR_RATE}"
# 第2步:注入故障
echo "[2/7] 注入故障:杀死主数据库pod..."
kubectl delete pod -l app=postgresql,role=primary -n production
# 第3步:监控故障转移
echo "[3/7] 监控故障转移过程..."
for i in {1..60}; do
READY_PODS=$(kubectl get pods -l app=postgresql -n production \
-o jsonpath='{.items[?(@.status.conditions[?(@.type=="Ready")].status=="True")].metadata.name}' \
| wc -w)
if [ $READY_PODS -ge 1 ]; then
echo "故障转移完成于T+${i}s: $READY_PODS就绪pod"
break
fi
echo "T+${i}s: 等待副本提升..."
sleep 1
done
# 第4步:测量影响
echo "[4/7] 测量事件影响..."
sleep 60 # 等待指标稳定
INCIDENT_ERROR_RATE=$(promtool query instant \
'max_over_time((sum(rate(http_requests_total{code=~"5.."}[1m])) / sum(rate(http_requests_total[1m])))[5m:])' \
| jq -r '.data.result[0].value[1]')
echo "事件期间峰值错误率: ${INCIDENT_ERROR_RATE}"
# 第5步:验证恢复
echo "[5/7] 验证服务恢复..."
for i in {1..30}; do
CURRENT_ERROR_RATE=$(promtool query instant \
'sum(rate(http_requests_total{code=~"5.."}[1m])) / sum(rate(http_requests_total[1m]))' \
| jq -r '.data.result[0].value[1]')
if (( $(echo "$CURRENT_ERROR_RATE < 0.01" | bc -l) )); then
echo "服务恢复于T+$((60+i))s"
break
fi
sleep 1
done
# 第6步:数据完整性检查
echo "[6/7] 运行数据完整性检查..."
psql -h postgres-primary-service -U app -c "SELECT COUNT(*) FROM orders WHERE created_at > NOW() - INTERVAL '10 minutes';"
# 第7步:结果总结
echo "[7/7] 实验结果:"
echo "================================"
echo "基线错误率: ${BASELINE_ERROR_RATE}"
echo "峰值错误率: ${INCIDENT_ERROR_RATE}"
echo "当前错误率: ${CURRENT_ERROR_RATE}"
echo "故障转移时间:约30-45秒"
echo "假设验证:$([ $(echo "$INCIDENT_ERROR_RATE < 0.05" | bc -l) -eq 1 ] && echo "PASS" || echo "FAIL")"
echo "================================"
# 输出实验报告
cat > experiment-report-$(date +%Y%m%d-%H%M%S).md <<EOF
# 混沌实验报告:数据库故障转移
## 实验详情
- **日期**: $(date)
- **假设**: 应用程序在主数据库故障中生存,错误率<5%
- **干扰**: 杀死主PostgreSQL pod
## 结果
- **基线错误率**: ${BASELINE_ERROR_RATE}
- **故障期间峰值错误率**: ${INCIDENT_ERROR_RATE}
- **恢复时间**: 约45秒
- **数据完整性**: 已验证(无数据丢失)
## 假设验证
$([ $(echo "$INCIDENT_ERROR_RATE < 0.05" | bc -l) -eq 1 ] && echo "✅ PASS - 错误率保持在5%以下" || echo "❌ FAIL - 错误率超过5%")
## 行动项
1. 将故障转移时间从45秒减少到<30秒(调整健康检查间隔)
2. 添加连接池重试逻辑(减少客户端错误)
3. 改进数据库故障转移事件的监控警报
EOF
echo "实验报告生成。"
预期结果:
- 故障转移时间:30-45秒
- 峰值错误率:3-4%(低于5%阈值)
- 数据完整性:100%保留
- SLO影响:45秒@4%错误率=1.8秒错误预算消耗
❌ 反模式2:没有事故指挥结构
看起来像什么:
[在Slack上的P0事故中]
工程师A:"数据库宕机了!"
工程师B:"我正在重启它"
工程师C:"等等,我也在尝试重启它"
工程师A:"我们应该回滚部署吗?"
工程师B:"我不知道,也许?"
工程师C:"谁在和客户沟通?"
[15分钟的混乱,无协调行动]
为什么失败:
- 没有单一决策者
- 重复/冲突行动
- 没有利益相关者沟通
- 时间线未记录
- 学习机会丢失
正确方法(事故指挥系统):
事故角色:
1. 事故指挥官(IC)- 做决策,协调
2. 技术领导- 调查根本原因,实施修复
3. 通信领导- 更新利益相关者
4. 记录员- 记录时间线
[事故开始]
IC:"@team P0事故声明。我是IC。@alice技术领导,@bob通信,@charlie记录员"
IC:"@alice当前状态是什么?"
Alice:"数据库主宕机,副本健康。正在调查原因。"
IC:"决定:现在提升副本为主。@alice继续。"
Bob:"发布状态页面更新:正在调查数据库问题。"
Charlie:[记录时间线:T+0: 警报触发,T+2: DB主宕机,T+5: 故障转移启动]
IC:"缓解完成。@alice确认服务健康。"
Alice:"错误率回到0.1%,延迟正常。"
IC:"事故解决。@bob最终状态更新。@charlie为事后分析编制时间线。"
质量检查表
SLO实施
- [ ] SLIs明确定义且可测量
- [ ] 错误预算计算并跟踪
- [ ] Prometheus/监控查询验证
- [ ] 设置警报阈值(避免警报疲劳)
- [ ] 错误预算政策文档化
事故响应
- [ ] 所有关键服务都有运行手册
- [ ] 事故指挥角色定义
- [ ] 通信模板准备
- [ ] 值班轮换可持续(<5页/周)
- [ ] 事后分析流程建立(无责任)
高可用性
- [ ] 多AZ部署验证
- [ ] 自动故障转移测试
- [ ] RTO/RPO文档并验证
- [ ] 灾难恢复每季度测试
- [ ] 混沌实验每月运行
这个SRE技能提供了生产就绪的可靠性工程实践,强调SLOs、事故管理和持续改进。