- Google SRE 全球共計約 1000 人
- SRE 是一群天生的懷疑論者,懷疑一切「高大尚」技術,以及任何「神奇的產品」
- SRE 在確保系統可靠性方面沒有什麼萬靈丹,有的只是極度的務實(progmatic)
- 如果用一個詞來描述 Google 的歷史,那就是不斷的 scaling up
- 系統維運本質上是人與電腦共同參預的一項系統性工程
- IT 產業大多自我封閉,交流過少,很多從業人員或多或少受到教條主義的限制
- 今天我們能感受到整個業界都在鼓吹厚顏無恥的「給我程式碼,其餘免談」;開源社群內部也正在形成一種「別問我問題」的風氣,過於強調平等卻忽略專家的意見
- 相對於最終的軟體結果、架構設計,真實的設計過程和作者本身的思考歷程更具價值
- 一套軟體的 40% ~ 90% 成本,其實是花費在建置之後的不斷維護過程
SRE 的工作範疇
- 維運具體服務
- 設計研發大型分散式系統
- 協助產品部門開發其系統的額外元件,如負載平衡,同時盡可能重複使用這些元件
- 想出各式各樣的方法,利用現有元件解決新的問題
- 對架構設計、維運流程不斷最佳化,讓這些大型系統有更好的「可靠性」
- 可靠性(reliability)——系統能夠在指定環境下,在要求的時間內成功持續執行某個功能的機率
- SRE 的 「S」最開始指的是 google.com
- SRE 是從 Google 的內部職位、從 Web 社群中誕生的
- 與 DevOps 一詞不同的是,SRE 同樣認同 IaC,但 SRE 最關注的是可靠性(或者說是風險),甚至可以為了可靠性而「消除維運的需求」
- 可靠性就像安全性,愈早關注愈好
- 「無論對一套系統的執行原理掌握得多麼透徹,也不能阻止人為的意外錯誤。」
- SRE 的 「E」可以指事 —— Engineering,也可以是指人——Engineer
入門
傳統的分工模式:Dev/Ops 分離,有以下問題:
- 直接成本:系統管理員(sysadmin)大部分依賴人工來處理/維護事件及變更,隨著系統複雜度增加,會需要更多人力成本
- 間接成本:兩個部門的落差/代溝,代價通常會比直接成本高很多
兩個業務目標本質上是矛盾的
- Dev: 如何快速部署、迭代版本(隨時改動)
- Ops: 如何避免故障(不要改動)
- SRE 模型是為了解決 Dev/Ops 的矛盾——請軟體工程師開發軟體/系統,來維護系統執行
- SRE 運用軟體工程的思維和方法,建構自動化工具來取代人工操作(傳統 sysadmin 做的事)
- Google SRE 的組成:
- 50-60%:軟體工程師
- 40-50%:具備 85-99% 軟體工程師標準,但同時具備其他能力(UNIX、layer 1-3 的網路經驗)
- SRE 必須要有足夠時間開發自動化程式—— Google SRE 的傳統維運工作最多只能佔 50% (工單處裡、on-call、手動操作)
- SRE 應致力於消除所有基本維運工作,不只是人工作業自動化(automated),終極目標是讓系統能自動修復、自主執行的無人化(automatic)
- 管理階層維持 SRE 團隊的工作均衡的手段:
- 持續衡量每個團隊的工作時間分配
- 將一般維運工作做交還產品研發團隊負責
- 從產品研發團隊調人參與 on-call
- 要求停止任何新增的維運工作
- SRE 文化在公司內部是代表一種快速、創新、擁抱變化的文化
- SRE 和研發團隊之間的成員可以自由流動,整個產品部門的人員都有機會學習和參與大規模部署活動
- 如何招聘合適的 SRE 是一個大難題:要求更高、需要和 RD 部門競爭
- SRE 有時需要採取違反傳統的作法,須要管理階層強力支持
- 可將 DevOps 視為 SRE 核心理念的通用版,反之,SRE 是 DevOps 模型在 Google 的具體實踐
SRE 的核心方法論
持續關注開發
- 維運工作限制在 50% 以內,避免過度維運,超過的話須採取暫時性措施,此模式需要產品部門的認同與配合
- 每 8~12 小時 on-call 期間最多只能處理兩個緊急事故,確保有足夠時間追蹤、排除故障、撰寫事後報告
- 事後檢討(postmortem):沒有觸發警報的事故(漏洞)更值得檢討、對事不對人
符合 SLO 的同時維持最快的更迭速度(Maximum Change Velocity)
- 不以「零故障」為目標、任何產品都無法作到 100% 可靠
- 建立合理的可靠性目標(Service-Level Objective, SLO),如果可靠性是 99.99%,那錯誤預算(error budget)就是 0.01%。
- 可靠性目標考慮下列幾點:
- 基於使用者習慣,怎樣的可靠度是使用者滿意的?
- 如果服務的可靠性不夠,使用者是否有別的替代選擇?
- 服務的可靠性是否會影響使用者的使用模式?
- 錯誤預算用在發行新功能,幫助衡量新功能何時可以最快上線
監控系統
- 超過監控值自動發信這種策略效益很有限
- 警報訊息應該由系統自動分析,只有須人為介入時才通知
- 三種輸出:
- alert:須立即做出回應與處理
- ticket:沒有立即性的危害,允許幾天內完成操作
- logging:用於調校與分析,平時不會看
緊急應變
- 衡量可靠性的指標是平均故障間隔時間(MTTF)、平均修復時間(MTTR)
- 透過事先模擬、將最佳處理方法紀錄在「維運手冊(playbook)」上,通常至少可讓 MTTR 降低 3 倍
變更(change)管理
- 大約 70% 的系統事件是因部署變更導致的
- 使用自動化來完成:
- 漸進式(progressively)更新
- 發生問題時迅速退回變更(roll-back)
- 快速、準確定義問題
容量(capacity)規劃
- 是一個容易被忽略的一般性概念
- 有幾個必要步驟:
- 自然成長的需求預測(demand forecast)
- 自然成長以外的需求來源(demand-resources)統計
- 週期性壓力測試,用來對比實際數字
- 跟資源部署一樣,應由 SRE 主導
Provisioning(譯做資源配置)
- 是變更管理與容量規劃的結合
- 必須盡快完成(要精確)、必要才做,因為資源很昂貴
- 風險較高
效率與效能
- 改善資源使用率(透過容量規劃)可以有效降低成本
- 整體資源使用情況受下列三者影響:
- 流量
- 服務的可用容量
- 軟體的演算法
- 設定一個特定的延遲時間(response speed)作為目標,來規劃容量
- SRE 團隊和產品研發團隊應該共同監控系統效能
從 SRE 視角看 Google 正式環境
這章開頭的問題意識是為什麼 Google 要把伺服器明確區分成「實體 machine」跟「軟體 server」,並以資料中心的拓樸結構來說明
其中一個原因是想把硬體故障跟實際業務使用者區隔開來,因為硬體的損壞率極高(每年幾千起,損失幾千顆硬碟)
具體管理方法是用了 Borg 做叢集管理跟資源分配——也就是 Kubernetes 的前身
硬體伺服器
實體伺服器的網路通訊是透過自建的 Switch,以 Clos 結構連接(inlet x outlet 的一個 2-d 矩陣,無論在什麼負載情況下都能保證連線的建立),集合成一個虛擬 Switch 擁有上萬個虛擬通訊埠
各個資料中心透過主幹廣域網路(WAN) B4,特色是透過動態管理,達到最大平均頻寬(最佳化)
Borg 負責安排叢集內的實體伺服器執行 job(由多個 task 組成),由於 task 跟 machine 不是一對一,必須透過一個抽象層:由 BNS(Borg Naming Server)去分配一個名稱跟索引,例如 /bns/<cluster>/<user>/<job name>/<task number>
,連線時,透過這個名稱去跟 BNS 問 <IP address>:<port>
為了提高實體伺服器的使用率,根據 task 定義的資源,Borg 會選擇最適合的機器去執行,同時盡量分散 job 的 task 避免單點故障
如果 task 超用資源,會被重啟——緩慢、不斷重啟比洩漏資源不重啟更好
叢集持久化(persistent)的部份,透過兩個重要的底層服務:D、Clossus
每台實體機器都跑 D(無論是 HDD 還是 SSD),再透過上層的 Clossus 整合整個叢集的硬碟,提供單一介面——這種儲存系統跟 HDFS 類似
再上去的話可以透過幾個資料庫服務存取:BigTable、Spanner
跟資源分配一樣,頻寬也是動態分配(由 Bandwidth Enforcer, BwE 分配),要作到這點,必須透過集中式的路由計算(分散式的路由會有流向遷徙問題)
服務可能是跨叢集的,為了降低延遲,請求會盡量導到地理位置最近的 BNS(透過全球負載平衡系統 GSLB)
Q: 如果同時有五台閒置實例,要分派給那一台?
透過名為 Chubby 的 lock service,做 master-election——保障了 Reliability 和 Consistency(透過類似檔案系統的 API 來鎖定,可跨地)
監控系統運行在資料中心層級,從實例中擷取「監控指標」 (metric)
軟體伺服器
軟體大多採用多執行緒去提高 CPU 利用率
每個軟體伺服器都有一個 HTTP 服務用於查詢 task 的運行情況
所有 Google 軟體服務通訊都透過名為 Stubby 的遠端程序呼叫(RPC)——開源版本就是 gRPC,傳輸格式是 protobuf(比 xml 小 3-10 倍,序列化快 20-100 倍)
軟體伺服器透過它的前端(frontend/client) 接收 RPC 請求,轉發到它的後端(backend/server) 處理
開發環境
所有專案都放在同一個共享 repo,有個優點是開發者可以直接提交修正(changelist, CL)到基礎元件的專案
請求的處理過程
- 訪問服務站點,DNS 解析後向 GSLB 取得 IP 位址
- 訪問該 IP 位址,連接到反向代理(layer 4, TCP)
- 反向代理透過 GSLB 找到服務可用的前端,發送一份 RPC 請求(含請求內文)
- 服務的前端解析 RPC 中的 HTTP 請求內文、建構一個新的 protobuf,一樣再透過 GSLB 找到服務可用的後端,轉發
- 後端處理請求,回傳給前端後,由前端去建構 HTTP 響應內文
從這個流程,可以看出集中式的路由怎麼運作的,尤其突顯 GSLB 的重要性(DNS、GFE、App FE、App BE 都要詢問它)
N+2 模式
假設服務可處理的 qps 為 100,調查得出尖峰流量為 3470,至少需要 35 個實例,N+2 後為 37 實例
- 系統更新時(例如 rolling update),只有 36 個可用
- 同時又有一台實例出問題,剩下 35 個可用,剛好滿足尖峰需求
為了更進一步降低延遲,也須觀察流量來源地區(例如 70% 來自北美),根據各個地區的流量分別部署不同數量的服務