1. 程式人生 > >Google SRE主管:使用開源軟體打造類似Google的開發和生產環境

Google SRE主管:使用開源軟體打造類似Google的開發和生產環境

作者簡介:

Minghua Ye(Google  SRE 主管)

2007加入 Google 公司,2009年開始,主要負責 Google 的雲端計算平臺,特別是 Google App Engine。

前言

如果大家對 App Engine 還不熟悉的話,簡單來說 App Engine 就是 Google 提供的 paas,一個開發、託管網路應用程式的平臺,使使用者的程式能在 Google 的資料中心執行。

作者在本文中分析他在 Google 的一些經驗,鑑於作者的 App Engine 背景。本文很多話題裡都涉及跟 App Engine 相關的應用。

1、雲平臺至關重要的可擴充套件性

當7年前,我剛剛開始在 App Engine 的 SRE 生涯的時候,App Engine 還是在 Google 內部一個很渺小的服務,活躍使用者,流量都遠遠不能和 Google Search 這樣的巨無霸相提並論。

而在短短的7年時間 App Engine 實現的指數型的增長,現如今已經成為了 Google 雲平臺的重要組成部分。

應用程式開發者在 App Engine 上部署了上千萬的應用。在其中不乏一些很重要的客戶和很有趣的用例。

上圖裡我提及到的這些應用開發者們都在它們的網站公開描述了它們在 AE 上的實現。大家如果有興趣做深入的案例研究可以直接搜尋相關的關鍵字。

值得一提的是威廉王子和凱瑟琳王妃在2011的大婚,皇室選擇了 Google 的雲端計算平臺作為婚禮網站和婚禮實時直播平臺的提供者。而作為運維小組的 SRE 也得到了皇室的感謝。

在短短的幾天之內,網站接受了 15m 的訪問和超過 42000QPS 的峰值流量。他們之所以選擇 AE,最重要的原因是看中了 AE 系統的自動可擴充套件性。

網站開發者僅僅部署了網站的原始碼,而後臺容量的自動擴充套件和流量的自動均衡都由 AE 系統自動完成,而不需要開發者或者 SRE 的任何干預。

另外一個很重要的客戶是 Workivia,Workivia 向全球500強公司提供財務報表的提交服務。眾所周知,財務報表的提交時限性很強,而且不容許有失敗和錯誤出現。

這對雲平臺的穩定性和容錯性就有更高的要求,它們選擇AE原因也恰恰在於由 Google 提供的高可靠 SLA。

同時 AE 的自動擴充套件功能使他們能夠在繁忙的稅季有足夠的後端冗餘去處理使用者請求,而在淡季又能夠通過自動減少後端容量已到達節約開支的目的。

最後要提到的是 Spotiy,作為網際網路音樂流媒體的主要提供者,它們主要看中的是 Google 雲平臺的一致性和寬容度,不論你是處理每秒7個事件還是70萬個,服務都能保證一至的使用者體驗。

所以說可擴充套件性對於一個雲平臺來說是至關重要的。

2、可擴充套件系統的基石

Google App Engine 採用了和大多數其他 Google 內部服務一樣的微服務架構。而不得不提到的是這些微服務的共同點和它們所依賴的通用內部平臺。

  • 分散式鎖和儲存服務

首先不得提到的則是 Google 內部自己實現的分散式鎖和儲存服務 chubby。

在 Google 內部基本上所有的服務都依賴於 chubby 所提供的一系列功能。chubby 本身並沒有開源,但是 Google 將 chubby 的實現細節和 API 通過一篇研究論文發表了。

這篇研究論文也恰恰催生了一批開源的實現,而其中最有名的就是大家都知道的 Apache zookeeper。

而大家也能看到 chubby 所提供的功能在單機環境就類似於大家熟知的鎖和暫存器,而 chubby 或者 zookeeper 恰恰是把這種基礎的服務拓展到了分散式的環境,是的軟體開發者能在分散式的環境中輕鬆的應用單機開發中常用的方法和理論。

  • 服務的自動發現

當你有很多鬆耦合的微服務組建在執行的時候,如何能夠自動發現並定址到這些服務,就變的非常重要。服務的自動發現在 Google 也是通過 chubby 來實現的。

BNS 是在chubby上實現的地址協議,chubby 提供小檔案讀寫的一致性,這樣就能通過寫入 BNS 地址和真實 IP:port 繫結,來實現服務發現。

當服務需要解析一個 BNS 地址的時候,他只要通過一致性的讀取相應檔案即可。etcd 和基於 etcd 的 skydns 則是服務發現在開源環境中的實現。

  • 流量負載均衡

當你有很多鬆耦合的微服務組建在執行的時候,你同樣面臨的問題是如何能夠實現流量負載均衡。

在 Google 內部負載均衡是通過 Google generic service loadbalancer 服務來實現的。你如果使用 Google 的雲平臺的話,Google 可以提供給你網路即3層,或者 HTTPS 即七層的自動負載均衡。

在 AWS 也有類似的 Elastic loadbalancer 實現。在很多情況下,使用者還可以通過 HApxoy 或者 engineX 來實現一些簡單的負載均衡。

  • Protobuf

最後值得一提的是 Google 的 RPC 子系統和 Protobuf。Google 在近期開源了 gRPC 也就是 Google 內部使用的 RPC 子系統的開源實現。

gRPC 使用 http2 作為傳輸層,同時使用 Protobuf 作為介面描述語言和訊息格式。

2.1 分散式鎖和儲存

