如何以 SRE 角度改善既有系統

July 20, 2019

cover

要改善既有系統(Legacy System)一直以來都不是一件容易的事情,尤其是當面臨要改動整體架構時,需要耗費的時間和人力成本往往讓老闆無法輕易買單。因此,如何評估既有系統並明確指出為什麼要進行改善,以及新的系統架構要如何設計才能面對更大的挑戰,是非常重要的。本篇文章將以 SRE 課程 中的評估方法作為主軸進行系統評估,結合 從零開始學架構大規模數據處理實戰 兩本書中的知識,總結出一套通用且不會過於複雜的系統改善技巧。

大綱

學習案例介紹

從零開始學架構 中提到的架構設計三原則:合適、簡單、演化。你不需要在一開始就設計一個技術領先於業界的系統,正所謂『將軍難打無兵之仗』,一開始就投入大量的人力與時間在開發一個高可用、高乘載的系統卻沒有半個使用者,是一點意義也沒有的。所以,設計不良的舊有系統(Legacy System)存在於成功的企業中是常見、正常的狀況。畢竟往往正是因為有了這些符合成本且滿足初期使用者需求的舊有系統,才成就了所謂的成功企業。

案例:轉轉咖啡屋

轉轉咖啡屋是一個虛擬的咖啡廳開店平台,提供每一個註冊店家可以在轉轉咖啡屋上開一家屬於自己的咖啡店,並有咖啡配送員幫你將新鮮的咖啡送給消費者。一開始,轉轉咖啡屋做了一個簡單的網站,消費者端有瀏覽店家、咖啡菜單查詢、下單購買、搜尋所有店家菜單等功能。店家端有更新菜單、通知配送員等功能。這個網站使用了單體 + RDBMS 的架構做成如下圖示。過沒多久,轉轉咖啡屋使用者人數一飛沖天,店家數也即將破百。由於搜尋所有店家菜單功能依賴 SQL 查詢關聯式資料庫,效率十分低落,隨著每秒查詢量增加,不但搜尋的速度變慢,還造成 RDBMS 過載,連帶影響到其他功能。

monolith

從單體到微服務

轉轉咖啡屋唯一的工程師在時間壓力下,決定先將搜尋所有店家菜單功能獨立出來,做成第一個微服務,並使用 ElasticSearch 作為搜尋引擎,改善搜尋效率,並寫了一隻同步程式,每分鐘會將更新資料從 RDB 同步到 ElasticSearch。

coffee search service

新的挑戰:更大的規模

在拆分咖啡搜尋服務之後,解決了搜尋效率問題以及降低了搜尋功能與主要功能之間互相影響的程度。當每秒搜尋次數增加時,也可以單獨的擴充咖啡搜尋服務來應付。

一年過去了,轉轉咖啡屋的店家數量破萬,使用者人數更不用說。由於穩定獲利,轉轉咖啡屋聘請了更多的工程師,也成立了獨立的 SRE 團隊。

此時,咖啡搜尋服務開始出現了一些客戶抱怨,例如:

原來,由於個人咖啡店的特色是每個人都可以少量販售,隨時修改咖啡菜單和可販售數量。然而資料是由 RDB 經由中間程式同步到 ElasticSearch 的,隨著店家數量變多,資料量變大,中間同步的時間也漸漸地不斷拉長,導致搜尋結果資訊落差。這些資訊落差,已經嚴重的影響到消費者體驗了。

對於轉轉咖啡屋的 SRE 團隊來說,咖啡搜尋服務這個既有系統,該如何去分析並解決這個問題呢?

系統評估

