關於街口線上服務監控的那些小事

「保持系統的高可用及高穩定性以支持街口量級的成長」

Dopiz Liu
OnedaySoftware
12 min readNov 25, 2021

--

街口近年來的成長速度飛快,截至目前為止會員數已增長至超過 500 萬人。為了提供眾多用戶完善的金融服務,街口不斷地拓展新的業務需求,因此內部的基礎設施及服務數量不斷地增加、甚至與第三方合作的功能串接也日益增長。為了支撐這些服務,我們必須時刻保持系統的可用性及穩定性,所以隨時監控各個服務這件事就變得越趨重要。

而在達成穩定性建設目標下,有幾項時間指標可做為參考:

  • 平均無故障時間 (Mean Time To Failure, MTTF):各故障 T1 時間的平均值,服務均正常可使用的時間長。
  • 平均修復時間 (Mean Time To Recovery, MTTR):各故障 T2 + T3 總和的平均值,從發現服務異常到開始進行修復再到修復完成、服務恢復可用的時間長。
  • 平均故障間隔 (Mean Time Between Failure, MTBF):各故障 T2 + T3 + T1 總和的平均值,即是每個故障的間隔時間。
▲ MTTF / MTTR / MTBF

在這些指標中,會希望將平均修復時間 (MTTR) 縮至最短、平均故障間隔 (MTBF) 拉長,進而提升服務的高可用性。而為了達成前述目標,我們建立了許多監控的機制來觀測服務的健康程度,避免因為感知的速度太慢造成功能不可用的時長過長、甚至造成公司資損等情形發生。

怎麼樣算是良好的監控機制呢?

我們認為監控的方式有非常多種,但良好的監控機制應該能夠依序釐清以下幾個問題:

  • 現在服務是否有問題?

— e.g. 支付成功率下降、訂單建立數量減少、銀行綁定失敗率升高

  • 是哪裡發生了問題?

— e.g. 訂單建立 API 的 Response Time 過高、對外串接銀行 API 大量 HTTP Status Code 500 發生

  • 是發生了什麼問題?

— e.g. 資料庫負載過大、上游業務的 Thread Pool 已滿,導致處理 Request 的性能下降

之後也會跟大家聊聊有關監控體系與穩定性建設的內容,這篇主要就針對目前街口測試團隊執行 Health Check 的幾種方式來作分享。

要達成 Health Check 的做法非常多樣,從最基礎的透過 command 執行 script (e.g. ping) 來確認 host 是否存活、確認與 Server 是否能正確建立 TCP socket;到程式架構中 framework 或是 Docker、Nginx 提供的 Health Check 機制等等,都有一定的效果。

在街口,除了 Infra 及 RD 團隊內各自使用的工具以外,SDET 在平常的監控場景主要分為三種 — 硬體監控、業務監控、服務監控,而對應所使用的工具分別為:

  • Grafana
  • Kibana
  • Production URL Health Check

以下會簡述我們使用 Grafana 與 Kibana 的方式,以及實作 Production URL Health Check 的方法及原因。

Grafana

Grafana 是一套開源的分析與監控解決方案,其應用非常多。在我們的應用場域就包含了機器監控、壓力測試數據觀測等。而在監控場景下主要使用它來針對 Service 的硬體指標進行監控,包含最基礎的 CPU、Memory、Disk 使用率,以及 Network Traffic 流量、Socket Connection 連線數等數據。

並且透過硬體規格以及平時流量的經驗法則來設定各個指標的閾值,當有機器的某項指標超過我們所設定的閾值時,就會觸發 Alerting Rule 進而透過 Slack 以及 LINE Notify 通知相關人員進行處理。

▲ Grafana Alerting Message in Slack

Kibana

Kibana 中記錄並呈現了大量的 log 資訊,透過它可以分析、搜尋、視覺化 Elasticsearch 中的資料。而我們透過 filter 針對特定的日誌內容來間接觀測業務指標的數據,例如:購物節活動的每日參加人數、實時的交易成功筆數、AccountLink 逾時紀錄等等。

