閒聊設計 Slo 與 Sli

最近在閱讀 Implementing Service Level Objectives 這本書,作者 Alex 參與過 The Site Reliability Workbook 某些章節的寫作,所以很多概念跟之前幾本 SRE 相關書籍是有關連的。
這文章想介紹的是其中的第 12 章 A Worked Example,以及將學到的概念用在 OpenTelemetry Demo 的電商系統上。

A Worked Example

這是書中的零售網站架構,讓我來把這圖做個劃分
之前的章節一直提到 SLO 應該作為用戶旅程的工具。
所以這裡提出了一個核心觀點:SLO 應該基於用戶旅程來定義,這樣可以更好地對齊技術目標與業務需求。 將用戶分為三類:
外部客戶(如網站用戶)
其他服務作為用戶(如內部依賴的微服務)
內部用戶(如公司員工)
外部客戶:瀏覽和搜索產品
用戶需求:客戶需要能夠快速瀏覽和搜索產品。
相關組件:包括 CDN、Web 應用、產品數據庫、緩存、庫存微服務等。
示例 SLO:
首頁加載延遲:99.9% 的請求在 2,000 毫秒內返回 2xx、3xx 或 4xx 狀態碼。
搜索結果:99.8% 的搜索請求在 4,000 毫秒內返回 2xx 或 3xx 狀態碼。
關鍵觀點:
SLO 應該考慮用戶的耐心,例如用戶對搜索結果的等待容忍度可能高於普通頁面加載。
需要平衡性能與用戶體驗。
其他服務作為用戶:購買產品
用戶需求:支付流程需要快速且可靠,因為這直接影響收入。
相關組件:包括支付微服務、外部支付供應商等。
示例 SLO:
結賬成功率:99.99% 的結賬請求在首次嘗試時成功。
整體支付工作流程:99.93% 的結賬請求在整個流程中首次嘗試成功。
關鍵觀點:
當內部服務依賴外部供應商時,內部 SLO 必須考慮供應商的 SLA。
需要計算多個目標百分比的相互影響,並設計適當的重試邏輯。
內部用戶
用戶需求:內部工具(如數據分析應用和 Wiki)需要穩定可靠,否則會影響員工效率。
相關組件:包括數據處理管道、內部應用、內部 Wiki 等。
示例 SLO:
數據導出:90% 的數據導出嘗試在一個月內成功。
內部 Wiki 可用性:工作時間內可用性達到 99.9%。
關鍵觀點:
即使是內部工具,也需要可靠性目標,否則會影響員工的工作滿意度。
簡單的 SLO(如「是否可用」)對於第三方或開源軟體可能已足夠。
因此我們能把整個系統架構按照上面的案例畫分成這三區。

