面試官聽完我的 LivenessProbe 故障復(fù)盤,說:“你比我們 SRE 還細(xì)!”
引言
對(duì)于這種案例,你們的處理思路是怎么樣的呢,是否真正的處理過,如果遇到,你們應(yīng)該怎么處理。
我想大多數(shù)人都沒有遇到過。
最后有相關(guān)的社區(qū)群,有興趣可以加入。
開始
現(xiàn)象:詭異的 Pod 重生輪回
1. 故障表象
? Pod 狀態(tài)異常:通過 kubectl get pods 觀察到 Pod 狀態(tài)在 Running → Terminating → CrashLoopBackOff 之間循環(huán),重啟間隔約 30 秒。
NAME READY STATUS RESTARTS AGE
web-app-0 1/2 CrashLoopBackOff 12 8m
? 日志與事件線索:
應(yīng)用日志(kubectl logs web-app-0 -c app):
ERROR: Database connection timeout - unable to acquire connection from pool
Kubelet 事件(kubectl describe pod web-app-0):
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning Unhealthy 25s kubelet Liveness probe failed: HTTP probe failed:
Get "http://10.1.2.3:8080/health": context deadline exceeded
Normal Killing 25s kubelet Container app failed liveness probe, will be restarted
2. 關(guān)鍵指標(biāo)異常
? 數(shù)據(jù)庫監(jiān)控(Prometheus + Grafana):
活躍數(shù)據(jù)庫連接數(shù)持續(xù)達(dá)到最大值(如 max_connections=100),且存在大量 idle in transaction 連接。
每秒新建連接數(shù)(pg_stat_database.numbackends)在 Pod 重啟時(shí)劇烈波動(dòng)。
? Kubernetes 資源監(jiān)控:
? Pod 的 CPU/Memory 使用率在重啟前無明顯異常,排除資源不足問題。
? 網(wǎng)絡(luò)延遲(kube_pod_container_status_restarts_total)與探針失敗次數(shù)呈正相關(guān)。
根因分析:健康檢查背后的致命陷阱
1. 代碼級(jí)問題解剖
? 健康檢查接口實(shí)現(xiàn)(偽代碼):
# Flask 示例:/health 接口設(shè)計(jì)
@app.route('/health')
def health_check():
# 錯(cuò)誤:直接依賴數(shù)據(jù)庫查詢
result = db.execute("SELECT 1") # 觸發(fā)數(shù)據(jù)庫連接請(qǐng)求
if result:
return "OK", 200
else:
return "Unhealthy", 503
致命缺陷:當(dāng)數(shù)據(jù)庫連接池耗盡時(shí),db.execute() 阻塞等待可用連接,最終超時(shí)返回 503。
? 連接池配置缺陷:
# 應(yīng)用配置(application.yml)
spring:
datasource:
hikari:
maximum-pool-size: 10 # 最大連接數(shù)設(shè)置過低
connection-timeout: 5000 # 5秒超時(shí)(與探針超時(shí)時(shí)間沖突)
? 矛盾點(diǎn):數(shù)據(jù)庫連接超時(shí)(5秒) > LivenessProbe 超時(shí)(1秒),導(dǎo)致探針提前失敗。
2. Kubernetes 探針機(jī)制詳解
? LivenessProbe 工作流程:
# Kubelet 內(nèi)部探針執(zhí)行邏輯(簡(jiǎn)化版)
for {
if time.Now() > lastProbeTime + periodSeconds {
statusCode := httpGet(host:port/path, timeoutSeconds)
if statusCode != 200 {
failureCount++
if failureCount >= failureThreshold {
killContainer()
}
}
}
}
關(guān)鍵參數(shù)沖突:
參數(shù) | 設(shè)置值 | 導(dǎo)致后果 |
| 10 | 每10秒觸發(fā)一次探測(cè),加劇連接池壓力 |
| 1 | 過早判定超時(shí),誤殺健康容器 |
| 3 | 3次失敗即重啟,敏感度過高 |
3. 連接泄漏的數(shù)學(xué)證明
假設(shè)每次 Pod 重啟泄漏 2 個(gè)數(shù)據(jù)庫連接:
? 初始狀態(tài):可用連接數(shù) = 10
? 第1次重啟后:泄漏 2 → 可用連接數(shù) = 8
? 第2次重啟后:泄漏 2 → 可用連接數(shù) = 6
? ...
? 第N次重啟后:可用連接數(shù) = 10 - 2N
當(dāng) 10 - 2N ≤ 0 時(shí),數(shù)據(jù)庫完全不可用,系統(tǒng)進(jìn)入不可恢復(fù)狀態(tài)。
魔幻現(xiàn)實(shí):Kubernetes 的「自毀傾向」
1. 自我放大效應(yīng)
圖片
2. 事件時(shí)間線還原
通過 kubectl get events --field-selector involvedObject.name=web-app-0 --sort-by=.lastTimestamp 可觀察到精確到毫秒級(jí)的故障循環(huán):
Timestamp | Reason | Message |
2023-09-20T14:02:05 | Scheduled | Successfully assigned default/web-app-0 to node-1 |
2023-09-20T14:02:10 | Pulled | Container image already present |
2023-09-20T14:02:15 | Created | Created container app |
2023-09-20T14:02:20 | Started | Started container app |
2023-09-20T14:02:25 | Unhealthy | Liveness probe failed: ... |
2023-09-20T14:02:25 | Killing | Killing container app |
解決方案:從止血到根治
1. 緊急止血措施
? 臨時(shí)擴(kuò)容數(shù)據(jù)庫連接池:
-- PostgreSQL 示例
ALTER SYSTEM SET max_connections = 200;
SELECT pg_reload_conf();
? 禁用 LivenessProbe:
livenessProbe:
enabled: false # 非生產(chǎn)推薦!僅用于臨時(shí)排查
2. 探針配置深度優(yōu)化
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 45 # 必須大于應(yīng)用啟動(dòng)到DB連接就緒的時(shí)間
periodSeconds: 20 # 降低探測(cè)頻率至1/3 QPS
timeoutSeconds: 5 # 覆蓋DB查詢超時(shí)上限
failureThreshold: 5 # 允許更多次失敗
successThreshold: 2 # 避免偶發(fā)成功逃逸
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 15
periodSeconds: 5
failureThreshold: 3
3. 應(yīng)用代碼改造
? 健康檢查分級(jí)設(shè)計(jì):
# LivenessProbe 端點(diǎn):僅檢查進(jìn)程存活
@app.route('/alive')
defliveness():
return"OK", 200
# ReadinessProbe 端點(diǎn):檢查核心依賴
@app.route('/ready')
defreadiness():
try:
# 快速檢查連接池狀態(tài)(不執(zhí)行真實(shí)查詢)
if db.pool.available_connections < 2:
raise Exception("Insufficient connections")
return"Ready", 200
except:
return"Not Ready", 503
? 優(yōu)雅終止實(shí)現(xiàn):
import signal
from flask import Flask
app = Flask(__name__)
def shutdown_handler(signum, frame):
print("Received SIGTERM, closing connections...")
db.pool.dispose() # 主動(dòng)釋放連接池
sys.exit(0)
signal.signal(signal.SIGTERM, shutdown_handler)
4. 連接池治理策略
? 動(dòng)態(tài)擴(kuò)容算法:
// HikariCP 高級(jí)配置
hikariConfig.setMaximumPoolSize(50);
hikariConfig.setMinimumIdle(10);
hikariConfig.setLeakDetectionThreshold(30000); // 30秒泄漏檢測(cè)
hikariConfig.setValidationTimeout(1000); // 1秒驗(yàn)證超時(shí)
? 連接回收機(jī)制:
-- PostgreSQL 自動(dòng)清理 idle 連接
ALTER SYSTEM SET idle_in_transaction_session_timeout = '60s';
防御體系:構(gòu)建韌性健康檢查系統(tǒng)
1. 混沌工程驗(yàn)證
# 使用 chaos-mesh 注入故障
kubectl apply -f - <<EOF
apiVersion: chaos-mesh.org/v1alpha1
kind: NetworkChaos
metadata:
name: db-latency
spec:
action: delay
mode: one
selector:
namespaces:
- database
labelSelectors:
"app": "postgres"
delay:
latency: "2s"
correlation: "100"
jitter: "0ms"
duration: "5m"
EOF
2. 監(jiān)控黃金指標(biāo)
指標(biāo)名稱 | 監(jiān)控目標(biāo) | 告警閾值 |
| 探針執(zhí)行耗時(shí) | > timeoutSeconds |
| 數(shù)據(jù)庫連接使用率 | > 80% 持續(xù)5分鐘 |
| 容器重啟次數(shù) | > 3次/小時(shí) |
3. 自動(dòng)化防護(hù)
# 自動(dòng)調(diào)節(jié)連接池的 Operator 示例
classConnectionPoolScaler:
defreconcile(self):
current_connections = get_db_metric("active_connections")
max_pool_size = current_connections * 2 + 10
patch_deployment(
name="web-app",
patch={"spec": {"template": {"spec": {
"containers": [{
"name": "app",
"env": [{
"name": "DB_POOL_SIZE",
"value": str(max_pool_size)
}]
}]
}}}}
)
深度總結(jié):云原生健康檢查設(shè)計(jì)哲學(xué)
1. 存活探針的「最小化」原則
? 僅檢測(cè)進(jìn)程級(jí)不可恢復(fù)故障(如死鎖、內(nèi)存泄漏)
? 絕對(duì)避免依賴外部服務(wù)(數(shù)據(jù)庫、Redis等)
2. 就緒探針的「真實(shí)性」原則
? 必須反映真實(shí)的業(yè)務(wù)就緒狀態(tài)
? 需要包含核心依賴的健康檢查
3. 優(yōu)雅終止的「確定性」保障
? 必須實(shí)現(xiàn) SIGTERM 處理邏輯
? 關(guān)鍵資源(連接、文件句柄)必須顯式釋放
4. 參數(shù)設(shè)計(jì)的「物理驗(yàn)證」方法
? 通過公式計(jì)算初始參數(shù):
initialDelaySeconds ≥ 應(yīng)用啟動(dòng)時(shí)間 + 依賴初始化時(shí)間 + 安全余量(20%)
timeoutSeconds ≥ 依賴服務(wù)最大超時(shí)時(shí)間 * 1.5
5. 監(jiān)控的「三維視角」覆蓋
? 時(shí)間維度:探針歷史成功率曲線
? 資源維度:連接池使用率趨勢(shì)
? 拓?fù)渚S度:服務(wù)依賴關(guān)系圖譜
通過這種深度技術(shù)解構(gòu),我們不僅解決了當(dāng)期的死亡循環(huán)故障,更重要的是建立了一套防御性編程的完整方法論,將 Kubernetes 的健康檢查機(jī)制從潛在的故障放大器轉(zhuǎn)化為系統(tǒng)穩(wěn)定性的基石。