除了建立 metric/log 的 Dashboard 直接監控實時數據外,同樣的我們也會建立多種業務情境的 filter 及預期的閾值到 elastalert rules 中來進行業務指標的監控及通知。舉例來說,當 15 分鐘內透過 App 進入並瀏覽街享券頁面的用戶請求少於 1 次時,就會透過 Slack 通知,依此來查看服務是否存在任何異常而導致平均用戶流量下降。

▲ Kibana Dashboard Example
▲ Elastalert Notification Message in Slack

Production URL Health Check

最後一項則是監控服務指標的部分,我們建立了一套簡易的機制對這些 Service 的 Health Path 或是負擔最小的 API Path 定期進行 Request 以確保其存活;以及街口 App 內所能看得到的 Banner、各個行銷宣傳網頁甚至是從街口所導流出去的第三方網頁等,都將其加入列表中定期進行監控,以便發生問題時,我們能夠快速的將服務、網頁下架止血或是通報外部修復,避免使用者體驗不佳。

而以下會介紹組成該機制所使用到的工具:

✔ ️Google Sheets

為什麼選擇使用 Google Sheets 作為儲存監控列表的工具?

起初其實只有針對特定幾個非常重要的 Service 進行監控,於是我們將這些 URL Path 直接寫死在 Code 之中。但很明顯地,當開始有新增、修改或是暫時 Skip 特定監控的需求時,每次都要 Push Code 就會變得非常麻煩,並且一定要透過特定的 VPN 管道才能夠進行處理。

所以後來我們考慮了資料庫及 Google Sheets 兩種方案,衡量下選擇 Google Sheets 的原因是因為希望非技術人員也能夠快速地新增、查看目前進行監控中的服務,並且表格的特性也可以將其轉為 .xlsx 或 .csv 檔案提供給 Test Script 作為測資的來源。

實際的使用方式可以參考 Google Developers 的文件,主要就是在 Google Cloud Platform (GCP) 建立一個新的 Project,並且啟用 Google Sheets API 的服務、建立一組憑證金鑰 (credentials) 以提供後續撰寫的 Script 使用。

▲ Google Sheets Data Example

✔ ️Pytest

選擇 Pytest 的原因主要是基於我們 API 自動化測試的框架選型就是採用該方案,能夠復用舊有的 Code 降低成本是我們首要的目標。關於 API 自動化測試框架的這個題目,之後會專門寫一篇文章與大家分享,有興趣的話可以先參考之前發布的文章 — 街口支付軟體測試自動化方案選型

先列出幾個在這次實作中的思路給大家參考,若有推薦更好的方式也請不吝賜教!

  • conftest.py

有使用過 pytest 框架的夥伴應該都清楚 fixture 與 conftest.py 作為 setup/teardown 的使用方式。而在實作中,Test Script 執行之前會先做一件事情:

「透過 Client API 取得放在 Google Sheets 的監控列表,並且將其作為 Excel 檔案儲存在本機端」

會將檔案存在本機端再餵給 Test Script 進行測試的原因,是因為即使 Google 身為全球數一數二的服務供應商,也無法確保其提供的服務在每時每刻都是正常的。為了降低對外部服務的依賴,每次成功取得監控列表後,都將其儲存在本機端。若是某次執行時遇到錯誤而導致無法從 Google Sheets 取得最新的監控列表,至少還能夠使用前一次儲存下來的資料來執行測試,避免監控會因此而中斷。

另外,將 Slack 通知的 channels 放到 command option 則是因為目前所有的監控通知我們都統一推播到同個 channel。倘若未來有其他需求,可能也會選擇將其放到監控列表文件的欄位之中,如此一來各個 Service 的異常通知就可以分別推播到指定的 channel 中。

  • base_api.py

透過 requests lib 封裝後,用來進行 API 請求的基礎類別物件。在我們的自動化測試框架中,各個 Service/Component 的 API 會繼承該類別、有另外的衍伸,之後的文章會再分享給大家。