每個我們在更細緻的探索它們應用案例相關的 SLO 與 SLI
外部客戶
瀏覽和搜索產品
首頁加載延遲SLI:
HTTP 響應時間是否小於 2000 ms。
HTTP 響應狀態碼是否為 2xx、3xx 或 4xx。
SLO︰99.9% 的請求應在 2000 毫秒內返回成功狀態。
(
sum(rate(http_request_duration_seconds_bucket{le="2", status=~"2..|3..
"}[5m]))
/
sum(rate(http_request_duration_seconds_count[5m]))
) * 100
搜索結果
SLI:
搜索請求是否在 4000 ms內完成。
搜索請求是否返回 2xx 或 3xx。
SLO:
99.8% 的搜索請求應在 4000 ms內返回成功狀態。
# 計算符合 SLO 的成功率
(
sum(rate(search_request_duration_seconds_bucket{le="4", status=~"2..|3.."}[5m]))
/
sum(rate(search_request_duration_seconds_count[5m]))
) * 100
為什麼明明圈起來的還有 Cache 和 Database,SLO 這裡卻沒用到呢?
SLI 的核心目標是反映用戶體驗:
SLI 的設計是為了量化用戶旅程的成功與否,例如「首頁是否快速加載」或「搜索結果是否快速返回」。這些是用戶直接感受到的指標。
DB 和 Cache 是支持這些用戶操作的後端組件,對用戶來說是透明的。因此,我們通常不會直接將它們作為 SLI,而是通過高層次的指標(如 HTTP 響應時間)間接反映它們的性能。
內部組件的健康狀況通常通過內部監控來衡量:
DB 和 Cache 的性能(例如查詢延遲、cache hit rate等)可以作為內部的技術指標進行監控,但它們更適合作為服務可靠性的支持性指標,而不是直接的 SLI。
如果 DB 或 Cache 出現問題,這些問題會反映在高層次的用戶操作(如頁面加載時間或搜索結果返回時間)中。
避免過於細化 SLI:
如果將每個內部組件都單獨定義 SLI,會導致指標過於分散,難以管理和解釋。
我們的目標是關注用戶價值,而不是每個內部組件的細節。
但我們可以設計 Dashboard link ,讓高階指標儀表板、連結至相關的細顆粒度的系統組件儀表板,協助分析。
------------------------------------------------------- | 高層次指標(SLO):首頁加載時間 | | [首頁加載時間:99.9% 在 2000ms 內完成] | ------------------------------------------------------- | 相關內部指標(SLI): | | - DB 查詢延遲(99% 在 100ms 內完成) | | - Cache 命中率(95%) | | - 外部 API 響應時間(99% 在 200ms 內完成) | -------------------------------------------------------回呼一下小弟自己的出版內容OpenTelemetry 入門指南 第 9 章中曾提到,儀表板的設計,而 SLO 這樣的分層設計概念也是一樣的。
整個支付流程(包括結賬、支付微服務、外部支付供應商)成功完成的比例。
支付流程成功率 = 支付微服務成功率 × 外部支付 API 成功率
結賬成功率
結賬成功率是指結賬請求中返回成功狀態(如 HTTP 2xx)的比例。
支付微服務
SLI:
支付請求是否在 1000 ms 內完成並返回成功狀態碼(2xx)。
支付請求是否在首次嘗試時成功。
SLO:
99.99% 的支付請求應在 1000 ms 內成功完成。
99.95% 的支付請求應在整個支付流程中成功。
外部供應商 API
SLI:
外部 API 請求是否在 2000 ms 內返回成功狀態碼(2xx 或 3xx)。
外部 API 可用性是否達到指定 SLA。
SLO:
99.9% 的外部 API 請求應在 2000 ms 內返回成功狀態。
外部 API 每月可用性應達到 99.95%。
# 計算支付流程成功率
(
sum(rate(payment_service_requests_total{status="success"}[5m]))
/
sum(rate(payment_service_requests_total[5m]))
)
*
(
sum(rate(external_payment_api_requests_total{status="success"}[5m]))
/
sum(rate(external_payment_api_requests_total[5m]))
)
為什麼支付這裡需要多個 SLI?
系統的複雜性
現代系統(如微服務架構)涉及多個組件和依賴(如結賬微服務、支付微服務、外部支付供應商等)。單一的 SLI 無法捕捉所有這些組件的行為和性能。不同層面的健康狀態
每個組件的可靠性(如資料庫、API、Cache、負載均衡器等)都可能影響整體的用戶體驗。需要針對每個層面定義單獨的 SLI,才能精確定位問題。從用戶體驗到內部依賴的監控
用戶體驗層面:如支付流程的成功率。
內部依賴層面:如支付微服務的延遲、外部支付 API 的可用性、database 查詢的成功率等。
基礎設施層面:如負載均衡器的響應時間、Cache hit rate等。
只有當這些低層級的 SLI 都達到預期時,高層級的 SLO 才可能被滿足。
SLO 和多個 SLI 的關係
1. 單一 SLO,依賴多個 SLI
一個高層級的 SLO(如支付流程成功率 99.93%)通常依賴多個 SLI 的表現。例如:
支付流程成功率 = 支付微服務成功率 × 外部支付 API 成功率。
如果任意一個 SLI 表現不佳,整個支付流程的 SLO 就可能無法達成。
2. 多個 SLO,分別追蹤不同維度
某些情況下,您可能需要為不同的關鍵指標設置單獨的 SLO。例如:
支付流程成功率 SLO:99.93%。
支付微服務延遲 SLO:95% 的請求延遲小於 1000 毫秒。
外部支付 API 可用性 SLO:99.9%。
這樣可以更清晰地定義每個組件的責任範圍。
如何有效地管理多個 SLI?
分層管理
高層級 SLI:直接影響用戶體驗的指標,例如支付流程成功率。
低層級 SLI:內部系統的性能指標,例如支付微服務的延遲、外部支付 API 的可用性等。
自動化監控與告警 使用工具(如 Prometheus 和 Grafana)來自動化監控多個 SLI,並設置告警:
當高層級 SLI(如支付流程成功率)下降時,觸發告警。
當低層級 SLI(如 API 延遲)異常時,觸發更具體的告警。
關聯分析 在高層級 SLI 出現問題時,通過關聯分析低層級 SLI,快速定位問題源頭。
內部使用者
內部使用者的主要操作流程可以分為以下幾個階段:
資料查詢與處理(透過 Microservice D 和 Reporting 系統)
報表生成與查看(Reporting 系統)
資料查詢與處理
用戶行為: 使用者透過業務應用發送查詢請求,Microservice D 從資料庫中提取資料並進行處理,返回結果。
SLI:查詢所需報表與資料成功率
定義:查詢請求成功返回結果的比例。
測量方式:
成功查詢請求數 / 總查詢請求數SLO:99.8% 的查詢請求需成功
如果太常查詢不到所需的即時資料也有可能是 ETL 的前半段出現問題。
SLI:查詢延遲
定義:從用戶發送查詢請求到結果返回的時間。
測量方式:
查詢完成時間 - 查詢請求時間SLO:
P80: 80% 的查詢需在 700ms 內完成。
P99: 99% 的查詢需在 1.5s 內完成。
內部用戶的範疇是否需要再細分?
例如,內部用戶可以分為「技術團隊」(如開發、運維)和「非技術團隊」(如業務部門)。這兩者的需求可能不同,例如:* 技術團隊更關注內部系統的可用性(如 CI/CD 管道、監控工具)。
* 非技術團隊更關注業務支持工具的穩定性(如報表系統、CRM 系統)。
OpenTelemetry Demo 專案
Demo 專案剛好也是一個電商網站,其系統架構更加複雜一些。

先將用戶分類
訪客用戶 (Guest User)
購物用戶 (Shopping User)
支付用戶 (Payment User)
用戶類型與場景
訪客用戶 (Guest User)
未登入的用戶,瀏覽產品、查看推薦商品。
- 主要行為:瀏覽、產品搜索、推薦商品點擊。
購物用戶 (Shopping User)
正在進行購物的用戶,將商品加入購物車,進行結賬。
主要行為:加入購物車、結賬、選擇運送方式。
支付用戶 (Payment User)
完成購物並進行支付的用戶。
主要行為:提供支付信息、完成支付、收到訂單確認。
就能再根據這些場景去了解對應到哪些內部系統。
用戶場景
產品瀏覽場景
用戶進入網站或應用,瀏覽產品目錄,查看產品詳情,並獲得推薦商品。
涉及的服務:
frontend、productcatalogservice、recommendationservice。
購物車場景
用戶將商品加入購物車,並檢視購物車內容。
涉及的服務:
frontend、cartservice、currencyservice。
結賬場景
用戶提交購物車,進行結賬,選擇運送方式,並確認訂單。
涉及的服務:
checkoutservice、cartservice、quoteservice、shippingservice、frauddetectionservice。
支付場景
用戶提供支付信息,完成支付,並收到訂單確認郵件。
涉及的服務:
paymentservice、emailservice、accountingservice。
設計用戶旅程的 SLO 與 SLI
(1) 產品瀏覽場景
目標 (SLO):
產品瀏覽頁面加載成功率 ≥ 99.95%
推薦商品 API 響應延遲 ≤ 200ms (P95)
相關 SLI:
成功率:
frontend調用productcatalogservice和recommendationservice的成功請求數 / 總請求數
PromQL:
sum(rate(http_requests_total{service="frontend", status="2xx"}[5m]))
/
sum(rate(http_requests_total{service="frontend"}[5m]))
延遲:
recommendationservice的 P95 響應時間
PromQL:
histogram_quantile(0.95, rate(http_request_duration_seconds_bucket{service="recommendationservice"}[5m]))
(2) 購物車場景
目標 (SLO):
加入購物車成功率 ≥ 99.9%
購物車頁面加載延遲 ≤ 300ms (P95)
相關 SLI:
成功率:
cartservice的成功請求數 / 總請求數
PromQL:
sum(rate(grpc_requests_total{service="cartservice", status="success"}[5m]))
/
sum(rate(grpc_requests_total{service="cartservice"}[5m]))
延遲:
cartservice的 P95 響應時間
PromQL:
histogram_quantile(0.95, rate(grpc_request_duration_seconds_bucket{service="cartservice"}[5m]))
(3) 結賬場景
目標 (SLO):
結賬成功率 ≥ 99.93%
結賬流程完成時間 ≤ 1秒 (P95)
相關 SLI:
成功率:
checkoutservice的成功請求數 / 總請求數
PromQL:
sum(rate(grpc_requests_total{service="checkoutservice", status="success"}[5m]))
/
sum(rate(grpc_requests_total{service="checkoutservice"}[5m]))
延遲:
checkoutservice的 P95 響應時間
PromQL:
histogram_quantile(0.95, rate(grpc_request_duration_seconds_bucket{service="checkoutservice"}[5m]))
(4) 支付場景
目標 (SLO):
支付成功率 ≥ 99.9%
訂單確認郵件發送成功率 ≥ 99.8%
相關 SLI:
支付成功率:
paymentservice的成功請求數 / 總請求數
PromQL:
sum(rate(grpc_requests_total{service="paymentservice", status="success"}[5m]))
/
sum(rate(grpc_requests_total{service="paymentservice"}[5m]))
郵件發送成功率:
emailservice的成功請求數 / 總請求數
PromQL:
sum(rate(grpc_requests_total{service="emailservice", status="success"}[5m]))
/
sum(rate(grpc_requests_total{service="emailservice"}[5m]))
透過將使用者分類,給出業務場景,就能對照到系統架構與組件的依賴關係圖中,去設計出適合的使用者相關的 SLO。
總結
設計用戶旅程的 SLO 與 SLI 主要基於以下原則:
核心行為:針對用戶的關鍵操作(如瀏覽、購物、支付)設計 SLI。
多層次指標:從成功率、延遲和吞吐量等多角度衡量系統性能。
場景分解:根據不同用戶場景拆分指標,確保每個場景都有清晰的目標 (SLO)。
這樣的設計能幫助您清楚了解系統在不同用戶場景下的表現,並快速定位問題來源。








