GitHub網站究竟可不可靠?谷歌工程師教你用BigQuery一探究竟

作者簡介:Felipe Hoffa,谷歌開發顧問,來自智利,現工作於舊金山以及全球各地,谷歌Cloud Platform社區編輯。

以獨特方式組織的可視化數據往往能夠為我們提出一些有趣的觀點。Felipe Hoffa最近使用BigQuery結合Reddit近八年來的網站活動以及上線時間數據進行了可視化分析,我們從中看到了一些非常有趣的信息。作為一名剛入門的負責任務控制的網站可靠性工程師,我總是會這樣問自己,"如果我是負責這項服務的可靠性工程師,我會採用什麼方法解決這個問題?"

這次,Felipe將從可靠性工程師的角度出發,對GitHub的一些歷史數據展開分析。首先,我們需要先確定,使用BigQuery對GitHub Archive上關於GitHub的部分事件數據進行分析是否足以推斷出GitHub網站的健康狀況。GitHub為開發者定義了很多種不同的活動事件類型,但在本篇文章的分析中,我們僅關注成功向GitHub發出請求的事件。

我們可以使用這個查詢語句:

#StandardSQL nSELECT TIMESTAMP_TRUNC(created_at, MINUTE) minute, COUNT(*) nFROM `githubarchive.month.201607` nGROUP BY 1 nORDER BY 1n

我們可以找到在2016年7月中GitHub在每一分鐘發生的事件數量。created_at欄位記錄了一個以微秒為單位的時間戳,查詢語句將其按分鐘進行截取。這使得我們將查詢結果按時間戳分組時,可以使用COUNT聚合函數來統計每分鐘對應的事件數量。將查詢結果簡單可視化即可得到下圖:

在上圖中我們可以發現一些很有趣的數據點,這些數據點對應的事件數量格外得低,但是,僅通過上圖我們很難準確判斷每一分鐘究竟是"正常的"還是"異常的"。因此,我們可以根據查詢結果創建事件數據直方圖,使判斷的過程變得更加清晰。

這幅圖很明顯地表明,對於GitHub,當每分鐘內處理的事件總數低於200時,網站處於異常的狀態,這一結論至少在2016年7月份是成立的。我們假設每分鐘極少數的事件與異常少的終端用戶請求無關,而是由於網站自身伺服器問題所導致的。在這個前提下,有兩種可能的解釋:用戶請求未達到伺服器,或者伺服器無法成功響應用戶請求。這為我們提供了一個標誌來近似地判斷GitHub當前的狀態是"健康"還是"不健康"。

在這裡我們定義了一個"服務水平指標",即一個SLI(Service Level Indicator)。根據網站可靠性工程相關文獻中的介紹,服務水平指標是"一個針對所提供服務水平中的某些方面謹慎定義的定量標準"。在我們這個例子中,服務水平指標是指"每分鐘成功處理的事件數量"。我們要做的是,對這個服務水平指標進行轉換,幫助我們判斷網站服務在某一時刻是否上線或宕機。最簡單的方法是為"每分鐘成功處理事件"設置一個閾值,低於這個閾值時,我們將認為網站服務"宕機"。那麼,我們應該怎麼選擇這個閾值?

總中斷會導致在特定的時間內沒有請求事件記錄。因此,我們可以將"宕機"閾值設置為0來檢測總中斷的情況。然而,大多數的中斷都不是總中斷。網站服務可能會進入某種不健康的狀態,進而在提供服務的過程中開始出現異常高的錯誤率,這一現象會在日誌數據中格外低的(成功請求)事件比例上得以體現。

考慮到總中斷情況下不會記錄請求事件,我們在前面使用的簡單查詢在這種情況下可能會出現一些問題。沒有事件記錄的分鐘不會顯示在查詢結果中!這樣的結果完全忽略了總中斷的情況。下面的查詢語句展示了解決此類問題的方法。它創建了一個包含查詢月份所有分鐘的表格,並將其與前面的查詢結果連接,隨後將所有為NULL的結果(意味著不存在對應的行)映射為0事件數量:

#StandardSQLnSELECT b.minute m, IFNULL(c, 0) cnFROM (n # first day of monthn SELECT i*60 + UNIX_SECONDS(TIMESTAMP(2016-07-01)) minute n FROM `fh-bigquery.geocode.numbers_65536`n WHERE i < 60*24*n # number of days in monthn EXTRACT(DAY FROM DATE_SUB(DATE_ADD(DATE(2016-07-01), INTERVAL 1 MONTH), INTERVAL 1 DAY))n) b nLEFT JOIN (n SELECT UNIX_SECONDS(TIMESTAMP_TRUNC(created_at, MINUTE)) minute, COUNT(*) cn FROM `githubarchive.month.201607`n GROUP BY 1n) anON a.minute=b.minutenORDER BY b.minuten

為了使接下來的查詢操作更加簡便,我們將本次查詢的結果以視圖形式保存,命名為events_per_minute_201607,並在接下來的查詢中基於該視圖檢索數據。

