系統是否可擴展?回答這個問題似乎很簡單。但我們大多弄錯了。不再了。閱讀更多以找出答案。
“應用程序可擴展嗎?” 經理問。每周的系統路線圖會議幾乎進行了一半。我以為我們已經完成了所有技術部分,很快就會轉向與業務相關的問題。
我團隊的架構師清了清嗓子回答說:“它可以輕松處理兩倍于通常的負載。”
經理看了很久,一副不相信這個答案的樣子。但是,在沒有任何更好的觀點的情況下,他繼續進行進一步的更新。我含蓄地相信我們的系統確實是可擴展的。畢竟,建筑師已經明確地宣布過了。
一年下來,我知道了真相。一個晴天,系統因負載過大而崩潰。
該銀行為假期推出了一種新的貸款產品。商業戰略得到了回報,需求激增。由于我們的應用程序提供了做出信用決策的核心數據,因此它被來自其他幾個應用程序的傳入請求淹沒了 5 倍。
我們添加了更多 CPU 來處理我們服務的負載。同樣的策略在最近幾次都奏效了。然而,這次沒有。
我們的系統是可擴展的,直到它不再是。
經過分析,我們發現問題并不完全出在我們的應用程序代碼中。我們的應用程序由與銀行中央數據庫相連的多項服務組成。與數據庫的連接是使用連接池建立的。
我們的錯誤是我們對打開的連接數粗心大意。事實證明,數據庫管理不是。
DBA 對我們應用程序組的打開連接數有一個嚴格的限制。當對我們應用程序的傳入請求激增時,我們最終獲得了更多的連接,直到我們碰壁。無論我們添加多少額外的 CPU 來增加應用程序容量,都沒有任何區別。
雪上加霜的是,DBA 拒絕增加允許的連接數。剩下的唯一選擇是對我們的應用程序進行代價高昂的更改以正確處理連接。出于所有實際目的,我們的系統不再具有可擴展性。
當然,這是我們的錯誤。我們應該考慮到有限的連接數并明智地使用它們。盡管如此,問題并非無法解決。但這種改變并不劃算。
雖然情況最終得到了處理,但它激起了我對這個主題的興趣。我們認為該系統是可擴展的。但事實并非如此。至少在我們達到連接限制之前不會。
很明顯,我們對可伸縮性的真正含義的理解是錯誤的。我決定深入了解整個情況。我最初的動機是避免陷入與我團隊的架構師相同的境地
系統可擴展性的通常定義
可擴展性是構建分布式系統的基本挑戰之一。
在研究分布式系統的可伸縮性時,我遇到的最常見的定義如下:
可伸縮性是系統處理增加的工作負載的能力。
這個定義在現實生活中如何應用?
活躍使用的系統的開發人員監控其工作負載水平。他們創建流程來預測系統性能何時會變得不盡如人意。目標是在達到危險級別之前增加系統的容量。
在這種可擴展性方法中,主要關注點是確定一個需求區間,在該區間內系統將以可接受的水平執行。如果這個間隔足夠大,則系統被認為是可擴展的。
在我看來,這個定義非常有限。此定義的重點始終是工作負載。
該定義的主要關注點是,如果系統隨著工作負載的增長繼續充分執行,則該系統是可擴展的。沒有注意必須如何修改系統才能將性能保持在同一水平。
正如我們在案例中發現的那樣,我們的系統本可以繼續保持良好的性能。但是數據庫端所需的更改是不可接受的。更改代碼也不符合成本效益。
通用的可伸縮性定義不關注容量增加的方法或其對系統的整體影響。我們不會問重要的問題,例如:
- 處理器數量加倍是否能讓系統處理雙倍的工作負載?
- 處理器之間協調工作的開銷是否會過高?
為了捍衛定義,它是系統設計人員和開發人員使用的最常見的定義。我們總是聽到有人說系統是可擴展的,它可以毫無問題地處理雙倍的工作負載。
擴展的可擴展性
在尋求了解可伸縮性的過程中,我遇到了另一種經常被忽視的可伸縮性定義。但是,我開始相信它在實際情況中可能更為重要。
可伸縮性是通過重復應用具有成本效益的策略來擴展系統容量來處理增加的工作負載的能力。
重點立即轉移到增加容量的策略上。
我們不再對一次性增加容量以提高可擴展性感興趣。我們感興趣的是增加容量的策略以及可以經濟高效地應用該策略的次數。
這種思路總是讓我想起像拉斐爾納達爾或羅杰費德勒這樣的世界級網球運動員。多年來,像納達爾或費德勒這樣的球員有多少次調整他們的比賽風格以適應不斷變化的比賽需求?
很多次,我想。
他們所做的每一次改變都延長了他們的職業生涯并使他們更加成功。
然而,做出改變并不容易。許多玩家升到頂峰后就因為無法適應而失敗。即使是最好的球員也必然會在嘗試適應時遇到困難。球員越容易做出改變,他在比賽中保持統治地位的可能性就越大。
擴展系統也是如此。
當我們考慮可伸縮性的第二個定義時,我們開始考慮關于我們系統的其他類型的爭論。
- 如果我們添加更多的處理器來增加容量,那么在添加的處理器之間協調工作的方法是什么?
- 協調方式會不會占用更多的處理周期?
- 如果是,將無法實現增加容量的全部好處。因此,添加超過某個點的處理器可能不是一種提高可擴展性的經濟有效的方法。
專注于擴展策略的重復應用可以讓我們更加了解我們的選擇。
例如,將O(n^2)替換為O(nlogn)算法可以在相同的時間內處理更大的工作負載。換句話說,用更高效的算法替換算法可以提高系統的可擴展性。
但是我們可以重復使用這種方法嗎?我不這么認為。
一旦我們有了最有效的算法,算法替換策略就不再可行了。您不能不斷地應用該策略來提高系統的可擴展性。
系統是否可擴展?
有了可伸縮性的兩個定義,我終于能夠理解這個基本問題。這是我們會議中突然出現的同一個問題,但沒有得到充分回答。
為了回答這個問題,我們最終將系統標記為可擴展或不可擴展。在我看來,這是過于簡單化了。
系統可擴展意味著什么?
大多數系統在某種意義上都可以擴展。但是,沒有任何系統可以無限擴展。
那么我們應該如何處理可擴展性呢?
理論方法
比起給系統貼標簽,比較兩個不同系統的可擴展性更有收獲。考慮下圖,它顯示了兩個假設系統 A 和 B 的響應與需求曲線。
對于任何給定的需求水平,與系統 B 相比,系統 A 的響應更差。如果存在響應的最大容忍值,系統 A 將比系統 B 更早達到該值。
系統 B 比系統 A 更具可擴展性。
當然,如果兩條線繼續以相同的單調速率上升,它們最終將達到對資源的需求超過其可用性的點。到那時,兩個系統的響應時間都將變得不盡如人意。盡管 A 和 B 的分數可能不同,但它們表示系統可擴展性的限制。
請記住 - 沒有任何系統可以無限擴展。
系統不遵循響應與需求指標的單調增長率。曲線看起來更像下面的例子。
假設的系統可以很好地容忍需求增加,直到它達到一個重要的設計限制。這種限制在響應需求曲線中形成了類似膝蓋的形狀。在超過特定需求水平后,響應指標就會失控。
設計師的目標是使曲線的拐點盡可能靠右。一旦系統接近膝蓋,它就不再具有可擴展性。需求的任何增加都會將其推下山坡。
實用方法
可擴展性的理論方面讓我大開眼界。但我還是覺得少了什么。
我無法將上述圖表與我們的系統完全聯系起來。每當負載普遍增加時,我們都能夠在最初幾天成功地擴展我們的系統。只有當我們達到數據庫限制時,事情才會變得糟糕。
這種行為不符合描述可伸縮性的兩個理論模型中的任何一個。
如何對這種行為進行分類
大多數真實系統表現出更多的混合行為。下圖顯示了這一點:
當系統在底部綠色區域運行時,它響應良好。當它開始在中間區域徘徊(以黃色顯示)時,響應開始變得不可接受。當它最終進入頂部區域(以紅色顯示)時,系統變得不可用。
在我看來,這是對可擴展性的第二個定義的更準確的表述。
- 在前幾次,系統設計人員能夠迅速采取行動將響應保持在可接受的范圍內。這可能是添加額外內存的問題。
- 第三次,設計人員需要更多的時間和精力來將響應指標降低到可接受的水平。改善響應所需的更改可能更復雜。
- 在最后一種情況下,系統已達到無法合理解決方案以防止響應時間變得不可用的程度。使用最初幾次有效的成本效益技術,該系統不再可擴展。
上述事件也描述了我們系統的情況。盡管我們能夠在一段時間內保持系統的可擴展性,但它最終達到了一個臨界點,超過這個臨界點,任何具有成本效益的解決方案都不可能實現。
那么,系統是否可擴展?
答案是——視情況而定!而不是以一種逃避的方式。
可擴展性更像是一個不斷發展的移動目標,而不是一個固定的狀態。
如果系統所有者有能力繼續投入資金以滿足更高的需求水平,則系統可以擴展到一定程度。除此之外,沒有任何具有成本效益的行動可以緩解響應指標問題。
如果系統所有者在一開始就沒有錢購買額外的資源,那么系統是不可擴展的。
無論如何,沒有任何系統是可以無限擴展的。
結語
我理解可伸縮性真正含義的旅程得出了一些重要的結論。
在我看來,您不能簡單地在系統上貼上可擴展性的標簽,然后就此結束。
所有系統在某種程度上都是可擴展的。但這并不意味著您可以以具有成本效益的方式無限期地繼續擴展它們。
理想的可擴展性情況需要采用細致入微的系統設計方法。只關注增加資源以提高可擴展性是一個陷阱。您還需要考慮額外資源的成本效益。
通過這篇文章,我的目標是將這種觀點帶入討論。
請在下面的評論部分分享您的想法。