on-call
關鍵是「數量」跟「品質」的平衡:
- 數量:不超過 25% 時間 on-call
- 品質:須要有充足的時間處理(含分析、debug、事後檢討,一個事件約須花 6 小時完成)
幾分鐘內要回應?
回應時間與服務水準、可靠性有關,例如面向使用者的服務須在 5 分鐘內回應,非敏感業務通常是 30 分鐘
維運負擔過大怎麼辦?
事件 / 警報比例應接近 1:1,避免重複警報導致維運壓力、調派有經驗的 SRE 協助、與研發團隊一起分擔維運
系統太穩定怎麼辦?
維運壓力不夠會導致自信過度或自信不足,每個工程師每季應至少參與一次 on-call,公司可定期舉辦災害演練
故障排除技巧
故障排除是一連串的「假設」+「排除」,這個技能是可以教學相長的,如果能做好事後檢討、紀錄負面結果(negative result),故障排除會是學習一套系統很有效的方法
小心避免以下陷阱:不理解現象(方向錯誤)、假設是對的,但測試假設的方法錯誤、過早下結論、被巧合/偽相關誤導
「緊急情況下,飛行員的首要任務是保持飛機飛行及安全登陸,故障定位和排除只是次要目標。」
Google 用什麼追蹤工具?
每個系統用的工具可能不同,文中提到的 Dapper 是 Google 內部很廣泛應用的工具,特別看了一下文獻整理幾個重點
在分散式系統,跨服務請求很常見,例如發出一個 requestX
,在下游會發出額外數個請求 —— 攤開看就是一個 Tree(巢狀的 RPCs)
這個請求/響應歷程的樹狀結構稱為一個 Trace
,當中的節點就是單一請求/響應,稱為 Span
,裡面會紀錄時間戳、traceID、parentID、host 等詳細資訊。Span
是以本地文檔的方式建立和寫入的,再透過 Dapper daemon 去拉取並儲存到後端 —— BigTable, Trace
存成 row,Span
存到其對應的 sparse column
可以把 Span
視為是一種 Log,除了運行在伺服器上的 Dapper daemon,應用程式也可以透過函式庫發送 Span
、加標籤或自訂的額外訊息等,這個重要功能稱為 annotation
Dapper
設計上很重視的理念是「低成本」,包含本地檔案的讀寫、後端儲存、網路頻寬(只佔小部份),因此採用取樣 (sampling) ,經驗上顯示取樣不只可以大幅降低延遲,也能讓資料得以保存更久,Dapper 的預設取樣率是 1/1024——對數據密集型系統而言,不會造成分析上的盲點
Dapper 原本只是一個追蹤工具(黑箱的),但後來演化成一個大型的監控平台,有強大的界面可以幫助分析,甚至到後來,發現可以應用的層面更廣:系統的依賴關係(dependency)分析、網路狀態分析、在共享儲存的基礎上區分服務、長尾延遲的分析、錯誤報告分析等
緊急事件的流程管理
職責分離很重要:
- 指揮 (incident command):掌握事故基本資訊、負責組織處理團隊、分配/協調工作
- 維運 (operational work):做系統修改(只有維運團隊能「動手」)
- 發言 (communication):對外發言、擬稿、定時發送通知給所有相關的人員
- 計畫 (planning):支援一般事務、紀錄交接及處理過程
用什麼方式溝通?
除了 E-mail ,溝通的方式推薦 IRC(internet relay chat):可靠、可完整紀錄
即時狀態紀錄範本
用 Google Docs(可多人線上編輯),以條列式紀錄事件概要、組織架構、待辦事項及時間軸
什麼時候宣佈事件?
取決於「是否須跨團隊」、「服務性質是否直接面向使用者」、「無法在一小時內解決」
事後檢討(Postmortem)
核心是「釐清根源性問題,避免未來再度發生」
要導入事後檢討,必須先定義標準和條件,例如「當機時間超過 SLO」、「有任何形式的 data-loss」
Best Practices
- 對事不對人:事後檢討不是懲罰,而是整個公司的學習機會
- 寫完後要審查:找資深工程師評估(例如影響評估是否完整、處理的優先順序是否合理)
- 公開獎勵:可透過分享每週最佳事後檢討、發獎金來建立由工程師自主驅動的文化
- 收集回饋
事後檢討範本
用 Google Docs,除了條列的事實陳述,還加上「反省」的部份,時間軸可以從即時狀態紀錄直接延伸
事件追蹤
從前面的章節可以知道,警報是從最細的 log 加上定義好的條件式得來的,可以視為 log 的彙總。而過多的重複警報是不好的(雖然觸發條件不同,但來自於同一個根源),因此警報也需要加以彙總,稱為「事件(event)」
一個好的警報系統有這些功能:
- 可以分組、彙總
- 可以添加標籤
- 如果超時未處理,可以自動升級(escalation),例如通知副 on-call 工程師
- 可以整合郵件服務,例如選擇一系列故障發給下一位 on-call 工程師
測試可靠性
當服務每做一次變更,可靠性都會降低(尤其是短時間做大量變更)。這時候我們可以提高測試數量(或覆蓋率)來降低「不確定性」跟可能影響可靠性的因子
有哪幾種測試?
- 單元測試(unit test):只考慮最小的軟體單元,不考慮整體
- 整合測試(intergration test):考慮多個相關的的獨立元件,透過 mock 模擬一方行為
- 系統測試:可理解為測試站環境,可以測試點對點(end to end)功能
- 冒煙測試(smoke test/sanity test):最基本、最優先做的基本功能測試
- 效能測試(performance test):測試隨著時間變長系統效能跟資源要求的變化
- 回歸測試(regression test):曾經發生過的 bug 重複拿來測試
- 量產測試(production test / black-box test):可以以黑箱監控來理解,在正式環境上做測試(可配合小部份循序變更的發行步驟)
- 組態測試(configuration test):測試參數組合、與正式環境使用的設定檔做交叉比對
- 壓力測試:找出系統的效能邊界
- 金絲雀測試:透過循序的小部份升級(常見標準從 0.1% 開始,每 24 小時增長 10 倍),監控使用情況判斷功能是否正常、是否該停止升級
怎麼評估金絲雀測試出現的錯誤?
1 2 3 |
U = R * K / C 單一 Bug 的錯誤複雜度 = 錯誤發生速度 * 升級所需時間 / 錯誤累積值 |
哪些測試先寫?
- 冒煙測試
- 考慮元件的重要程度
- 考慮元件中的重要的功能,例如購物車
- 其他團隊會用到的功能或 API
怎麼計算測試覆蓋率?
很多工具可以計算測試對程式的覆蓋率,但重點是怎麼從一堆數字看出重點,例如「哪個模組才是最需要補測試的」,因此會須要可視化,例如畫成 TreeMap
最後筆記幾個有關測試的重點:
- 最終一致(eventual consistent)不等同從頭到尾都一致,資料庫的 transaction 常需要考慮這點
- 測試多執行幾次可能會有幫助
- 須關注測試環境跟正式環境的不一致
- 設定檔應該跟程式碼分開看待,設定檔的修改頻率比程式碼低很多
- 使用直譯式語言如 Python 寫設定檔會有風險,因為不知道執行起來會花多少時間/資源
- 正式環境的探針(probe)其實也是一種測試