讓我們來看一下 chubby 會提供哪些在分散式環境下至關重要的服務:

  • 第一、不同微服務間的同步,通過獨佔鎖的實現,只有一個服務是能獲得獨佔鎖並更新共享的資訊。
  • 第二、有一些服務需要實現主從分配,多個服務用例能通過masterelection庫,競選出真正的主例項。而且從例項能自動轉換成主例項,如果主例項不可用。
  • 第三、是序列號這個在儲存和網路中都會經常要用到。
  • 第四、則是我前面提到的 BNS 服務。
  • 第五、chubby 本身是一個檔案系統,所以可以用於分散式的檔案儲存。事實上,在 Google 很多服務用 chubby 儲存一些不大的配置檔案,這樣能實現線上的和同步的,不需要重啟服務的配置更新。

2.2 自動註冊的服務發現

自動服務發現使服務能夠實現自動擴充套件,你可以隨時增加服務的容量,增加或更改服務執行的資料中心,而作為 devops 則不需要上游系統做任何更改。

當一個服務用例失敗的時候,RPC 傳輸和負載均衡中介軟體能自動發現並將不健康的用例自動從負載均衡的備選用例中剔除,從而實現真正的無人值守。

2.3 谷歌雲平臺上的負載均衡

剛才提到了在 Google 的雲平臺上有現成的負載均衡可供使用者使用。而且使用者也能通過使用第三方的軟硬體來自行實現負載均衡。

2.4 Protobuf

不得不提到的是 Google 開源的 Protobuf 庫提供給不同的語言開發者一個統一的通訊協議,服務定義和儲存格式。

Protobuf 重要特性是向後相容性,比如說應用在08書寫的 Protobuf 格式的日誌,在2017年能夠繼續被使用和分析,即使是 Protocol buffers 已經被更新很多次。

在介面描述語言和訊息格式裡面,你可以任意新增新的閾值而不影響服務的向後相容性。這一點在大規模微服務實現中非常重要。

當你的服務用例數足夠大,你則不可能在不影響服務質量的前提下,同時更新所有的服務用例。所以前端和後端必須保證向後相容的特性,否則在升級過程中會造成資料的丟失或損壞。

在大型的開發團隊裡,更要求前端和後端能獨立開發,獨立部署,獨立測試,而 Protobuf 的向後相容的特性,恰恰是這樣的開發部署模式成為了可能。

Protobuf 還提供跨平臺和語言的相容性,所以 node.js 的前端能很自然的使用 Protobuf 與 C++ 的後端通訊。

更值得一提的是,恰恰是 Protobuf 的這種特性像 Google 這樣使用一個單一程式碼庫的公司能在內部部署成千上萬的相互依賴的鬆耦合的微服務。

3、使用Google service(C++)的核心類庫

接下來我想談談我在作為一個軟體開發者的一些體會,SRE 是 Dev+Ops 的合體,所以參與開發也是 SRE 日常工作的一個重要組成部分。

眾所周知 Google 廣泛的使用各種開源軟體打造它的平臺,而作為開發者 Google 也向開源社群回饋了很多內部使用的工具的類庫。

我將舉例幾個跟 SRE 相關比較緊密的庫逐一講解,我選擇了 C++ 的版本因為我主要從事 C++ 的開發所以比較熟悉。

這些類庫大多也都有其他語言的實現,值得一提的這些庫基本上被所有的 Google 內部服務呼叫。

3.1 命令列庫—gflags

首先提到的是 Google 的命令列庫叫 gflags。在 Google 幾乎所有的服務引數和特性都可以通過命令列引數來調教和更改。在很多時候新的服務特性往往是通過命令列引數來啟用或者禁用。

舉個例子,如果在某次的部署當中新的服務實現了 A,B,C 三種新功能,但是通過部署測試發現 B 功能不能正常工作,這是SRE往往採用命令列引數來禁用b功能,從而使 A,C 功能能及時的釋出。

在第二個例子當中,SRE 經常會通過命令列引數來更改服務的特性而不需要重新編譯和打包。很多時候程式的配置被寫在命令列裡,這樣只要更改命令列就能服務實現不同的功能。例如你能配置一個服務使用英文而另一個服務使用中文而不需要重新打包。

gflag 定義 flag 為全域性變數,你可以用 DEFINE flag 去在任何檔案裡定義命令列標誌,在其他檔案中通過 DELCLARE_flag 來實現呼叫。使用 gflag 你將擺脫手動分析 args,能使程式更加簡潔易讀。

3.2 日誌服務—glog庫

第二個提到的是 Google 的 glog 庫,實現了程式中標準的日誌服務。

glog 定義了不同的日誌型別,而開發者可以通過 LOG 型別來簡單的實現將不同的日誌儲存在不同檔案中的目的。

glog 提供了 CHECK 巨集,能幫助程式檢測一些不可恢復的錯誤並終止程式。在這個例子中如果寫失敗將終止程式並將 stacktrace 輸出到日誌中方便 SRE 和 DEV 來 debug。

glog還提供詳細日誌服務,詳細日誌通過命令列引數來控制。通過 vmodule 和 v 兩個引數可以控制不同的模組產生不同的日誌。

glog 還提供系統訊號處理,在程式被系統訊號終止的時候,他能自動生成出錯點的 stacktrace 方便 SRE 和 dev 來 debug。

glog可以和其他的日誌管理程式一起實現日誌的重定向等服務。

3.3 單元測試庫—Google test

最後要提到的是 Google 開源的單元測試庫 Googletest,提供兩個方面的功能:

一個是單元測試;
一個是虛擬測試;

單元測試被廣泛應用於 Google 的程式碼庫,基本上每個實現都有單元測試,而且測試的覆蓋率會自動報告。

虛擬測試則廣泛應用在複雜服務的測試中,在寫單元測試的過程中,被測部分的複雜依賴則通過 mock 來實現,是開發者能專注於單元測試中。