凡走過必留下痕跡 - 雲端服務巨量 Log 架構設計
為什麼要寫 Log 呢?絕不是要有效利用磁碟空間,而是要幫助我們除錯 / 記錄,當系統發生可預期或非預期的錯誤時,我們都可以藉由調閱 Log 來追朔問題發生的原因,還原現場找出兇手。我們是 RD 不是殺手,總不能「解不了問題就解決提出問題的人」,功能要做 Bug 也要解,多寫點 Log 還是有點幫助的。
開始之前,先了解一下典型面對 Bug Issue 排除工作,正確手順是:
複製錯誤 > 修正 Bug (或者加入新的 Bug) > 驗證錯誤被修正
複製錯誤是第一階段,複製錯誤之前要先盡可能建構與 Bug 發生相同的環境。程式碼如果有版本控制與佈署機制 (自動程序、Script 或 Docker 更好),基本上環境沒有太大的問題。建構環境通常有三個比較難克服的地方,就是資料、效能與規模模擬。
先在模擬環境重現問題才能解 Bug
資料問題在於我們有時碰不到上線產品環境中的資料,如果 Bug 的發生牽扯到資料與 Status 關係,就會很頭大。
效能問題也不容易複製,在實驗環境中不容易模擬大量且複雜的服務請求,這種問題常常牽扯雪崩效應與子系統之間的連帶關係,常常模擬工作就需要很大量的時間與資源。
然而規模模擬也是很燒錢的項目,曾經有聽過某些雲架構建制了兩套一模一樣的服務資源,透過路由直接切換與更新服務,上線後一有問題可以立即退版切回來。這種機制除了很燒錢以外,RD 可千萬別跑錯場,搞混就糟糕了。
假設我們很幸運,一旦錯誤可以成功複製以後,後面的問題就簡單了 (大多數的情況啦)。一但在複製錯誤階段卡關,所有的工作就變得很難進行,這時候就需要 Log 的幫忙。Log 可以幫助我們快速定位問題,甚至在沒有複製問題的情況下直接排除,這是雲服務維運中很重要的一個環節。
如果 Debug 是消除軟體 Bug 的過程,那寫程式一定是把 Bug 放進去的過程!
Frontend 與 Backend Log
那我們就來談談如何在雲服務中建立 Log 機制,開始前我先將 Log 分為兩個蒐集層面:Frontend 與 Backend,以下我們分別對兩個層面進行分析。
Frontend Log 使用者界面 (UI) 操作
這類型的 Log 屬於前端的範疇,無論是 Web Application, Desktop Application 或 Mobile Application,我們必須假設用戶的操作都是本地 (甚至離線狀態) 進行。紀錄所有使用者的操作的流程絕非必要,我們需要的是在問題發生時,可以透過 Log 追蹤問題發生的原因。程式一旦發生了 Exception 或者偵測到 Crash,可以在正確的時機將最近階段的 Log 自動回報至 Log Server (Log Server 如何設計下次再描述),這類的 Log 可能包括 Runtime Call Stack, Device Diagnostic, User Action, Event 等等,這些 Log 資訊其實都是輔助功用,真正能幫上多少忙也很難講,但總有個依據。避免遇到前端 Bug 只能兩手一攤,準備下班。
Backend Log 服務 (API 核心)
Backend Log 顧名思義產生與紀錄都發生在 Server 端,目前大多數的雲服務設計都是透過 API 與 Application 組合而成,採用 Client/Server 或 Browser/Server 架構,設計這樣的系統邊際降低耦合性,算是目前很流行的設計。這裡的 Log 我還會細分為三種類型:
-
- Event Log
- Application Log
- Request Log
Event Log
定義使用者在介面 (UI) 上的一項操作,比如刪除訂單、上傳檔案、發送一則訊息等等動作,通常表示一個業務邏輯的執行。每一個操作實際在功能實現上,可能包含多次後端 API 的呼叫,每一次的呼叫都會被定義為一項操作。這個 Event Log 設計的目的是讓使用者調閱操作記錄,可用來稽核與進行統計等等,一般來說與系統維運層面沒有太大的關係,但是有了這個設計,使用者可以在介面中自行調閱記錄,省得因為使用者的操作問題,浪費太多的客戶服務資源。
Application Log
Web API Server 執行過程中所產生的 Log,通常發生在 Server 端,會記錄系統實際運作的情況,好用來追蹤資料在程式之間流動的行為。特別在發生錯誤的時候可以被直接記錄,通常這樣的 Runtime Exception 都會記錄 Call Stack 好讓後續可以追蹤分析。
Request Log
由於目前大部分的後端都是採用 HTTP Web Service 實現 API,Request 就成為 HTTP 最基礎的通訊內容。記錄所有 HTTP Request 與 Response 成本是很高的,在實務的作業上可以在正常的情況記錄 HTTP Header 不記錄 HTTP Body,當在 Application 發生 Error 時才記錄 HTTP Body,可以大幅節省 Log Server 的負擔。
由於 Log 設計架構想寫的內容比較多,所分成兩個章節,怕各位看倌讀著讀著就吐了。請自行酌約服用,下次再續....