好的,接下來終於可以進入我們今天的主題了。第一步是要對系統進行評估,評估的方法採用 SRE 服務水平指標(Service Level Indicators, SLIs)的理論,藉由找出關鍵 SLIs 指標,來數據化使用者對於系統的滿意程度。根據 The properties of good SLI metrics 裡面提到,一個好的 SLI 指標必須真實且直接反應出使用者感受。意即我們可以從一個數值區間為 0%~100% 的 SLI 指標中得知,目前系統某個操作的性能與狀態,是否造成使用者不好的體驗,影響程度與範圍多大。甚至我們可以從數字中換算出客服處理時間,服務水平指標 越差,代表公司必須付出更多的客服成本,且降低使用者對產品品質的信心。

有了這些數據,我們就可以在改善項目成本與不進行改善所付出的代價之間進行取捨。

通常一個服務根據功能項目多寡和性質,可以定義出多種不同的 SLIs 指標。找出可供改善系統參考的 SLIs 並不容易,在這邊分享一套我自己的做法,供大家參考。

1. 畫出數據流

首先,我們要從既有系統當中,辨識出 數據流。數據流是新數據進入到系統,經過系統處理到儲存的路徑。簡單來說,我們可以從資料最終的儲存位置反推回去到資料來源,即是一個數據流。如果數據最終的流動方向不是系統資料存儲,這邊我們就不把它當成一個數據流。例如,從資料庫調閱店家簡介回傳給使用者,由於店家簡介這個數據在系統中的存儲內容並沒有變更,故不算在我們的標記範圍(備註:如果這個操作產生了一筆使用者行為紀錄,並儲存在系統某處,就算是一個數據流)。一個簡單的數據流示意圖如下:

data flow

回到前面提到的咖啡搜尋服務範例,更新咖啡菜單這個動作,會產生兩條數據流。一條紅色,由咖啡店長更新菜單產生,最終存儲至 RDB。另一條藍色,由資料同步程式拉取 RDB,並轉換格式存儲於 ElasticSearch。

coffee search service with data flow marked

2. 標示批處理,流處理

接著,我們需要做的是,標註數據處理的型態,是批處理(Batching Processing)還是流處理(Streaming Processing)。要分辨數據處理的類型我們可以從輸入的數據類型來判斷。

再回到前面提到的咖啡搜尋服務範例,我們可以依照前面的規則標示紅、藍兩條數據流是經過了批處理、或是流處理。

streaming or batching

由於咖啡菜單更新這個操作是即時的,一筆一筆進行的,我們可以把它歸類在 流處理。而咖啡菜單同步至 ElasticSearch 的數據流,每次處理的是 1 分鐘前到現在的更新資料,具有明確的數據範圍,我們把它歸類在 批處理

3. 定義服務水平指標

sli principles

服務水平指標(SLI)必須符合這個公式,SLI = 好的事件/整體合法事件,會是一個 0%~100% 的數值。

在開始定義服務水平指標(SLI)之前,我們先將 咖啡搜尋服務 的微服務邊界劃分清楚。以下綠色區塊的部分便是 咖啡搜尋服務 的守備範圍。有了明確的邊界,就可以列舉出邊界內的系統操作,並針對這些操作定義能反應使用者感受的指標,也就是 SLI。

boundary of search service

為了節省篇幅,這邊簡單列出兩個 咖啡搜尋服務 的基本操作情境:

  1. 查詢咖啡商品
  2. 更新咖啡商品數據

operations of search service

接著我們要挑選適當的 SLI 分別放到這兩個操作當中。幸好,我們已經有現成的工具可以用了,The SLI Menu。Thanks, Google.

The SLI Menu

The SLI Menu 是一份 SLI 的參考清單,幾乎包含了大部分的使用情境,請大家安心使用。SLI 參考清單將系統操作情境分成三大類,每個分類底下都有幾個建議使用的 SLI 範本,完整清單如下:

  1. 請求/回應(Request/Response)
    • 可用性指標(Availability)
    • 回應時間指標(Latency)
    • 回應品質指標(Quality)
  2. 數據處理(Data Processing)
    • 覆蓋率指標(Coverage)
    • 正確性指標(Correctness)
    • 新鮮度指標(Freshness)
    • 吞吐量指標(Throughput)
  3. 資料存儲(Storage)
    • 持久性指標(Durability)