既然我們現在有一個視圖,其中記錄了所有零事件對應的分鐘,那麼我們可以使用一個分位數函數來探索在每分鐘事件數量較低情況下的數據分布。

#StandardSQL nSELECT APPROX_QUANTILES(c, 10001) as q nFROM `fh-bigquery.public_dump.events_per_minute_201607`n

APPROX_QUANTILE函數的"10001"參數表明數據將被劃分至10000個桶中,每個桶具有相同數量的數據點。非統計學專業的讀者可能對具有100個桶的分位數函數的特殊情況比較熟悉。例如,如果你在測試中處於95分位數,這意味著在測試中有5%的人成績比你好,有94%的人成績不如你,同時還有1%的人的成績與你相同。

下圖為其中20條結果對應的條形圖:

由於我們認為中斷屬於異常情況,因此在這裡我們尋找的是超出"正常"範圍的數據點。我們想要選擇一個合適的閾值,這樣的閾值足夠低,不會誤將事件處理數較少的分鐘判斷為宕機時間,同時閾值也應足夠高,以至於我們可以檢測到任何明顯導致請求事件響應數降低的操作。通常情況下,每分鐘響應的用戶請求數在20到77之間時,可能會出現"狀態轉換"的情況,這可能意味著當每分鐘響應請求數低於20時,網站的服務幾乎完全"宕機"。

儘管上面的分析還未得出任何結論,但是我們可以先將閾值設為每分鐘20個事件,並以此為服務是否"宕機"的判斷依據,看看我們能夠發現什麼。使用下面的查詢語句我們可以看到GitHub在2016年7月總共宕機了多少分鐘:

#StandardSQLnSELECT m, cnFROM `fh-bigquery.public_dump.events_per_minute_201607`nWHERE c <= 20n

查詢語句返回了54行記錄,因此,根據我們的定義,GitHub的服務在七月份總共"宕機"了54分鐘。但是54分鐘究竟是好還是不好呢?

為了回答這個問題,我們需要確定可接受的宕機時間是多少。正常運行時間目標通常以你希望達到多少個9的形式表示,例如,99%的正常運行時間,99.9%的正常運行時間等等。99.9%的正常運行時間意味著你只能在0.1%的時間內宕機。但是,為了讓這樣的表述有實際意義,我們必須先選擇一個時間段。一個月是一個不錯的選擇。此時,正常運行時間目標的確切表述可能是"網站服務在一個公曆月內宕機時間不得超過總共運行時間的0.1%"。

為服務水平指標添加這樣一個條件可將其轉換為服務水平目標(SLO,Service Level Objective)。2016年7月共有44640分鐘。這意味著在未達到服務水平目標前,我們總共有44.6分鐘的宕機時間。這通常被稱為"錯誤預算"。

因此我們可以說在2016年7月份,GitHub的網站服務消耗了44分鐘錯誤預算中的54分鐘,因此,它以10分鐘的差距未達到99.9%的服務水平目標。

將服務水平目標可視化的典型方法是在給定時間段內累積錯誤時間,在我們的例子中,累計計算的時間段是七月的31天時間。接下來的查詢語句統計了七月份的累積宕機時間。

#StandardSQLnSELECT m, cumulative_down, next_cumnFROM (n SELECT m, cumulative_down, LEAD(cumulative_down) OVER(ORDER BY m) next_cum, MIN(m) OVER() min_m, MAX(m) OVER() max_mn FROM (n SELECT m, SUM(IF(c <= 20, 1, 0)) OVER(ORDER BY m ROWS BETWEEN 43200 PRECEDING AND CURRENT ROW) cumulative_downn FROM (n SELECT m, c, 1 as downn FROM `fh-bigquery.public_dump.events_per_minute_201606` UNION ALLn SELECT m, c, 1 as downn FROM `fh-bigquery.public_dump.events_per_minute_201607` UNION ALLn SELECT m, c, 1 as downn FROM `fh-bigquery.public_dump.events_per_minute_201608`)n )n )nWHERE cumulative_down!=next_cum nOR m IN (min_m, max_m)nORDER BY mn

根據查詢結果我們繪製了下圖。圖中折線的階躍對應於"中斷"的情況。中斷時間越長,階躍的幅度越大。當折線越過44分鐘時,我們的宕機時間已經超過了錯誤預算,稱該服務在30天的時間窗口內"未達到服務水平協議的要求"。

我們的分析表明,兩次中斷消耗了大部分的錯誤預算,一次是在月中,而另一次則發生在月末。事實上,如果我們查看GitHub的狀態日誌,我們可以看到GitHub在7月12日的報告中記錄了"異常率激增"的情況,並在7月27日的報告中記錄了"主要服務中斷"。

