79 KiB
title | weight | math | breadcrumbs |
---|---|---|---|
2. 定義非功能性需求 | 102 | true | false |
網際網路做得如此之好,以至於大多數人認為它是一種自然資源,就像太平洋一樣,而不是人造的東西。上一次有這種規模的技術如此沒有錯誤是什麼時候?
Alan Kay, 在接受 Dr Dobb's Journal 採訪時(2012)
如果你正在構建一個應用程式,你將受到一系列需求的驅動。在你的列表頂部,最可能的是應用程式必須提供的功能:你需要什麼螢幕和什麼按鈕,以及每個操作應該做什麼以實現你的軟體目的。這些是你的 功能性需求。
此外,你可能還有一些 非功能性需求:例如,應用程式應該快速、可靠、安全、合規,並且易於維護。這些需求可能沒有明確寫下來,因為它們可能看起來有些顯而易見,但它們和應用程式的功能一樣重要:一個慢得難以忍受或不可靠的應用程式可能等同於不存在。
許多非功能性需求,如安全性,超出了本書的範圍。但是有一些非功能性需求我們將考慮,本章將幫助你為自己的系統闡明它們:
- 如何定義和衡量系統的 效能(參見 "描述效能");
- 服務 可靠 意味著什麼——即使在出現問題時也能繼續正確工作(參見 "可靠性和容錯");
- 透過在系統負載增長時有效新增計算能力的方法,使系統具有 可擴充套件性(參見 "可擴充套件性");以及
- 使系統在長期內更容易維護(參見 "可維護性")。
本章介紹的術語在後續章節中也很有用,當我們深入瞭解資料密集型系統的實現細節時。然而,抽象定義可能相當枯燥;為了讓這些想法更具體,我們將以一個社交網路服務如何工作的案例研究開始本章,這將提供效能和可擴充套件性的實際示例。
案例研究:社交網路首頁時間線
想象一下,你被賦予實現一個 X(前 Twitter)風格的社交網路的任務,使用者可以釋出訊息並關注其他使用者。這將是對這種服務實際工作方式的巨大簡化 1 2 3,但它將有助於說明大規模系統中出現的一些問題。
假設使用者每天釋出 5 億條訊息,平均每秒 5,700 條帖子。偶爾,速率可能飆升至每秒 150,000 條帖子 4。我們還假設平均使用者關注 200 人,並有 200 個粉絲(儘管範圍很廣:大多數人只有少數粉絲,而少數名人如巴拉克·奧巴馬有超過 1 億粉絲)。
表示使用者、帖子與關注關係
想象我們將所有資料儲存在關係資料庫中,如 圖 2-1 所示。我們有一個使用者表,一個帖子表,和一個關注關係表。
{{< figure src="/fig/ddia_0201.png" id="fig_twitter_relational" caption="圖 2-1. 使用者可以相互關注的社交網路的簡單關係模式。" class="w-full my-4" >}}
假設我們的社交網路必須支援的主要讀取操作是 主頁時間線,它顯示你關注的人最近的帖子(為簡單起見,我們將忽略廣告、來自你未關注的人的建議帖子和其他擴充套件)。我們可以編寫以下 SQL 查詢來獲取特定使用者的主頁時間線:
SELECT posts.*, users.* FROM posts
JOIN follows ON posts.sender_id = follows.followee_id
JOIN users ON posts.sender_id = users.id
WHERE follows.follower_id = current_user
ORDER BY posts.timestamp DESC
LIMIT 1000
要執行此查詢,資料庫將使用 follows
表查詢 current_user
關注的所有人,查詢這些使用者的最近帖子,並按時間戳排序以獲取任何被關注使用者的最新 1,000 條帖子。
帖子應該是及時的,所以假設在某人釋出帖子後,我們希望他們的粉絲能夠在 5 秒內看到它。一種方法是使用者的客戶端在使用者線上時每 5 秒重複上述查詢(這稱為 輪詢)。如果我們假設有 1000 萬用戶同時線上並登入,那意味著每秒執行查詢 200 萬次。即使你增加輪詢間隔,這也是很多的。
此外,上述查詢相當昂貴:如果你關注 200 人,它需要獲取這 200 人中每個人的最近帖子列表,併合並這些列表。每秒 200 萬次時間線查詢意味著資料庫需要每秒從某個傳送者查詢最近的帖子 4 億次——一個巨大的數字。這是平均情況。一些使用者關注數萬個帳戶;對他們來說,這個查詢執行起來非常昂貴,並且很難快速執行。
時間線的物化與更新
我們如何做得更好?首先,伺服器主動將新帖子推送給當前線上的任何粉絲,而不是輪詢,會更好。其次,我們應該預先計算上述查詢的結果,以便可以從快取中提供使用者對其主頁時間線的請求。
想象一下,對於每個使用者,我們儲存一個包含其主頁時間線的資料結構,即他們關注的人的最近帖子。每次使用者釋出帖子時,我們查詢他們的所有粉絲,並將該帖子插入每個粉絲的主頁時間線——就像將訊息投遞到郵箱一樣。現在當用戶登入時,我們可以簡單地給他們我們預先計算的主頁時間線。此外,要接收有關其時間線上任何新帖子的通知,使用者的客戶端只需訂閱新增到其主頁時間線的帖子流。
這種方法的缺點是,每次使用者釋出帖子時,我們現在需要做更多的工作,因為主頁時間線是需要更新的派生資料。該過程如 圖 2-2 所示。當一個初始請求導致執行幾個下游請求時,我們使用術語 扇出 來描述請求數量增加的因子。
{{< figure src="/fig/ddia_0202.png" id="fig_twitter_timelines" caption="圖 2-2. 扇出:將新帖子投遞給釋出帖子的使用者的每個粉絲。" class="w-full my-4" >}}
以每秒 5,700 條帖子的速率,如果平均帖子到達 200 個粉絲(即扇出因子為 200),我們將需要每秒執行超過 100 萬次主頁時間線寫入。這很多,但與我們否則必須執行的每秒 4 億次按傳送者的帖子查詢相比,這仍然是一個顯著的節省。
如果由於某些特殊事件導致帖子速率激增,我們不必立即進行時間線投遞——我們可以將它們排隊,並接受帖子暫時需要更長時間才能顯示在粉絲的時間線中。即使在這種負載峰值期間,時間線仍然可以快速載入,因為我們只是從快取中提供它們。
這種預先計算和更新查詢結果的過程稱為 物化,時間線快取是 物化檢視 的一個例子(我們將在 [Link to Come] 中進一步討論這個概念)。物化檢視加速了讀取,但作為回報,我們必須在寫入時做更多的工作。對於大多數使用者來說,寫入的成本是適度的,但社交網路還必須考慮一些極端情況:
- 如果使用者關注了大量帳戶,並且這些帳戶釋出了很多內容,那麼該使用者的物化時間線將有很高的寫入率。然而,在這種情況下,使用者實際上不太可能閱讀其時間線中的所有帖子,因此可以簡單地丟棄其時間線寫入的一部分,只向用戶顯示他們關注的帳戶的帖子樣本 5。
- 當擁有大量粉絲的名人帳戶釋出帖子時,我們必須做大量工作將該帖子插入其數百萬粉絲的主頁時間線。在這種情況下,不能丟棄其中一些寫入。解決此問題的一種方法是將名人帖子與其他人的帖子分開處理:我們可以透過單獨儲存名人帖子並在讀取物化時間線時將它們合併,從而節省將它們新增到數百萬時間線的工作。儘管有這些最佳化,在社交網路上處理名人可能需要大量基礎設施 6。
描述效能
大多數關於軟體效能的討論考慮兩種主要型別的指標:
- 響應時間
- 從使用者發出請求到收到請求答案的經過時間。測量單位是秒(或毫秒,或微秒)。
- 吞吐量
- 系統正在處理的每秒請求數,或每秒資料量。對於給定的硬體資源分配,存在可以處理的 最大吞吐量。測量單位是"每秒的某物"。
在社交網路案例研究中,"每秒帖子數"和"每秒時間線寫入數"是吞吐量指標,而"載入主頁時間線所需的時間"或"帖子投遞給粉絲所需的時間"是響應時間指標。
吞吐量和響應時間之間通常存在聯絡;圖 2-3 勾畫了線上服務的這種關係示例。當請求吞吐量低時,服務的響應時間低,但隨著負載增加,響應時間增加。這是因為 排隊:當請求到達高負載系統時,CPU 很可能已經在處理較早的請求,因此傳入的請求需要等待較早的請求完成。隨著吞吐量接近硬體可以處理的最大值,排隊延遲急劇增加。
{{< figure src="/fig/ddia_0203.png" id="fig_throughput" caption="圖 2-3. 當服務的吞吐量接近其容量時,由於排隊,響應時間急劇增加。" class="w-full my-4" >}}
[!TIP] 當過載系統無法恢復時
如果系統接近過載,吞吐量被推到接近極限,它有時會進入惡性迴圈,變得效率更低,因此更加過載。例如,如果有一長串請求等待處理,響應時間可能會增加到客戶端超時並重新發送其請求的程度。這導致請求率進一步增加,使問題變得更糟——重試風暴。即使負載再次降低,這樣的系統也可能保持過載狀態,直到重新啟動或以其他方式重置。這種現象被稱為 亞穩態故障,它可能導致生產系統中的嚴重中斷 7 8。
為了避免重試使服務過載,你可以在客戶端增加並隨機化連續重試之間的時間(指數退避 9 10),並暫時停止向最近返回錯誤或超時的服務傳送請求(使用 熔斷器 11 12 或 令牌桶 演算法 13)。伺服器還可以檢測何時接近過載並開始主動拒絕請求(負載卸除 14),併發送要求客戶端減速的響應(背壓 1 15)。排隊和負載均衡演算法的選擇也可能產生影響 16。
就效能指標而言,響應時間通常是使用者最關心的,而吞吐量決定了所需的計算資源(例如,你需要多少伺服器),因此決定了服務特定工作負載的成本。如果吞吐量可能增長超過當前硬體可以處理的範圍,則需要擴充套件容量;如果透過新增計算資源可以顯著增加其最大吞吐量,則稱系統是 可擴充套件的。
在本節中,我們將主要關注響應時間,我們將在 "可擴充套件性" 中回到吞吐量和可擴充套件性。
延遲與響應時間
"延遲"和"響應時間"有時可以互換使用,但在本書中,我們將以特定方式使用這些術語(如 圖 2-4 所示):
- 響應時間 是客戶端看到的;它包括系統中任何地方產生的所有延遲。
- 服務時間 是服務主動處理使用者請求的持續時間。
- 排隊延遲 可能發生在流程的幾個點:例如,在收到請求後,它可能需要等到 CPU 可用才能處理;如果同一臺機器上的其他任務通過出站網路介面傳送大量資料,響應資料包可能需要在傳送到網路之前進行緩衝。
- 延遲 是請求未被主動處理的時間的總稱,即它是 潛在的 時間。特別是,網路延遲 或 網路延遲 是指請求和響應在網路中傳輸所花費的時間。
{{< figure src="/fig/ddia_0204.png" id="fig_response_time" caption="圖 2-4. 響應時間、服務時間、網路延遲和排隊延遲。" class="w-full my-4" >}}
在 圖 2-4 中,時間從左到右流動,每個通訊節點顯示為水平線,請求或響應訊息顯示為從一個節點到另一個節點的粗對角箭頭。你將在本書的過程中經常遇到這種風格的圖表。
響應時間可能從一個請求到下一個請求顯著變化,即使你一遍又一遍地發出相同的請求。許多因素可能會增加隨機延遲:例如,上下文切換到後臺程序、網路資料包丟失和 TCP 重傳、垃圾回收暫停、強制從磁碟讀取的頁面錯誤、伺服器機架中的機械振動 17,或許多其他原因。我們將在 "超時和無界延遲" 中更詳細地討論這個主題。
排隊延遲通常佔響應時間變化的很大一部分。由於伺服器只能並行處理少量事物(例如,受其 CPU 核心數量的限制),只需要少量慢速請求就可以阻止後續請求的處理——這種效應稱為 隊頭阻塞。即使那些後續請求具有快速的服務時間,由於等待先前請求完成的時間,客戶端也會看到緩慢的整體響應時間。排隊延遲不是服務時間的一部分,因此在客戶端測量響應時間很重要。
平均值、中位數與百分位數
因為響應時間從一個請求到下一個請求各不相同,我們需要將其視為不是單個數字,而是可以測量的值的 分佈。在 圖 2-5 中,每個灰色條代表對服務的請求,其高度顯示該請求花費了多長時間。大多數請求相當快,但偶爾有 異常值 需要更長時間。網路延遲的變化也稱為 抖動。
{{< figure src="/fig/ddia_0205.png" id="fig_lognormal" caption="圖 2-5. 說明平均值和百分位數:對服務的 100 個請求樣本的響應時間。" class="w-full my-4" >}}
報告服務的 平均 響應時間是很常見的(技術上,算術平均值:即,將所有響應時間相加,然後除以請求數)。平均響應時間對於估計吞吐量限制很有用 18。然而,如果你想知道你的"典型"響應時間,平均值不是一個很好的指標,因為它不會告訴你有多少使用者實際經歷了那種延遲。
通常使用 百分位數 會更好。如果你將響應時間列表從最快到最慢排序,那麼 中位數 是中間點:例如,如果你的中位數響應時間是 200 毫秒,這意味著你的一半請求在不到 200 毫秒內返回,一半請求需要更長時間。這使中位數成為一個很好的指標,如果你想知道使用者通常需要等待多長時間。中位數也稱為 第 50 百分位數,有時縮寫為 p50。
為了弄清楚你的異常值有多糟糕,你可以檢視更高的百分位數:第 95、第 99 和 第 99.9 百分位數是常見的(縮寫為 p95、p99 和 p999)。它們是響應時間閾值,95%、99% 或 99.9% 的請求比該特定閾值快。例如,如果第 95 百分位響應時間是 1.5 秒,這意味著 100 個請求中有 95 個需要不到 1.5 秒,100 個請求中有 5 個需要 1.5 秒或更長時間。這在 圖 2-5 中有所說明。
響應時間的高百分位數,也稱為 尾延遲,很重要,因為它們直接影響使用者對服務的體驗。例如,亞馬遜根據第 99.9 百分位數描述內部服務的響應時間要求,即使它隻影響 1,000 個請求中的 1 個。這是因為請求最慢的客戶通常是那些在其帳戶上擁有最多資料的客戶,因為他們進行了許多購買——也就是說,他們是最有價值的客戶 19。透過確保網站對他們來說速度快,保持這些客戶滿意很重要。
另一方面,最佳化第 99.99 百分位數(10,000 個請求中最慢的 1 個)被認為對亞馬遜的目的來說太昂貴且收益不足。在非常高的百分位數下減少響應時間很困難,因為它們容易受到你無法控制的隨機事件的影響,而且收益遞減。
[!TIP] 響應時間對使用者的影響
直覺上似乎很明顯,快速服務比慢速服務對使用者更好 20。然而,令人驚訝的是,很難獲得可靠的資料來量化延遲對使用者行為的影響。
一些經常被引用的統計資料是不可靠的。2006 年,谷歌報告說,搜尋結果從 400 毫秒減慢到 900 毫秒與流量和收入下降 20% 相關 21。然而,2009 年穀歌的另一項研究報告說,延遲增加 400 毫秒僅導致每天搜尋減少 0.6% 22,同年必應發現載入時間增加兩秒使廣告收入減少 4.3% 23。來自這些公司的較新資料似乎沒有公開。
Akamai 最近的一項研究 24 聲稱響應時間增加 100 毫秒使電子商務網站的轉化率降低多達 7%;然而,仔細檢查後,同一研究顯示,非常 快 的頁面載入時間也與較低的轉化率相關!這個看似矛盾的結果可以解釋為載入最快的頁面通常是那些沒有有用內容的頁面(例如,404 錯誤頁面)。然而,由於該研究沒有努力將頁面內容的影響與載入時間的影響分開,其結果可能沒有意義。
雅虎的一項研究 25 比較了快速載入與慢速載入搜尋結果的點選率,控制了搜尋結果的質量。它發現當快速和慢速響應之間的差異為 1.25 秒或更多時,快速搜尋的點選次數增加 20-30%。
響應時間指標的應用
高百分位數在後端服務中尤其重要,這些服務在服務單個終端使用者請求時被多次呼叫。即使你並行進行呼叫,終端使用者請求仍然需要等待最慢的並行呼叫完成。只需要一個慢速呼叫就能使整個終端使用者請求變慢,如 圖 2-6 所示。即使只有一小部分後端呼叫很慢,如果終端使用者請求需要多個後端呼叫,獲得慢速呼叫的機會也會增加,因此更高比例的終端使用者請求最終會變慢(一種稱為 尾延遲放大 的效應 26)。
{{< figure src="/fig/ddia_0206.png" id="fig_tail_amplification" caption="圖 2-6. 當需要幾個後端呼叫來服務請求時,只需要一個慢速後端請求就能減慢整個終端使用者請求。" class="w-full my-4" >}}
百分位數通常用於 服務級別目標(SLO)和 服務級別協議(SLA)中,作為定義服務預期效能和可用性的方式 27。例如,SLO 可能為服務設定目標,使中位數響應時間小於 200 毫秒,第 99 百分位數低於 1 秒,並且至少 99.9% 的有效請求導致非錯誤響應。SLA 是一份合同,規定如果未滿足 SLO 會發生什麼(例如,客戶可能有權獲得退款)。至少這是基本思想;在實踐中,為 SLO 和 SLA 定義良好的可用性指標並不簡單 28 29。
[!TIP] 計算百分位數
如果你想將響應時間百分位數新增到服務的監控儀表板中,你需要持續高效地計算它們。例如,你可能希望保留過去 10 分鐘內請求響應時間的滾動視窗。每分鐘,你計算該視窗中值的中位數和各種百分位數,並將這些指標繪製在圖表上。
最簡單的實現是保留時間視窗內所有請求的響應時間列表,並每分鐘對該列表進行排序。如果這對你來說效率太低,有一些演算法可以以最小的 CPU 和記憶體成本計算百分位數的良好近似值。開源百分位數估計庫包括 HdrHistogram、t-digest 30 31、OpenHistogram 32 和 DDSketch 33。
請注意,對百分位數求平均值,例如,減少時間解析度或組合來自多臺機器的資料,在數學上是沒有意義的——聚合響應時間資料的正確方法是新增直方圖 34。
可靠性與容錯
每個人都對什麼是可靠或不可靠有直觀的想法。對於軟體,典型的期望包括:
- 應用程式執行使用者期望的功能。
- 它可以容忍使用者犯錯誤或以意外方式使用軟體。
- 它的效能對於所需的用例、預期的負載和資料量來說足夠好。
- 系統防止任何未經授權的訪問和濫用。
如果所有這些事情加在一起意味著"正確工作",那麼我們可以將 可靠性 理解為大致意思是"即使出現問題也能繼續正確工作"。為了更準確地說明出現問題,我們將區分 故障 和 失效 35 36 37:
- 故障
- 故障是系統的特定 部分 停止正確工作:例如,如果單個硬碟驅動器出現故障,或單臺機器崩潰,或系統依賴的外部服務出現中斷。
- 失效
- 失效是系統 作為一個整體 停止向用戶提供所需的服務;換句話說,當它不滿足服務級別目標(SLO)時。
故障和失效之間的區別可能令人困惑,因為它們是同一件事,只是在不同的級別。例如,如果硬碟驅動器停止工作,我們說硬碟驅動器已經失效:如果系統僅包含那一個硬碟驅動器,它已經停止提供所需的服務。然而,如果你談論的系統包含許多硬碟驅動器,那麼從更大系統的角度來看,單個硬碟驅動器的失效只是一個故障,更大的系統可能能夠透過在另一個硬碟驅動器上擁有資料副本來容忍該故障。
容錯
如果系統儘管發生某些故障仍繼續向用戶提供所需的服務,我們稱該系統為 容錯的。如果系統無法容忍某個部分出現故障,我們稱該部分為 單點故障(SPOF),因為該部分的故障會升級導致整個系統的失效。
例如,在社交網路案例研究中,可能發生的故障是在扇出過程中,參與更新物化時間線的機器崩潰或變得不可用。為了使此過程容錯,我們需要確保另一臺機器可以接管此任務,而不會錯過任何應該投遞的帖子,也不會複製任何帖子。(這個想法被稱為 精確一次語義,我們將在 [Link to Come] 中詳細研究它。)
容錯總是限於一定數量的某些型別的故障。例如,系統可能能夠容忍最多兩個硬碟驅動器同時故障,或最多三個節點中的一個崩潰。容忍任何數量的故障是沒有意義的:如果所有節點都崩潰,就無能為力了。如果整個地球(及其上的所有伺服器)被黑洞吞噬,容忍該故障將需要太空網路託管——祝你獲得該預算專案的批准好運。
違反直覺的是,在這種容錯系統中,透過故意觸發故障來 增加 故障率可能是有意義的——例如,透過在沒有警告的情況下隨機殺死單個程序。這稱為 故障注入。許多關鍵錯誤實際上是由於錯誤處理不當造成的 38;透過故意引發故障,你確保容錯機制得到持續鍛鍊和測試,這可以增加你對故障在自然發生時將被正確處理的信心。混沌工程 是一門學科,旨在透過故意注入故障等實驗來提高對容錯機制的信心 39。
儘管我們通常更喜歡容忍故障而不是預防故障,但有些情況下預防比治療更好(例如,因為不存在治療方法)。例如,安全事項就是這種情況:如果攻擊者已經入侵了系統並獲得了對敏感資料的訪問,該事件無法撤消。然而,本書主要處理可以治癒的故障型別,如以下各節所述。
硬體與軟體故障
當我們考慮系統故障的原因時,硬體故障很快就會浮現在腦海中:
- 大約 2-5% 的磁性硬碟驅動器每年故障 40 41;在擁有 10,000 個磁碟的儲存叢集中,我們因此應該預期平均每天有一個磁碟故障。最近的資料表明磁碟變得更可靠,但故障率仍然很高 42。
- 大約 0.5-1% 的固態驅動器(SSD)每年故障 43。少量的位錯誤會自動糾正 44,但不可糾正的錯誤大約每年每個驅動器發生一次,即使在相當新的驅動器中(即,經歷過很少磨損);這個錯誤率高於磁性硬碟驅動器 45、46。
- 其他硬體元件,如電源、RAID 控制器和記憶體模組也會故障,儘管頻率低於硬碟驅動器 47 48。
- 大約千分之一的機器有一個 CPU 核心偶爾會計算錯誤的結果,可能是由於製造缺陷 49 50 51。在某些情況下,錯誤的計算會導致崩潰,但在其他情況下,它會導致程式簡單地返回錯誤的結果。
- RAM 中的資料也可能被損壞,要麼是由於宇宙射線等隨機事件,要麼是由於永久性物理缺陷。即使使用帶有糾錯碼(ECC)的記憶體,超過 1% 的機器在給定年份中遇到不可糾正的錯誤,這通常會導致機器崩潰和受影響的記憶體模組需要更換 52。此外,某些病理記憶體訪問模式可以高機率翻轉位 53。
- 整個資料中心可能變得不可用(例如,由於停電或網路配置錯誤)甚至被永久破壞(例如,因火災、洪水或地震 54)。太陽風暴在太陽噴射大量帶電粒子時在長距離電線中感應大電流,可能會損壞電網和海底網路電纜 55。儘管這種大規模故障很少見,但如果服務無法容忍資料中心的丟失,它們的影響可能是災難性的 56。
這些事件足夠罕見,以至於在處理小型系統時你通常不需要擔心它們,只要你可以輕鬆更換有故障的硬體。然而,在大規模系統中,硬體故障發生得足夠頻繁,以至於它們成為正常系統操作的一部分。
透過冗餘容忍硬體故障
我們對不可靠硬體的第一反應通常是向單個硬體元件新增冗餘,以降低系統的故障率。磁碟可以設定為 RAID 配置(將資料分佈在同一臺機器中的多個磁碟上,以便故障磁碟不會導致資料丟失),伺服器可能有雙電源和可熱插拔的 CPU,資料中心可能有電池和柴油發電機作為備用電源。這種冗餘通常可以使機器無中斷執行多年。
當元件故障是獨立的時,冗餘最有效,即一個故障的發生不會改變另一個故障發生的可能性。然而,經驗表明,元件故障之間通常存在顯著相關性 41 57 58;整個伺服器機架或整個資料中心的不可用仍然比我們希望的更頻繁。
硬體冗餘增加了單臺機器的正常執行時間;然而,如 "分散式與單節點系統" 中所討論的,使用分散式系統有一些優勢,例如能夠容忍一個數據中心的完全中斷。出於這個原因,雲系統傾向於較少關注單個機器的可靠性,而是旨在透過在軟體級別容忍故障節點來使服務高度可用。雲提供商使用 可用區 來識別哪些資源在物理上位於同一位置;同一地方的資源比地理上分離的資源更有可能同時故障。
我們在本書中討論的容錯技術旨在容忍整個機器、機架或可用區的丟失。它們通常透過允許一個數據中心的機器在另一個數據中心的機器故障或變得無法訪問時接管來工作。我們將在 第 6 章、第 10 章 以及本書的其他各個點討論這種容錯技術。
可以容忍整個機器丟失的系統也具有操作優勢:如果你需要重新啟動機器(例如,應用作業系統安全補丁),單伺服器系統需要計劃停機時間,而多節點容錯系統可以透過一次重新啟動一個節點來打補丁,而不會影響使用者的服務。這稱為 滾動升級,我們將在 第 5 章 中進一步討論它。
軟體故障
儘管硬體故障可能是弱相關的,但它們仍然大多是獨立的:例如,如果一個磁碟故障,同一臺機器中的其他磁碟很可能在一段時間內仍然正常。另一方面,軟體故障通常高度相關,因為許多節點執行相同的軟體並因此具有相同的錯誤是很常見的 59 60。這種故障更難預測,它們往往比不相關的硬體故障導致更多的系統故障 47。例如:
- 導致每個節點在特定情況下同時故障的軟體錯誤。例如,2012 年 6 月 30 日,閏秒導致許多 Java 應用程式由於 Linux 核心中的錯誤而同時掛起,導致許多網際網路服務癱瘓 61。由於韌體錯誤,某些型號的所有 SSD 在精確執行 32,768 小時(不到 4 年)後突然故障,使其上的資料無法恢復 62。
- 使用某些共享、有限資源的失控程序,例如 CPU 時間、記憶體、磁碟空間、網路頻寬或執行緒 63。例如,在處理大型請求時消耗過多記憶體的程序可能會被作業系統殺死。客戶端庫中的錯誤可能導致比預期更高的請求量 64。
- 系統依賴的服務變慢、無響應或開始返回損壞的響應。
- 不同系統之間的互動導致在每個系統單獨測試時不會發生的緊急行為 65。
- 級聯故障,其中一個元件中的問題導致另一個元件過載並減速,這反過來又導致另一個元件癱瘓 66 67。
導致這些軟體故障的錯誤通常會潛伏很長時間,直到它們被一組不尋常的情況觸發。在這些情況下,會發現軟體對其環境做出了某種假設——雖然該假設通常是正確的,但由於某種原因它最終不再正確 68 69。
軟體中系統性故障的問題沒有快速解決方案。許多小事情可以幫助:仔細考慮系統中的假設和互動;徹底測試;程序隔離;允許程序崩潰並重新啟動;避免反饋迴圈,如重試風暴(參見 "當過載系統無法恢復時");測量、監控和分析生產中的系統行為。
人類與可靠性
人類設計和構建軟體系統,保持系統執行的操作員也是人類。與機器不同,人類不只是遵循規則;他們的力量在於在完成工作時具有創造性和適應性。然而,這一特性也導致了不可預測性,有時儘管有最好的意圖,但會犯錯誤,導致故障。例如,一項對大型網際網路服務的研究發現,操作員的配置更改是中斷的主要原因,而硬體故障(伺服器或網路)僅在 10-25% 的中斷中發揮作用 70。
將這些問題標記為"人為錯誤"並希望透過更嚴格的程式和規則合規來更好地控制人類行為來解決它們是很誘人的。然而,為錯誤責怪人們是適得其反的。我們所說的"人為錯誤"實際上不是事件的原因,而是人們盡力完成工作的社會技術系統中問題的症狀 71。通常,複雜系統具有緊急行為,其中元件之間的意外互動也可能導致故障 72。
各種技術措施可以幫助最小化人為錯誤的影響,包括徹底測試(手寫測試和對大量隨機輸入的 屬性測試)38、用於快速恢復配置更改的回滾機制、新程式碼的逐步推出、詳細而清晰的監控、用於診斷生產問題的可觀察性工具(參見 "分散式系統的問題"),以及設計良好的介面,鼓勵"正確的事情"並阻止"錯誤的事情"。
然而,這些事情需要時間和金錢的投資,在日常業務的實用現實中,組織通常優先考慮創收活動,而不是增加其對錯誤的彈性的措施。如果在更多功能和更多測試之間有選擇,許多組織可以理解地選擇功能。鑑於這種選擇,當不可避免地發生可預防的錯誤時,責怪犯錯誤的人是沒有意義的——問題是組織的優先事項。
越來越多的組織正在採用 無責備事後分析 的文化:在事件發生後,鼓勵參與的人員分享關於發生的事情的全部細節,而不必擔心受到懲罰,因為這使組織中的其他人能夠學習如何在未來防止類似的問題 73。這個過程可能會發現需要改變業務優先順序、需要投資被忽視的領域、需要改變相關人員的激勵措施,或者需要引起管理層注意的其他系統性問題。
作為一般原則,在調查事件時,你應該對簡單的答案持懷疑態度。"鮑勃在部署該更改時應該更加小心"是沒有成效的,但"我們必須用 Haskell 重寫後端"也不是。相反,管理層應該藉此機會從每天使用它的人的角度瞭解社會技術系統如何工作的細節,並根據這些反饋採取措施改進它 71。
[!TIP] 可靠性有多重要?
可靠性不僅適用於核電站和空中交通管制——更平凡的應用程式也應該可靠地工作。業務應用程式中的錯誤會導致生產力損失(如果數字報告不正確,還會帶來法律風險),電子商務網站的中斷可能會在收入損失和聲譽損害方面造成巨大成本。
在許多應用程式中,幾分鐘甚至幾小時的臨時中斷是可以容忍的 74,但永久的資料丟失或損壞將是災難性的。考慮一位父母,他將所有孩子的照片和影片儲存在你的照片應用程式中 75。如果該資料庫突然損壞,他們會有什麼感覺?他們會知道如何從備份中恢復嗎?
作為不可靠軟體如何傷害人們的另一個例子,考慮郵局地平線醜聞。1999 年至 2019 年間,數百名管理英國郵局分支機構的人因盜竊或欺詐而被定罪,因為會計軟體顯示他們的賬戶有短缺。最終,很明顯,這些短缺中的許多是由於軟體中的錯誤造成的,許多定罪此後已被推翻 76。導致這一可能是英國曆史上最大的司法不公的是,英國法律假定計算機正確執行(因此,計算機產生的證據是可靠的),除非有相反的證據 77。軟體工程師可能會嘲笑軟體可能永遠沒有錯誤的想法,但這對那些因不可靠的計算機系統而被錯誤監禁、宣佈破產,甚至因錯誤定罪而自殺的人來說是很少的安慰。
在某些情況下,我們可能會選擇犧牲可靠性以降低開發成本(例如,在為未經證實的市場開發原型產品時)——但我們應該非常清楚何時在偷工減料,並牢記潛在的後果。
可伸縮性
即使系統今天可靠地工作,這並不意味著它將來一定會可靠地工作。降級的一個常見原因是負載增加:也許系統已經從 10,000 個併發使用者增長到 100,000 個併發使用者,或者從 100 萬增長到 1000 萬。也許它正在處理比以前大得多的資料量。
可擴充套件性 是我們用來描述系統處理負載增加的能力的術語。有時,在討論可擴充套件性時,人們會發表類似"你不是谷歌或亞馬遜。停止擔心規模,只使用關係資料庫"的評論。這個格言是否適用於你取決於你正在構建的應用程式型別。
如果你正在構建一個目前只有少數使用者的新產品,也許在一家初創公司,那麼首要的工程目標通常是保持系統儘可能簡單和靈活,以便你可以輕鬆修改和調整產品的功能,因為你瞭解更多關於客戶需求的資訊 78。在這樣的環境中,擔心未來可能需要的假設規模是適得其反的:在最好的情況下,對可擴充套件性的投資是浪費的努力和過早的最佳化;在最壞的情況下,它們會將你鎖定在不靈活的設計中,並使你更難發展你的應用程式。
原因是可擴充套件性不是一維標籤:說"X 是可擴充套件的"或"Y 不擴充套件"是沒有意義的。相反,討論可擴充套件性意味著考慮以下問題:
- "如果系統以特定方式增長,我們有哪些選擇來應對增長?"
- "我們如何新增計算資源來處理額外的負載?"
- "根據當前的增長預測,我們何時會達到當前架構的極限?"
如果你成功地使你的應用程式流行,因此處理越來越多的負載,你將瞭解你的效能瓶頸在哪裡,因此你將知道你需要在哪些維度上擴充套件。那時是開始擔心可擴充套件性技術的時候了。
描述負載
首先,我們需要簡潔地描述系統上的當前負載;只有這樣我們才能討論增長問題(如果我們的負載翻倍會發生什麼?)。通常這將是吞吐量的度量:例如,服務的每秒請求數、每天到達的新資料的千兆位元組數,或每小時購物車結賬的數量。有時你關心某些可變數量的峰值,例如 "案例研究:社交網路主頁時間線" 中同時線上使用者的數量。
通常,負載的其他統計特徵也會影響訪問模式,從而影響可擴充套件性要求。例如,你可能需要知道資料庫中讀取與寫入的比率、快取的命中率或每個使用者的資料項數(例如,社交網路案例研究中的粉絲數)。也許平均情況對你很重要,或者你的瓶頸可能由少數極端情況主導。這一切都取決於你特定應用程式的細節。
一旦你描述了系統上的負載,你就可以研究負載增加時會發生什麼。你可以從兩個方面來看:
- 當你以某種方式增加負載並保持系統資源(CPU、記憶體、網路頻寬等)不變時,你的系統性能如何受到影響?
- 當你以某種方式增加負載時,如果你想保持效能不變,你需要增加多少資源?
通常我們的目標是在滿足 SLA 要求的同時保持系統的效能(參見 "響應時間指標的使用"),同時最小化執行系統的成本。所需的計算資源越多,成本就越高。可能某些型別的硬體比其他型別更具成本效益,隨著新型硬體的出現,這些因素可能會隨著時間而改變。
如果你可以加倍資源以處理兩倍的負載,同時保持效能相同,我們說你有 線性可擴充套件性,這被認為是一件好事。偶爾可以用少於兩倍的資源處理兩倍的負載,這是由於規模經濟或峰值負載的更好分佈 79 80。更有可能的是,成本增長速度快於線性,效率低下可能有很多原因。例如,如果你有大量資料,那麼處理單個寫入請求可能涉及比你有少量資料時更多的工作,即使請求的大小相同。
共享記憶體、共享磁碟與無共享架構
增加服務硬體資源的最簡單方法是將其移動到更強大的機器。單個 CPU 核心不再變得明顯更快,但你可以購買(或租用雲實例)具有更多 CPU 核心、更多 RAM 和更多磁碟空間的機器。這種方法稱為 垂直擴充套件 或 縱向擴充套件。
你可以透過使用多個程序或執行緒在單臺機器上獲得並行性。屬於同一程序的所有執行緒都可以訪問相同的 RAM,因此這種方法也稱為 共享記憶體架構。共享記憶體方法的問題是成本增長速度快於線性:具有兩倍硬體資源的高階機器通常成本遠遠超過兩倍。由於瓶頸,兩倍大小的機器通常可以處理不到兩倍的負載。
另一種方法是 共享磁碟架構,它使用具有獨立 CPU 和 RAM 的幾臺機器,但將資料儲存在機器之間共享的磁碟陣列上,它們透過快速網路連線:網路附加儲存(NAS)或 儲存區域網路(SAN)。這種架構傳統上用於本地資料倉庫工作負載,但爭用和鎖定的開銷限制了共享磁碟方法的可擴充套件性 81。
相比之下,無共享架構 82(也稱為 水平擴充套件 或 橫向擴充套件)已經獲得了很大的普及。在這種方法中,我們使用具有多個節點的分散式系統,每個節點都有自己的 CPU、RAM 和磁碟。節點之間的任何協調都在軟體級別透過傳統網路完成。
無共享的優點是它具有線性擴充套件的潛力,它可以使用提供最佳價效比的任何硬體(特別是在雲中),它可以在負載增加或減少時更輕鬆地調整其硬體資源,並且它可以透過在多個數據中心和區域分佈系統來實現更高的容錯性。缺點是它需要顯式分片(參見 第 7 章),並且會產生分散式系統的所有複雜性(第 9 章)。
一些雲原生資料庫系統使用單獨的服務進行儲存和事務執行(參見 "儲存和計算分離"),多個計算節點共享對同一儲存服務的訪問。該模型與共享磁碟架構有一些相似之處,但它避免了舊系統的可擴充套件性問題:它不提供檔案系統(NAS)或塊裝置(SAN)抽象,而是提供專門為資料庫的特定需求設計的專用 API 83。
可伸縮性原則
大規模執行的系統架構通常高度特定於應用程式——沒有通用的、一刀切的可擴充套件架構(非正式地稱為 萬金油)。例如,設計用於處理每秒 100,000 個請求(每個 1 kB 大小)的系統與設計用於每分鐘 3 個請求(每個 2 GB 大小)的系統看起來非常不同——即使兩個系統具有相同的資料吞吐量(100 MB/秒)。
此外,適合一個負載級別的架構不太可能應對 10 倍的負載。如果你正在處理快速增長的服務,因此你可能需要在每個數量級負載增加時重新考慮你的架構。由於應用程式的需求可能會發展,通常不值得提前規劃未來的擴充套件需求超過一個數量級。
可擴充套件性的一個良好通用原則是將系統分解為可以在很大程度上相互獨立執行的較小元件。這是微服務背後的基本原則(參見 "微服務和無伺服器")、分片(第 7 章)、流處理([Link to Come])和無共享架構。然而,挑戰在於知道在哪裡劃定應該在一起的事物和應該分開的事物之間的界限。微服務的設計指南可以在其他書籍中找到 84,我們在 第 7 章 中討論無共享系統的分片。
另一個好原則是不要讓事情變得比必要的更複雜。如果單機資料庫可以完成工作,它可能比複雜的分散式設定更可取。自動擴充套件系統(根據需求自動新增或刪除資源)很酷,但如果你的負載相當可預測,手動擴充套件的系統可能會有更少的操作意外(參見 "操作:自動或手動再平衡")。具有五個服務的系統比具有五十個服務的系統更簡單。良好的架構通常涉及方法的實用混合。
可運維性
軟體不會磨損或遭受材料疲勞,因此它不會像機械物體那樣破壞。但是應用程式的需求經常變化,軟體執行的環境發生變化(例如其依賴項和底層平臺),並且它有需要修復的錯誤。
人們普遍認識到,軟體的大部分成本不在於其初始開發,而在於其持續維護——修復錯誤、保持系統執行、調查故障、使其適應新平臺、為新用例修改它、償還技術債務以及新增新功能 85 86。
然而,維護也很困難。如果系統已成功執行很長時間,它可能會使用今天很少有工程師理解的過時技術(例如大型機和 COBOL 程式碼);關於系統如何以及為什麼以某種方式設計的機構知識可能會隨著人們離開組織而丟失;可能有必要修復其他人的錯誤。此外,計算機系統通常與它支援的人類組織交織在一起,這意味著這種 遺留 系統的維護既是人的問題,也是技術問題 87。
我們今天建立的每個系統如果有足夠的價值能夠存活很長時間,有一天會成為遺留系統。為了最大限度地減少未來需要維護我們軟體的幾代人的痛苦,我們應該在設計時考慮維護問題。儘管我們不能總是預測哪些決定可能在未來造成維護麻煩,但在本書中,我們將關注幾個廣泛適用的原則:
- 可運維性
- 使組織能夠輕鬆地保持系統平穩執行。
- 簡單性
- 透過使用易於理解、一致的模式和結構來實現系統,並避免不必要的複雜性,使新工程師能夠輕鬆理解系統。
- 可演化性
- 使工程師能夠輕鬆地在未來對系統進行更改,隨著需求的變化而調整和擴充套件它以適應意外的用例。
可運維性:讓運維更輕鬆
我們之前在 "雲時代的運維" 中討論了運維的作用,我們看到人類流程對於可靠運維至少與軟體工具一樣重要。事實上,有人建議"良好的運維通常可以解決糟糕(或不完整)軟體的限制,但良好的軟體無法透過糟糕的運維可靠地執行" 60。
在由數千臺機器組成的大規模系統中,手動維護將是不合理的昂貴,自動化是必不可少的。然而,自動化可能是一把雙刃劍:總會有邊緣情況(例如罕見的故障場景)需要運維團隊的手動干預。由於無法自動處理的情況是最複雜的問題,更大的自動化需要一個 更 熟練的運維團隊來解決這些問題 88。
此外,如果自動化系統出錯,它通常比依賴操作員手動執行某些操作的系統更難排除故障。出於這個原因,更多的自動化並不總是對可操作性更好。然而,一定量的自動化很重要,最佳點將取決於你特定應用程式和組織的具體情況。
良好的可操作性意味著使例行任務變得容易,允許運維團隊將精力集中在高價值活動上。資料系統可以做各種事情來使例行任務變得容易,包括 89:
- 允許監控工具檢查系統的關鍵指標,並支援可觀察性工具(參見 "分散式系統的問題")以深入瞭解系統的執行時行為。各種商業和開源工具可以在這裡提供幫助 90。
- 避免對單個機器的依賴(允許在系統作為一個整體繼續不間斷執行的同時關閉機器進行維護)
- 提供良好的文件和易於理解的操作模型("如果我做 X,Y 將發生")
- 提供良好的預設行為,但也給管理員在需要時覆蓋預設值的自由
- 在適當的情況下自我修復,但也在需要時為管理員提供對系統狀態的手動控制
- 表現出可預測的行為,最大限度地減少意外
簡單性:管理複雜度
小型軟體專案可以擁有令人愉快的簡單和富有表現力的程式碼,但隨著專案變大,它們通常變得非常複雜且難以理解。這種複雜性減慢了每個需要在系統上工作的人的速度,進一步增加了維護成本。陷入複雜性的軟體專案有時被描述為 大泥球 91。
當複雜性使維護變得困難時,預算和時間表經常被超支。在複雜的軟體中,進行更改時引入錯誤的風險也更大:當系統對開發人員來說更難理解和推理時,隱藏的假設、意外的後果和意外的互動更容易被忽視 69。相反,降低複雜性極大地提高了軟體的可維護性,因此簡單性應該是我們構建的系統的關鍵目標。
簡單的系統更容易理解,因此我們應該嘗試以最簡單的方式解決給定的問題。不幸的是,說起來容易做起來難。某事是否簡單通常是主觀品味問題,因為沒有客觀的簡單性標準 92。例如,一個系統可能會在簡單介面後面隱藏複雜的實現,而另一個系統可能有一個向其使用者公開更多內部細節的簡單實現——哪個更簡單?
推理複雜性的一種嘗試是將其分為兩類,基本 和 偶然 複雜性 93。想法是基本複雜性是應用程式問題域中固有的,而偶然複雜性僅由於我們工具的限制而產生。不幸的是,這種區別也是有缺陷的,因為隨著我們的工具發展,基本和偶然之間的界限會發生變化 94。
我們管理複雜性的最佳工具之一是 抽象。良好的抽象可以在乾淨、易於理解的外觀後面隱藏大量的實現細節。良好的抽象也可以用於各種不同的應用程式。這種重用不僅比多次重新實現類似的東西更有效,而且還導致更高質量的軟體,因為抽象元件中的質量改進使所有使用它的應用程式受益。
例如,高階程式語言是隱藏機器程式碼、CPU 暫存器和系統呼叫的抽象。SQL 是隱藏複雜的磁碟和記憶體資料結構、來自其他客戶端的併發請求以及崩潰後不一致的抽象。當然,在高階語言中程式設計時,我們仍在使用機器程式碼;我們只是不 直接 使用它,因為程式語言抽象使我們免於思考它。
應用程式程式碼的抽象,旨在降低其複雜性,可以使用 設計模式 95 和 領域驅動設計(DDD)96 等方法建立。本書不是關於這種特定於應用程式的抽象,而是關於你可以在其上構建應用程式的通用抽象,例如資料庫事務、索引和事件日誌。如果你想使用 DDD 等技術,你可以在本書中描述的基礎之上實現它們。
可演化性:讓變化更容易
你的系統需求極不可能永遠保持不變。它們更有可能處於不斷變化中:你學習新事實,以前意料之外的用例出現,業務優先順序發生變化,使用者請求新功能,新平臺取代舊平臺,法律或監管要求發生變化,系統的增長迫使架構變化等。
就組織流程而言,敏捷 工作模式為適應變化提供了一個框架。敏捷社群還開發了在頻繁變化的環境中開發軟體時有用的技術工具和流程,例如測試驅動開發(TDD)和重構。在本書中,我們尋找在由幾個具有不同特徵的不同應用程式或服務組成的系統級別提高敏捷性的方法。
你可以修改資料系統並使其適應不斷變化的需求的難易程度與其簡單性及其抽象密切相關:鬆散耦合、簡單的系統通常比緊密耦合、複雜的系統更容易修改。由於這是一個如此重要的想法,我們將使用不同的詞來指代資料系統級別的敏捷性:可演化性 97。
使變化變得困難的一個主要因素是當某些行動是不可逆的,因此需要非常小心地採取該行動 98。例如,假設你正在從一個數據庫遷移到另一個數據庫:如果你無法在新資料庫出現問題時切換回舊系統,那麼風險比你可以輕鬆返回時要高得多。最小化不可逆性可以提高靈活性。
總結
在本章中,我們研究了幾個非功能性需求的示例:效能、可靠性、可擴充套件性和可維護性。透過這些主題,我們還遇到了我們在本書其餘部分所需的原則和術語。我們從一個如何在社交網路中實現主頁時間線的案例研究開始,這說明了大規模出現的一些挑戰。
我們討論了如何衡量效能(例如,使用響應時間百分位數)、系統上的負載(例如,使用吞吐量指標)以及它們如何在 SLA 中使用。可擴充套件性是一個密切相關的概念:即,確保負載增長時效能保持不變。我們看到了一些可擴充套件性的一般原則,例如將任務分解為可以獨立執行的較小部分,我們將在以下章節中深入探討可擴充套件性技術的技術細節。
為了實現可靠性,你可以使用容錯技術,即使某些元件(例如,磁碟、機器或其他服務)出現故障,系統也可以繼續提供其服務。我們看到了可能發生的硬體故障的示例,並將它們與軟體故障區分開來,軟體故障可能更難處理,因為它們通常高度相關。實現可靠性的另一個方面是建立對人類犯錯誤的韌性,我們看到無責備事後分析作為從事件中學習的技術。
最後,我們研究了可維護性的幾個方面,包括支援運維團隊的工作、管理複雜性以及使應用程式的功能隨著時間的推移易於發展。關於如何實現這些事情沒有簡單的答案,但有一件事可以幫助,那就是使用經過驗證在實踐中有價值的易於理解的構建塊來構建應用程式。本書的其餘部分將涵蓋一系列已被證明在實踐中有價值的構建塊。
參考
-
Mike Cvet. How We Learned to Stop Worrying and Love Fan-In at Twitter. At QCon San Francisco, December 2016. ↩︎
-
Raffi Krikorian. Timelines at Scale. At QCon San Francisco, November 2012. Archived at perma.cc/V9G5-KLYK ↩︎
-
Twitter. Twitter’s Recommendation Algorithm. blog.twitter.com, March 2023. Archived at perma.cc/L5GT-229T ↩︎
-
Raffi Krikorian. New Tweets per second record, and how! blog.twitter.com, August 2013. Archived at perma.cc/6JZN-XJYN ↩︎
-
Jaz Volpert. When Imperfect Systems are Good, Actually: Bluesky’s Lossy Timelines. jazco.dev, February 2025. Archived at perma.cc/2PVE-L2MX ↩︎
-
Samuel Axon. 3% of Twitter’s Servers Dedicated to Justin Bieber. mashable.com, September 2010. Archived at perma.cc/F35N-CGVX ↩︎
-
Nathan Bronson, Abutalib Aghayev, Aleksey Charapko, and Timothy Zhu. Metastable Failures in Distributed Systems. At Workshop on Hot Topics in Operating Systems (HotOS), May 2021. doi:10.1145/3458336.3465286 ↩︎
-
Marc Brooker. Metastability and Distributed Systems. brooker.co.za, May 2021. Archived at perma.cc/7FGJ-7XRK ↩︎
-
Marc Brooker. Exponential Backoff And Jitter. aws.amazon.com, March 2015. Archived at perma.cc/R6MS-AZKH ↩︎
-
Marc Brooker. What is Backoff For? brooker.co.za, August 2022. Archived at perma.cc/PW9N-55Q5 ↩︎
-
Michael T. Nygard. Release It!, 2nd Edition. Pragmatic Bookshelf, January 2018. ISBN: 9781680502398 ↩︎
-
Frank Chen. Slowing Down to Speed Up – Circuit Breakers for Slack’s CI/CD. slack.engineering, August 2022. Archived at perma.cc/5FGS-ZPH3 ↩︎
-
Marc Brooker. Fixing retries with token buckets and circuit breakers. brooker.co.za, February 2022. Archived at perma.cc/MD6N-GW26 ↩︎
-
David Yanacek. Using load shedding to avoid overload. Amazon Builders’ Library, aws.amazon.com. Archived at perma.cc/9SAW-68MP ↩︎
-
Matthew Sackman. Pushing Back. wellquite.org, May 2016. Archived at perma.cc/3KCZ-RUFY ↩︎
-
Dmitry Kopytkov and Patrick Lee. Meet Bandaid, the Dropbox service proxy. dropbox.tech, March 2018. Archived at perma.cc/KUU6-YG4S ↩︎
-
Haryadi S. Gunawi, Riza O. Suminto, Russell Sears, Casey Golliher, Swaminathan Sundararaman, Xing Lin, Tim Emami, Weiguang Sheng, Nematollah Bidokhti, Caitie McCaffrey, Gary Grider, Parks M. Fields, Kevin Harms, Robert B. Ross, Andree Jacobson, Robert Ricci, Kirk Webb, Peter Alvaro, H. Birali Runesha, Mingzhe Hao, and Huaicheng Li. Fail-Slow at Scale: Evidence of Hardware Performance Faults in Large Production Systems. At 16th USENIX Conference on File and Storage Technologies, February 2018. ↩︎
-
Marc Brooker. Is the Mean Really Useless? brooker.co.za, December 2017. Archived at perma.cc/U5AE-CVEM ↩︎
-
Giuseppe DeCandia, Deniz Hastorun, Madan Jampani, Gunavardhan Kakulapati, Avinash Lakshman, Alex Pilchin, Swaminathan Sivasubramanian, Peter Vosshall, and Werner Vogels. Dynamo: Amazon’s Highly Available Key-Value Store. At 21st ACM Symposium on Operating Systems Principles (SOSP), October 2007. doi:10.1145/1294261.1294281 ↩︎
-
Kathryn Whitenton. The Need for Speed, 23 Years Later. nngroup.com, May 2020. Archived at perma.cc/C4ER-LZYA ↩︎
-
Greg Linden. Marissa Mayer at Web 2.0. glinden.blogspot.com, November 2005. Archived at perma.cc/V7EA-3VXB ↩︎
-
Jake Brutlag. Speed Matters for Google Web Search. services.google.com, June 2009. Archived at perma.cc/BK7R-X7M2 ↩︎
-
Eric Schurman and Jake Brutlag. Performance Related Changes and their User Impact. Talk at Velocity 2009. ↩︎
-
Akamai Technologies, Inc. The State of Online Retail Performance. akamai.com, April 2017. Archived at perma.cc/UEK2-HYCS ↩︎
-
Xiao Bai, Ioannis Arapakis, B. Barla Cambazoglu, and Ana Freire. Understanding and Leveraging the Impact of Response Latency on User Behaviour in Web Search. ACM Transactions on Information Systems, volume 36, issue 2, article 21, April 2018. doi:10.1145/3106372 ↩︎
-
Jeffrey Dean and Luiz André Barroso. The Tail at Scale. Communications of the ACM, volume 56, issue 2, pages 74–80, February 2013. doi:10.1145/2408776.2408794 ↩︎
-
Alex Hidalgo. Implementing Service Level Objectives: A Practical Guide to SLIs, SLOs, and Error Budgets. O’Reilly Media, September 2020. ISBN: 1492076813 ↩︎
-
Jeffrey C. Mogul and John Wilkes. Nines are Not Enough: Meaningful Metrics for Clouds. At 17th Workshop on Hot Topics in Operating Systems (HotOS), May 2019. doi:10.1145/3317550.3321432 ↩︎
-
Tamás Hauer, Philipp Hoffmann, John Lunney, Dan Ardelean, and Amer Diwan. Meaningful Availability. At 17th USENIX Symposium on Networked Systems Design and Implementation (NSDI), February 2020. ↩︎
-
Ted Dunning. The t-digest: Efficient estimates of distributions. Software Impacts, volume 7, article 100049, February 2021. doi:10.1016/j.simpa.2020.100049 ↩︎
-
David Kohn. How percentile approximation works (and why it’s more useful than averages). timescale.com, September 2021. Archived at perma.cc/3PDP-NR8B ↩︎
-
Heinrich Hartmann and Theo Schlossnagle. Circllhist — A Log-Linear Histogram Data Structure for IT Infrastructure Monitoring. arxiv.org, January 2020. ↩︎
-
Charles Masson, Jee E. Rim, and Homin K. Lee. DDSketch: A Fast and Fully-Mergeable Quantile Sketch with Relative-Error Guarantees. Proceedings of the VLDB Endowment, volume 12, issue 12, pages 2195–2205, August 2019. doi:10.14778/3352063.3352135 ↩︎
-
Baron Schwartz. Why Percentiles Don’t Work the Way You Think. solarwinds.com, November 2016. Archived at perma.cc/469T-6UGB ↩︎
-
Walter L. Heimerdinger and Charles B. Weinstock. A Conceptual Framework for System Fault Tolerance. Technical Report CMU/SEI-92-TR-033, Software Engineering Institute, Carnegie Mellon University, October 1992. Archived at perma.cc/GD2V-DMJW ↩︎
-
Felix C. Gärtner. Fundamentals of fault-tolerant distributed computing in asynchronous environments. ACM Computing Surveys, volume 31, issue 1, pages 1–26, March 1999. doi:10.1145/311531.311532 ↩︎
-
Algirdas Avižienis, Jean-Claude Laprie, Brian Randell, and Carl Landwehr. Basic Concepts and Taxonomy of Dependable and Secure Computing. IEEE Transactions on Dependable and Secure Computing, volume 1, issue 1, January 2004. doi:10.1109/TDSC.2004.2 ↩︎
-
Ding Yuan, Yu Luo, Xin Zhuang, Guilherme Renna Rodrigues, Xu Zhao, Yongle Zhang, Pranay U. Jain, and Michael Stumm. Simple Testing Can Prevent Most Critical Failures: An Analysis of Production Failures in Distributed Data-Intensive Systems. At 11th USENIX Symposium on Operating Systems Design and Implementation (OSDI), October 2014. ↩︎
-
Casey Rosenthal and Nora Jones. Chaos Engineering. O’Reilly Media, April 2020. ISBN: 9781492043867 ↩︎
-
Eduardo Pinheiro, Wolf-Dietrich Weber, and Luiz Andre Barroso. Failure Trends in a Large Disk Drive Population. At 5th USENIX Conference on File and Storage Technologies (FAST), February 2007. ↩︎
-
Bianca Schroeder and Garth A. Gibson. Disk failures in the real world: What does an MTTF of 1,000,000 hours mean to you? At 5th USENIX Conference on File and Storage Technologies (FAST), February 2007. ↩︎
-
Andy Klein. Backblaze Drive Stats for Q2 2021. backblaze.com, August 2021. Archived at perma.cc/2943-UD5E ↩︎
-
Iyswarya Narayanan, Di Wang, Myeongjae Jeon, Bikash Sharma, Laura Caulfield, Anand Sivasubramaniam, Ben Cutler, Jie Liu, Badriddine Khessib, and Kushagra Vaid. SSD Failures in Datacenters: What? When? and Why? At 9th ACM International on Systems and Storage Conference (SYSTOR), June 2016. doi:10.1145/2928275.2928278 ↩︎
-
Alibaba Cloud Storage Team. Storage System Design Analysis: Factors Affecting NVMe SSD Performance (1). alibabacloud.com, January 2019. Archived at archive.org ↩︎
-
Bianca Schroeder, Raghav Lagisetty, and Arif Merchant. Flash Reliability in Production: The Expected and the Unexpected. At 14th USENIX Conference on File and Storage Technologies (FAST), February 2016. ↩︎
-
Jacob Alter, Ji Xue, Alma Dimnaku, and Evgenia Smirni. SSD failures in the field: symptoms, causes, and prediction models. At International Conference for High Performance Computing, Networking, Storage and Analysis (SC), November 2019. doi:10.1145/3295500.3356172 ↩︎
-
Daniel Ford, François Labelle, Florentina I. Popovici, Murray Stokely, Van-Anh Truong, Luiz Barroso, Carrie Grimes, and Sean Quinlan. Availability in Globally Distributed Storage Systems. At 9th USENIX Symposium on Operating Systems Design and Implementation (OSDI), October 2010. ↩︎
-
Kashi Venkatesh Vishwanath and Nachiappan Nagappan. Characterizing Cloud Computing Hardware Reliability. At 1st ACM Symposium on Cloud Computing (SoCC), June 2010. doi:10.1145/1807128.1807161 ↩︎
-
Peter H. Hochschild, Paul Turner, Jeffrey C. Mogul, Rama Govindaraju, Parthasarathy Ranganathan, David E. Culler, and Amin Vahdat. Cores that don’t count. At Workshop on Hot Topics in Operating Systems (HotOS), June 2021. doi:10.1145/3458336.3465297 ↩︎
-
Harish Dattatraya Dixit, Sneha Pendharkar, Matt Beadon, Chris Mason, Tejasvi Chakravarthy, Bharath Muthiah, and Sriram Sankar. Silent Data Corruptions at Scale. arXiv:2102.11245, February 2021. ↩︎
-
Diogo Behrens, Marco Serafini, Sergei Arnautov, Flavio P. Junqueira, and Christof Fetzer. Scalable Error Isolation for Distributed Systems. At 12th USENIX Symposium on Networked Systems Design and Implementation (NSDI), May 2015. ↩︎
-
Bianca Schroeder, Eduardo Pinheiro, and Wolf-Dietrich Weber. DRAM Errors in the Wild: A Large-Scale Field Study. At 11th International Joint Conference on Measurement and Modeling of Computer Systems (SIGMETRICS), June 2009. doi:10.1145/1555349.1555372 ↩︎
-
Yoongu Kim, Ross Daly, Jeremie Kim, Chris Fallin, Ji Hye Lee, Donghyuk Lee, Chris Wilkerson, Konrad Lai, and Onur Mutlu. Flipping Bits in Memory Without Accessing Them: An Experimental Study of DRAM Disturbance Errors. At 41st Annual International Symposium on Computer Architecture (ISCA), June 2014. doi:10.5555/2665671.2665726 ↩︎
-
Tim Bray. Worst Case. tbray.org, October 2021. Archived at perma.cc/4QQM-RTHN ↩︎
-
Sangeetha Abdu Jyothi. Solar Superstorms: Planning for an Internet Apocalypse. At ACM SIGCOMM Conferene, August 2021. doi:10.1145/3452296.3472916 ↩︎
-
Adrian Cockcroft. Failure Modes and Continuous Resilience. adrianco.medium.com, November 2019. Archived at perma.cc/7SYS-BVJP ↩︎
-
Shujie Han, Patrick P. C. Lee, Fan Xu, Yi Liu, Cheng He, and Jiongzhou Liu. An In-Depth Study of Correlated Failures in Production SSD-Based Data Centers. At 19th USENIX Conference on File and Storage Technologies (FAST), February 2021. ↩︎
-
Edmund B. Nightingale, John R. Douceur, and Vince Orgovan. Cycles, Cells and Platters: An Empirical Analysis of Hardware Failures on a Million Consumer PCs. At 6th European Conference on Computer Systems (EuroSys), April 2011. doi:10.1145/1966445.1966477 ↩︎
-
Haryadi S. Gunawi, Mingzhe Hao, Tanakorn Leesatapornwongsa, Tiratat Patana-anake, Thanh Do, Jeffry Adityatama, Kurnia J. Eliazar, Agung Laksono, Jeffrey F. Lukman, Vincentius Martin, and Anang D. Satria. What Bugs Live in the Cloud? At 5th ACM Symposium on Cloud Computing (SoCC), November 2014. doi:10.1145/2670979.2670986 ↩︎
-
Jay Kreps. Getting Real About Distributed System Reliability. blog.empathybox.com, March 2012. Archived at perma.cc/9B5Q-AEBW ↩︎
-
Nelson Minar. Leap Second Crashes Half the Internet. somebits.com, July 2012. Archived at perma.cc/2WB8-D6EU ↩︎
-
Hewlett Packard Enterprise. Support Alerts – Customer Bulletin a00092491en_us. support.hpe.com, November 2019. Archived at perma.cc/S5F6-7ZAC ↩︎
-
Lorin Hochstein. awesome limits. github.com, November 2020. Archived at perma.cc/3R5M-E5Q4 ↩︎
-
Caitie McCaffrey. Clients Are Jerks: AKA How Halo 4 DoSed the Services at Launch & How We Survived. caitiem.com, June 2015. Archived at perma.cc/MXX4-W373 ↩︎
-
Lilia Tang, Chaitanya Bhandari, Yongle Zhang, Anna Karanika, Shuyang Ji, Indranil Gupta, and Tianyin Xu. Fail through the Cracks: Cross-System Interaction Failures in Modern Cloud Systems. At 18th European Conference on Computer Systems (EuroSys), May 2023. doi:10.1145/3552326.3587448 ↩︎
-
Mike Ulrich. Addressing Cascading Failures. In Betsy Beyer, Jennifer Petoff, Chris Jones, and Niall Richard Murphy (ed). Site Reliability Engineering: How Google Runs Production Systems. O’Reilly Media, 2016. ISBN: 9781491929124 ↩︎
-
Harri Faßbender. Cascading failures in large-scale distributed systems. blog.mi.hdm-stuttgart.de, March 2022. Archived at perma.cc/K7VY-YJRX ↩︎
-
Richard I. Cook. How Complex Systems Fail. Cognitive Technologies Laboratory, April 2000. Archived at perma.cc/RDS6-2YVA ↩︎
-
David D. Woods. STELLA: Report from the SNAFUcatchers Workshop on Coping With Complexity. snafucatchers.github.io, March 2017. Archived at archive.org ↩︎
-
David Oppenheimer, Archana Ganapathi, and David A. Patterson. Why Do Internet Services Fail, and What Can Be Done About It? At 4th USENIX Symposium on Internet Technologies and Systems (USITS), March 2003. ↩︎
-
Sidney Dekker. The Field Guide to Understanding ‘Human Error’, 3rd Edition. CRC Press, November 2017. ISBN: 9781472439055 ↩︎
-
Sidney Dekker. Drift into Failure: From Hunting Broken Components to Understanding Complex Systems. CRC Press, 2011. ISBN: 9781315257396 ↩︎
-
John Allspaw. Blameless PostMortems and a Just Culture. etsy.com, May 2012. Archived at perma.cc/YMJ7-NTAP ↩︎
-
Itzy Sabo. Uptime Guarantees — A Pragmatic Perspective. world.hey.com, March 2023. Archived at perma.cc/F7TU-78JB ↩︎
-
Michael Jurewitz. The Human Impact of Bugs. jury.me, March 2013. Archived at perma.cc/5KQ4-VDYL ↩︎
-
Mark Halper. How Software Bugs led to ‘One of the Greatest Miscarriages of Justice’ in British History. Communications of the ACM, January 2025. doi:10.1145/3703779 ↩︎
-
Nicholas Bohm, James Christie, Peter Bernard Ladkin, Bev Littlewood, Paul Marshall, Stephen Mason, Martin Newby, Steven J. Murdoch, Harold Thimbleby, and Martyn Thomas. The legal rule that computers are presumed to be operating correctly – unforeseen and unjust consequences. Briefing note, benthamsgaze.org, June 2022. Archived at perma.cc/WQ6X-TMW4 ↩︎
-
Dan McKinley. Choose Boring Technology. mcfunley.com, March 2015. Archived at perma.cc/7QW7-J4YP ↩︎
-
Andy Warfield. Building and operating a pretty big storage system called S3. allthingsdistributed.com, July 2023. Archived at perma.cc/7LPK-TP7V ↩︎
-
Marc Brooker. Surprising Scalability of Multitenancy. brooker.co.za, March 2023. Archived at perma.cc/ZZD9-VV8T ↩︎
-
Ben Stopford. Shared Nothing vs. Shared Disk Architectures: An Independent View. benstopford.com, November 2009. Archived at perma.cc/7BXH-EDUR ↩︎
-
Michael Stonebraker. The Case for Shared Nothing. IEEE Database Engineering Bulletin, volume 9, issue 1, pages 4–9, March 1986. ↩︎
-
Panagiotis Antonopoulos, Alex Budovski, Cristian Diaconu, Alejandro Hernandez Saenz, Jack Hu, Hanuma Kodavalla, Donald Kossmann, Sandeep Lingam, Umar Farooq Minhas, Naveen Prakash, Vijendra Purohit, Hugh Qu, Chaitanya Sreenivas Ravella, Krystyna Reisteter, Sheetal Shrotri, Dixin Tang, and Vikram Wakade. Socrates: The New SQL Server in the Cloud. At ACM International Conference on Management of Data (SIGMOD), pages 1743–1756, June 2019. doi:10.1145/3299869.3314047 ↩︎
-
Sam Newman. Building Microservices, second edition. O’Reilly Media, 2021. ISBN: 9781492034025 ↩︎
-
Nathan Ensmenger. When Good Software Goes Bad: The Surprising Durability of an Ephemeral Technology. At The Maintainers Conference, April 2016. Archived at perma.cc/ZXT4-HGZB ↩︎
-
Robert L. Glass. Facts and Fallacies of Software Engineering. Addison-Wesley Professional, October 2002. ISBN: 9780321117427 ↩︎
-
Marianne Bellotti. Kill It with Fire. No Starch Press, April 2021. ISBN: 9781718501188 ↩︎
-
Lisanne Bainbridge. Ironies of automation. Automatica, volume 19, issue 6, pages 775–779, November 1983. doi:10.1016/0005-1098(83)90046-8 ↩︎
-
James Hamilton. On Designing and Deploying Internet-Scale Services. At 21st Large Installation System Administration Conference (LISA), November 2007. ↩︎
-
Dotan Horovits. Open Source for Better Observability. horovits.medium.com, October 2021. Archived at perma.cc/R2HD-U2ZT ↩︎
-
Brian Foote and Joseph Yoder. Big Ball of Mud. At 4th Conference on Pattern Languages of Programs (PLoP), September 1997. Archived at perma.cc/4GUP-2PBV ↩︎
-
Marc Brooker. What is a simple system? brooker.co.za, May 2022. Archived at perma.cc/U72T-BFVE ↩︎
-
Frederick P. Brooks. No Silver Bullet – Essence and Accident in Software Engineering. In The Mythical Man-Month, Anniversary edition, Addison-Wesley, 1995. ISBN: 9780201835953 ↩︎
-
Dan Luu. Against essential and accidental complexity. danluu.com, December 2020. Archived at perma.cc/H5ES-69KC ↩︎
-
Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides. Design Patterns: Elements of Reusable Object-Oriented Software. Addison-Wesley Professional, October 1994. ISBN: 9780201633610 ↩︎
-
Eric Evans. Domain-Driven Design: Tackling Complexity in the Heart of Software. Addison-Wesley Professional, August 2003. ISBN: 9780321125217 ↩︎
-
Hongyu Pei Breivold, Ivica Crnkovic, and Peter J. Eriksson. Analyzing Software Evolvability. at 32nd Annual IEEE International Computer Software and Applications Conference (COMPSAC), July 2008. doi:10.1109/COMPSAC.2008.50 ↩︎
-
Enrico Zaninotto. From X programming to the X organisation. At XP Conference, May 2002. Archived at perma.cc/R9AR-QCKZ ↩︎