而當服務的響應時間過慢或是無回應時,對用戶體驗來說也會非常扣分,因此響應時間同樣也必須納入需要關注的指標之一,透過 timeout 的設置就能夠輔助我們來觀測這個指標。除了有預設好的閾值外,也可以在監控列表中針對各個監控目標設定不同的閾值。

  • Test Script

實際測試執行的流程則是透過 pandas 讀取 Excel 檔案後,透過 pytest.mark.parametrize 的 decorator 將各個測資傳入 Test Function 中。其他資料型態處理或是測資轉換的內容就不放在範例裡面,可以依照各自的需求延伸出各種方案。

進入 Test Function 後會先確認該測試案例是否有被 skip (is_run),再來就會針對 URL 進行 request。以最基礎的確認來說,會驗證 Response 的 HTTP Status Code 是否為 200、以及前述提過的 timeout、duration 時間,其餘非預期的 Exception 也都會包起來以便在測試 Fail 時執行我們想要的行為。若有其他 Assertion 需求也可以自行擴充。

️✔ Jenkins

建立完 Test Script 後,當然就是考慮如何定期執行來達到 Health Check 的效果。無論是透過 cornjobs、schedule task 或是 Jenkins 等工具都可以達到此目標。

而我們選擇了 Jenkins 的定期建置來執行,原因也很簡單:

  1. 目前內部自動化測試的流程也大多是採用 Jenkins 來串通鏈路
  2. 除了執行 Test Script 外,在測試結果出爐後,仍有其他的動作要執行,例如:將結果記錄到資料庫留存、產生 Test Report 等
  3. 原先有使用 Jenkins Slack Notifications 的 Extension 來達到通知效果

為什麼會講原先呢?因為當時我們使用 Jenkins 來進行 Notify 時,它只會根據 Job 的 Build Status 來告知這次的執行結果是成功或是失敗,但沒有辦法立刻看出來實際發生問題的是哪一個 Service 的測試案例,導致我們需要進到 Jenkins 的 Console Output 中、或是另外透過 Allure Report 的內容才能知道是哪一個服務發生異常。

▲ Jenkins Slack Notifications

️ ✔ ️Slack Notification

為了解決前面提到 Jenkins Slack Notifications 的痛點,我們直接透過 Slack 提供的 API 建立了一隻通知用的 Slack Bot。實際建立的方式可以直接參考 Slack API: Applications 的文件,只要建立好 App 後透過 Python Slack SDK 撰寫 Script、使用 Bot User OAuth Token 串接,就可以輕易達成。

▲ Slack Application

除了推播到指定的 Slack channel 外,也可以 mention 指定的用戶來達到更有效的通知手段。

▲ Online Service Alerting Message in Slack

另外也推薦可以使用官方提供的 Block Kit Builder 來組建符合自己需求的訊息樣式,以呈現更完整的資訊。

▲ Slack Notification Message Example

這些監控的機制仍有許多能被優化或是擴展的方向,像是以目前設計的 URL Health Check 除了針對 HTTP Status Code 進行確認以外,之後也能夠拓展至關注 Response 回應的內容是否正確、確認 Remote Config 是否符合預期、透過 Kibana 的日誌記錄以發覺更多面向的業務價值。累計下來的數據紀錄也可以用來進行統計與分析,嘗試找出系統瓶頸或是不易發現的異常狀態。

建立了以上的監控機制後,街口對於服務異常的感知能力又大幅提升了幾個檔次,不再像以往都必須等到用戶輿情反應或是客服回報後才進行處理。而透過每次的異常紀錄也可以發現服務異常的平均修復時間 (MTTR) 明顯縮短,也因此客服人員處理的案件數量大幅減少、同時有效的降低維運成本。在街口服務日漸壯大的情況下,系統的穩定性會變得更加難以掌握,所以一旦服務出錯,能夠及早發現、快速止血就變成了街口最重要的小事。

Written by — Dopiz Liu
2021.11.25

--

--

Dopiz Liu
OnedaySoftware

A passionate Software Development Engineer in Test 🙂