儘管服務水平目標有時按照公曆月定義,但是這樣的定義方式有時會給工程師帶來困擾,主要有兩個原因。首先,"公曆月"並不是一個固定的時間跨度。一個公曆月可能有28天也可能有31天,這取決於當前時間碰巧屬於哪個月份。其次,這樣的定義使個別幾天變得非常特殊,錯誤預算在這幾天會被神奇地重置。例如,對於一個服務水平目標為公曆月99.9%正常運行時間的服務,可能在7月31日發生44分鐘的中斷,並且在8月1日又遭受另一次中斷,這種情況下只要該服務在這兩個月未發生其他中斷,我們仍稱其達到了服務水平目標,儘管該服務在48小時內總共發生了88分鐘的中斷。

為了解決這些不一致的現象,服務水平目標通常採用30天滑動窗口的形式定義 ,而非公曆月的形式。在不考慮閏秒的情況下,30天相比於公曆月,是一個固定的時間跨度。而且,使用滑動窗口的方式也可以解決前面討論的第二個問題。假設在7月31日和8月1日發生的兩次44分鐘中斷將使該服務在8月1日中斷髮生後,便"超過服務水平目標的要求",直到7月31日的中斷脫離30天滑動窗口的範圍。

這一點很重要,因為"超過服務水平目標的要求"應該引起負責團隊的注意,並採取更為保守有效的決策。例如,如果你提供的服務"未達到服務水平目標",那麼現在可能不是進行關鍵軟體升級的最佳時機。48小時內88分鐘的宕機時間足以令一個需達到99.9%服務水平目標的團隊採取更保守的措施。第一個基於公曆月的服務水平目標定義無法做到這一點,而第二個基於30天滑動窗口的定義則可以。

BigQuery可以輕鬆地跨多個日期分片表進行查詢,因此,我們可以為2016年6月,7月和8月的數據創建類似的視圖,同時,我們可以使用OVER子句來計算滑動窗口內的累積中斷時間(30天,共43200分鐘):

#StandardSQL SELECT m, cumulative_down, next_cum FROM ( SELECT m, cumulative_down, LEAD(cumulative_down) OVER(ORDER BY m) next_cum, MIN(m) OVER() min_m, MAX(m) OVER() max_m FROM ( SELECT m, SUM(IF(cn

當我們為這份新的滑動窗口數據繪製圖表時,我們可以清楚地看到GitHub的網站服務在七月下旬至八月上旬期間未到達服務水平目標(即圖中折線超過43)的時間段。我們也可以清楚地看到服務在八月份逐漸回到了服務水平目標要求的水平,在這個時候,關於服務的相關決策與措施可"一切照舊"。

截止到目前,我們還未討論過服務水平協議(SLA,Service Level Agreement)。我們刻意這樣做。服務水平指標代表著一項服務的健康與否。而服務水平目標旨在為確定何時適合執行風險較高的操作,如主要服務升級,提供保障。服務水平協議是服務提供商與其客戶之間的法律協議,通常對違反服務水平協議的情況指定罰金,例如服務信用等。一個服務水平協議一般應對應多個服務水平目標,因為服務水平目標指導我們如何操作服務,但服務水平協議在不同情況下通常指定不同的細節與閾值。例如,儘管我們已經觀察到30天滑動窗口更有利於指導服務相關的操作,但是為了簡單期間,法律合同通常還是會按照公曆月的形式編寫。此外,服務水平目標的閾值通常比服務水平協議的閾值更加保守。例如,服務水平目標閾值可定為99.9%,但在服務水平協議中,有可能會產生罰金的閾值可能會設置為99.5%。

在GitHub的具體示例中,它們的服務條款並沒有提到"服務水平協議"。實際上,GitHub聲明該網站服務基於"原生"與"可用"的原則提供的。缺少服務水平協議是否就意味著GitHub不關心網站的可靠性?當然不是!實際上Github上線了記錄網站狀態的網頁,這表明他們不僅測量並跟蹤其網站的可靠性,同時也對其用戶保持透明公開。

在這一點上,我們應該注意到,為了在圖表中展示一些有趣的東西,我們預先使用特定的查詢對數據進行了略微的處理,以便於找到一個日期相對較近且發生了一兩次中斷的月份,我們通過使用GitHub的狀態存檔來確認中斷是否是真實發生的。如果我們在前面的例子中選擇了八月份,那麼這將是一篇非常無聊的文章,因為GitHub在八月的可靠性是100%。幹得不錯,GitHub!

以上為譯文

本文由北郵@愛可可-愛生活 老師推薦,阿里云云棲社區組織翻譯。

文章原標題《A Google SRE explores GitHub reliability with BigQuery》,作者:Felipe Hoffa,譯者:6816816151

文章為簡譯,更為詳細的內容,請查看原文


推薦閱讀:

圖文詳解如何利用Git+Github進行團隊協作開發
GitHub 是識別用戶的機制是怎樣的?
觀察:阿里巴巴的開源戰略究竟怎麼樣?
平時你使用Git的workflow是怎樣的?
12 件可以用 GitHub 完成的很酷的事情

TAG:GitHub | bigquery | 编程学习 |