在進入 SLI 細節前,我們先替 咖啡搜尋服務 的兩個操作情境做 SLI 分類。這時候前面分析的數據流就派上用場了,更新咖啡商品數據 做的是數據批處理,直接分類在 2. 數據處理 情境。而 查詢咖啡商品 則是典型的 1. 請求/回應 情境(這邊可以使用刪去法來進行選擇,因為不屬於 2. 數據處理 也不屬於 3. 資料存儲)。適合 3. 資料存儲 SLI 的情境目前還沒遇到過,有機會以後再另外做分享,AWS S3 服務是一個例子。

深入 查詢咖啡商品 情境對應的三個指標:

一開始不需要特別為如何選定適合的指標而煩惱,先憑經驗和感覺來選擇,如果日後發現有不足之處,再補上即可。

查詢咖啡商品 情境目前沒有回應降級結果的設計,故不考慮 回應品質指標。而與使用者體驗有關的狀況為 API 回應的 HTTP Code 為 200(成功) 或是 500(系統錯誤)可以納入 可用性指標。如果 API 回應的速度過慢也會令使用者感到不適,因此也將 API response time 納入 回應時間指標。完整描述參照下圖。

search sli details

量測位置與方法也是非常重要的部分,當 SLI 無法反應真實情形時,必須重新考慮 SLI 量測位置。在這邊我們使用常見的 Loadbalancer 數據。

深入 更新咖啡商品數據 情境對應的四個指標:

更新咖啡商品數據 情境的數據處理僅僅是單純地將 RDB 資料轉換成 ElasticSearch Doc 形式,因此針對複雜數據處理的 正確性指標吞吐量指標 先不考慮。覆蓋率指標 或許可以反應資料轉換時格式錯誤的程度,可考慮。為了節省文章篇幅,在這裏選用與前面提到的顧客抱怨相關的 新鮮度指標。新鮮度指標依照 流處理批處理 有不同的建議做法。參照如下:

freshness sli suggestion

在上一章節我們已經標示出 更新咖啡商品數據 情境是 批處理。根據上圖的概念,可以實作如下:

freshness sli implementation

完整描述參照下圖。

dataupdate sli details

不新鮮的判定先暫時設為 5 分鐘,待日後觀察調整。

定義 SLI 還有許多考量點例如量測視窗大小、量測工具的選擇和 SLI Refinement 沒有包含在本篇文章講解範圍內,但是對於評估系統非常有幫助,學習更多

4. 上線觀察與校正

sli with user

有了 SLI,現在我們可以使用量化的方式觀察系統的滿意程度。但是我們還不知道 SLI 數值與實際使用者的影響程度之間的關聯。

Freshness SLI = 99% 代表什麼意思?

有沒有可能設定的資料新鮮度條件為 5 分鐘,實際上每次取樣結果都是 4 分半,計算出來的 SLI = 100%。而使用者仍然不開心,這時候就要下修條件,直到 SLI 可以反應真實使用體驗為止。同理 Latency SLI 的 500ms 條件是否太長或太短,也是需要收集使用者反饋再進行調整。

收集使用者反饋(Feedback)可以從客服部門的統計資料取得,或是在 client 端加上回報問題的按鈕,讓內部測試人員操作也是不錯的辦法。無論如何,提升 SLI 與使用者感受的連動性,是非常重要的。

5. 設定目標

盤點一下目前為止我們有的 SLI 指標,以及 30 天觀測結果(假設我們已經做了):

第一次定義 服務水平目標(Service Level Objectives)時,我們可以拿過去的一個月的數據作為基準,再打一點折。

保守型 SLOs,維持現狀就是你的目標。適合運行穩定、較少客服處理的情境。下個月只要能達到這個數字,代表一切相安無事。

