深色模式
混沌与稳定性关系
摘要:稳定性的敌人是"从未被验证过的假设":相信副本够、相信超时生效、相信降级可用。本文把这些假设转化为可验证的故障模式清单,并说明如何用实验逐个击破。
适用环境
bash
# 先梳理拓扑,找出所有"假设成立"的地方
kubectl get svc -A | head -20
kubectl get deploy -A -o custom-columns='NS:.metadata.namespace,NAME:.metadata.name,REPLICAS:.spec.replicas' | head -201
2
3
2
3
操作步骤
第 1 步:列出四类常见脆弱假设
bash
cat > assumptions.md <<'EOF'
| # | 假设 | 对应实验 |
| --- | --- | --- |
| 1 | 副本冗余足够,杀一个不影响 | Pod Kill |
| 2 | 下游慢时上游有超时保护 | 依赖延迟注入 |
| 3 | 弱网下客户端可重试成功 | 网络丢包注入 |
| 4 | 资源打满时仍能优雅降级 | CPU/内存压力注入 |
EOF1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
第 2 步:找出真正的单点
bash
# 副本数为 1 的工作负载就是潜在单点
kubectl get deploy -A -o json | jq -r '.items[] | select(.spec.replicas<2) | "\(.metadata.namespace)/\(.metadata.name) replicas=\(.spec.replicas)"'
# 无 PDB 的工作负载在驱逐时可能同时下线
kubectl get pdb -A1
2
3
4
5
2
3
4
5
第 3 步:验证超时与重试是否真的配置
yaml
# 反例:没有 timeout 的调用会在下游慢时拖垮上游
# 正例(以 Envoy/Istio 为例):
route:
timeout: 2s
retryPolicy:
retryOn: 5xx,reset
numRetries: 2
perTryTimeout: 1s1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
bash
# 检查服务网格中是否配置了超时
kubectl get virtualservice -A -o yaml | grep -n 'timeout' | head1
2
2
第 4 步:把假设转换成实验并排序
bash
# 按"发生概率 × 影响面"排序,先做最可能且最痛的
cat > backlog.md <<'EOF'
| 优先级 | 实验 | 概率 | 影响 |
| --- | --- | --- | --- |
| P0 | 依赖服务延迟 500ms | 高 | 高 |
| P1 | 单 Pod 被杀 | 高 | 中 |
| P2 | 节点宕机 | 低 | 高 |
EOF1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
第 5 步:把结论变成稳定性改造项
bash
# 每次实验输出一条可执行的改进项
cat >> backlog.md <<'EOF'
## 改进项
- [ ] pay 调用 order 未设超时 → 补 2s 超时 + 2 次重试
- [ ] demo 副本为 1 → 调整为 3 并补 PDB
EOF1
2
3
4
5
6
7
2
3
4
5
6
7
验证
bash
# 1. 单点清单已产出
kubectl get deploy -A -o json | jq -r '.items[] | select(.spec.replicas<2) | .metadata.name' | wc -l
# 2. 实验清单覆盖四类假设
grep -c '|' assumptions.md
# 3. 每项假设都有对应结论或改进项
grep -c '\- \[ \]' backlog.md1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
常见坑
只做"能做的实验"不做"该做的实验"
Pod Kill 最容易做,但真正的风险往往在依赖超时与容量上。按风险排序而非按实现难度排序。
实验结论不落到改造
发现脆弱点但不修,等于花钱做体检不吃药。每个不成立假设都要生成一条带负责人的改进项。
用混沌实验掩盖容量不足
反复注入压力却不扩容,会让团队习惯"能扛住"的错觉。实验是发现问题的手段,容量问题必须正视。