改善型 SLOs,提升數字是你的目標。提升數字意味著必須針對系統進行改善,為了在下個月能達成目標。視系統複雜程度而定,通常不建議在短時間內設立很大的目標,例如:80% -> 95%。這樣一來為了達成目標,在接下來的 30 天就必須投入大量的人力。如果一直無法達成目標,SLO 形同虛設。

設立 SLO 的好處除了可以幫助進行改善系統的決策,也提供了下個月維運的 錯誤預算(Error Budget)

錯誤預算(Error Budget) 讓你可以在已經達標的系統上,有犯錯的空間以進行機器維運、部署新版本、或異常演練等工作。

Error Budget = 目前 SLI - SLO (例:Coffe Search Latency Error Budget = 99% - 96% = 3%)

Error Budget 也可以用來評估系統維運風險,當你的 Error Budget 已經等於 0% 或小於 0% 時。在接下來的日子裡,你很有可能即將面臨接不完的電話,和不斷流失的客戶。

系統改善設計

服務水平目標(SLI)量化了系統當前的狀態。服務水平目標(SLO)讓我們有更明確的方法在改善與不改善之間做權衡判斷。接下來我們繼續使用 SLI 種類的特性來選用系統改善的做法。

1. SLI 與工具選用

還記得 The SLI Menu 嗎?要改善的 SLI 都有屬於自己的類型。例如,請求/回應回應時間指標

如果想要提升的是 回應時間指標,可以參考 從零開始學架構高性能架構模式

如果想要提升的是 可用性指標,可以參考 從零開始學架構高可用架構模式

數據處理類型的 SLI,則可以參考 工作流設計模式(Workflow Pattern)

工作流設計模式 有以下模式:

workflow patterns

2. 範例:改善 Freshness SLI

我們重新來檢視一下 更新咖啡商品數據 和其相關的數據流。

re-dataflow

可以發現相同的數據來源,卻分成了兩條不同的工作流。有沒有可能使用 工作流設計模式 的其中之一,將這兩條數據流合併呢?例如,使用 Copier Pattern

copier design

採用 Copier Pattern 後,會發現資料來源統一了,但是多了一個 Copier 節點。Copier 節點要如何去實作,也是一個值得探討的問題。Copier 節點必須具備單一輸入扇形輸出(fan out)的特性,聽起來是不是很像單一來源的 發布/訂閱(Pub/Sub) 模式呢?如果要實作 Pub/Sub,那選擇就很多了,如 GCP Cloud Pub/Sub, Apache Kafka, AWS SNS + SQS, Redis 等等。

想必大家在實作方面都有自己獨門的見解和建議,在這裡我就不講出來讓人見笑了。本篇文章的主軸還是在如何使用 SRE 方法引導出系統改善的方向。

3. 驗收成果

經過了上一章節的架構調整,我們可以觀察原本定義好的 Freshness SLI 數值變化來驗收成果。

如果,因為架構調整而使原本的 SLI 無法收集到資料,那可能要思考看看是不是 SLI 定義或是量測方式有需要調整的部分。以 更新咖啡商品數據 情境為例,中間做數據處理的程式邏輯仍然是轉換資料格式,轉換完成後寫入一樣的完成時間到一樣的 log 位置,即使接收數據的方式可能改變(SQL 結果 -> Message)。但是被量測的部分並沒有受到影響。

當然 SLI 也並不是一直不變的。我們應該遵循一次只改動一個地方的原則來比較成果。修改 SLI 時不改動系統,改動系統時不修改 SLI。如此才能得到可以被比較的前後結果。

結語

從 SRE 的觀點來操作系統改善這件事,有助於釐清改善的關鍵點。同時避免依賴經驗主義導致過度設計的陷阱。

另一方面,改善的結果也可以很明確地看出成果。甚至在改善的過程中,也不斷地觀察著 SLI 變化,對於複雜系統需要一步一步改善的過程,也可以持續地得到回饋。或許,我們再也不需要摸黑前進了吧。

Send Me Comments