如果你們是一家擁有宏大夢想的小公司,相比于傳統的系統供應商,云基礎設施供應商對于你們最大的優勢就是,他們可以幫助你靈活調整應用程序所用的源。你們再也不用為了一些需要花費六個星期才能安裝完成的服務器,而與托管服務供應商商談機架空間的事宜。現在,這整個冗雜的過程通過API調用可以得到簡化,同時,服務器可以在幾秒種內即可準備完畢。
舊模型的主要供應策略很簡單:供應過量,并且過量許多。擴充容量的時候,你至少要以“一個服務器”為單位來增加容量,并且由于改動部署方案的人力成本和時間成本都很高,所以需要分批進行改動。這一點使你需要花費比預期多得多的部署精力,而且要擴充部署規模,而并不僅是在已有的狹小空間內尋求最優化的方案。
最新的云技術使得DevOps團隊得以用非常先進的顆粒化方式部署了新的源,只要多花一些金錢,就可以對抗任何容量問題。這通常是一個很有效的策略,但它需要我們在云的容量規劃方面做得更好。
桌上賭注
相比于一次性制定正確的容量規劃,如何應對錯誤的容量規劃則更為重要。你需要采用便于挑整應用程序的架構和開發策略。否則,你就沒有很好地利用上供應的靈活度——調整應用程序的人力成本將蓋過云的靈活度這一優勢,你就會止步于云時代之外。更糟糕的是,你還要為了沒有利用上的靈活度功能付額外費用。
選擇便于擴充容量的架構
大多數應用程序會使用兩種擴展容量的方式:水平擴展(“買更多的箱子!”)和垂直擴展(“買更大的箱子!”)。業內已經總結出了幾個非常有效的架構方法,我們沒有必要再去開發新的方法了。
你可能會最終選用n層架構,數量龐大的應用程序服務器利用著非常小的數據庫(或者其他后臺數據存儲)。這是網頁應用程序部署的最常見模型,因為它可以在應用程序層利用水平擴展,在數據庫利用垂直擴展。
在不進行任何基礎改動的條件下,在世界最大的生產部署原型中 ,這個架構對于何種環境和規模都可以很好的運行。如果你們公司想要發展成谷歌或者Facebook那樣的公司——假如真的實現了,你們將需要上千個工程師來處理擴展問題。
將應用程序編碼與部署環境的知識分離開
盡管這是幾十年間最佳方法,但假如你在應用程序的整個使用過程中只擴充一、兩次API服務器,硬編碼的API服務器并不是一個大問題。當你想要迅速擴充時,你需要應用程序(或部署/供應過程)來處理配置的變化。
近來有許多管理方面的優秀的開源選擇、例如,Consul可以很方便的探索服務——服務器會直接通知Consul有哪些服務是可用的。消費者們可以通過API尋找服務,或者當服務運行時進行DNS 搜索,此搜索可以遍及整個服務器。
在使用服務為基礎的架構或多層架構時,你會發現一個無處不在的交流層,它使得你可以任意改變服務的大小、添加新的服務,以便滿足應用程序的需求。你有很多種選擇——在我的經驗里,NSQ的表現十分出色,而且是一個容易采用的消息總線。Kafka也有許多擁護者。普遍性和標準化是應用程序很重要的兩大方面,它使得我們可以專注于處理一些棘手問題的內部加工和操作過程(而非強調制造商和顧客間復雜度為n^2的互動),并且解決了關于如何更改應用程序的爭論,對于這個問題,答案過去通常是“在NSQ里面再輸入一個事件”。
“那些不與控制基礎設施直接相關的應用程序或服務器,不需要察覺到服務器的加入或退出”是你應當選用的黃金準則。它們需要了解的就是如何連接到路由要求通往以及它要連接到的網絡。
這或許聽起來很復雜,但最近科技的迅速進步使得一個小型開發團隊就可以輕易的完成這件事。在我最新一家公司中,一個從未著手處理過類似工作的非專業的工程師,只花了大約兩周的時間就開發了一個“泡泡糖膠帶”版本的基礎設施。其他開發團隊已經為你開辟了道路,你就不用再重新經歷太多困難——即使還會遇到一些困難,你距離應用程序的商業價值已經更進一步了。
自動化供應和部署
盡管通過點擊供應商的線上界面就可以發布實例并進行SHH,來供應云的源,你還需要花費大量時間來管理服務器、處理它們之間的不一致、清理操作錯誤。你需要盡早投資服務器(或者其他源)的自動化供應以及應用程序的自動化部署。
在我最新一家公司中,我們使用了Ansible來自動化服務器的配置。Chef、Puppet、Salt以及普通的shell腳本也是可供選擇的。傳送可理解的Ansible腳本以及自動化服務的部署并不是一件易事,但我們可以在幾分鐘內就抓住機會來優化架構,多花費一些工程成本也是值得的。
除了可以簡化容量優化,自動化供應和部署還可以顯著簡化操作過程。我們可以像對待牲畜一樣對待箱,而非像對待寵物那樣——修復一次性問題的關鍵步驟是直接殺掉并替換箱,而非嘗試弄明白問題的原理到底是什么。我們的運行手冊將不再區分滿的硬盤、干擾的鄰近設備、失敗的硬件或是糟糕的部署等問題——“直接將它丟棄,沒有必要花費時間來診斷問題并手動修正它。”
有些應用程序最終會達到一定的規模,有些部署也會達到它的成熟期,此時應用程序要負責自行擴展和修復。這對于大多數讀者來說可能很難懂,因為復雜度提高了許多。這時,你可能會需要開發者或操作團隊使用常見自動化工具來手動調整資源。這位自動擴展提供了一條途徑,因為你可能會需要在計算機做出可以面對所有特殊情況的穩健決定之前,花上幾個月或幾年來處理“只發生在生產當中的問題”。
運供應商提供一些可以幫助你處理擴展的工具。它們可以幫助自動化一些應對自然增長的需求或者應用程序使用度的跨期變化的機制(服務器不需要在用戶睡眠時被喚醒)。這也就是說,你可能需要在供應和操作方面足夠智慧,來機動應對需求的變化,使得自動擴展要么會引發生產的問題,要么積累沒必要的巨額賬單。
容量規劃的費米估計
在大多數應用程序的初期,過度重視精確度會導致高成本。你應該最初通過一個預期的工作量來進行供應,然后隨需求進行調整。
在設計階段,最有用的的問題是“我們期望先突破什么?”例如,在之前的一個公司,我們發布了一個應用程序,其中包含了十多種服務。對它們進行嚴格的規模估計是很困難的,但這也并不是必要的:高度內部利用、所選用技術的運行以及明顯的開發耗費,顯然服務一開始就會崩潰。這意味著在固定基礎上需要最多的源,還需要最多的工程操作時間。我們應該重點著手在服務的容量規劃,而放棄其他這些工作。
當你決定了要專注于哪一部分,你需要找到是什么影響著容量要求,以及哪個源是操作的限制因素。
查找驅動器
應用程序不需要擴展。如果刪除一些要求,編碼也不需要。但商業有時候需要,所以嚴謹的考慮商業對于特定服務的要求是很重要的。
在我們的項目中,應用程序是一個游戲,服務由初級AI和游戲世界的世界狀態來提供的。如果服務超過了容量,那么一部分玩家將無法進行游戲。可能會令人驚訝的是,對于重要商業應用程序的工程師來說,為了峰值負載而調整容量,從而放棄90%+的玩家是完全可以接受的工程權衡。(峰值負載和典型高水位線的差別在一周內超過500。)
替代這種方案,我們按照游戲的目標使用來調整初始容量,按照這種目標使用持續下去,我們認為可以獲得一個良好的公司事業,并且在事業越來越好的同時不斷增加目標容量。其他公司可能需要支撐峰值負載,而不是支撐更低的基線——穩定負載。
由于我們系統的設計要求在玩家游戲的期間持續工作,我們利用“每小時的活躍玩家”來描述峰值負載。其他大多數應用程序可能會使用“每秒的要求”來描述峰值負載。
查找限制因素
不同的技術棧和工作量消耗源的方式具有很大的區別。例如軌道應用程序中的Ruby通過增加進程來水平擴展,比起其他系統源,這些進程常常占用更大比例的內存。(在穩定狀態下,有些軌道應用程序很快就可以達到幾百兆的RAM用量。因為每個軌道過程可以服務一個請求,可以通過買內存來獲得額外容量:
內存需求=(每秒的目標請求)*(每秒的請求平均長度)*(穩定狀態下的過程平均尺寸)
所以,如果一個應用程序想要每秒對1000個請求進行服務,一個請求的平均長度約為350ms,一個進程的平均大小約為250MB,我們大約需要350個進程,這消耗大約90GB的RAM。假如有96GB的空間,我們可以供應12個箱,每個8GB,也可以供應24個箱,每個4GB。
部署環境除了RAM以外還有許多其他的特征,包括CPU容量、硬盤接入速度和網絡帶寬。我們忽略這些特征,因為它們并不是大多數軌道應用最先耗盡的因素:內存最先耗盡。如果不是病態運行了系統,我們永遠也不會達到箱的CPU限制。如果達到了,我們再另想對策(我們也會在生產中監管CPU利用,因為無論是錯誤或是錯誤但未察覺的假設,都代價極高。)
這個方法模型并不適用于所有的棧和工作量,尤其是對于那些具有異源性的響應次數分布的(例如,使用一個不太可靠而你無法監管的API)。它致力于降低執行的成本,并且足夠精確,使你可以放心地建立系統,而不是去支撐硬件要求。
在不確定的情況下估算性能
如果沒有一個和最佳規則相近的選擇,你可能需要進行一些試驗。以下是一些你可以嘗試的手段。
CPU每秒可以處理多少請求?10個顯然太少了,計算機是很快的。1000個可能太多了,有的請求需要花費很多精力,有的內部服務很奇怪,還有的棧本身就很緩慢。100個看起來是個合適的折中。我們就假設每秒可以處理100個。
運行微型標準檢測程序
你可以開發一個微型標準檢測程序,模擬一個你的應用程序的簡單請求/響應、應用程序的單個元素或者整個端到端的數據流。這些工作人們之前就已經進行過,TechEmpower對于設計標準檢測程序有很好的的建議,它們也有一些關于現代棧和硬件的成果。
在實際應用程序上進行負載測試
你可以編寫并運行腳本來模擬應用程序可能的使用情況,在開放網絡、工作環境中,向結撥號,直到某一環節崩潰。這很困難。幾乎沒有腳本可以精確的捕捉成產工作量。盡管工程成本增加,但你也找不到一個比以上方法更精確的了。
無論你選用哪一種方法,當你估算了理想容量以及一單位源提供多少容量之后,容量規劃都是一個簡單的任務。雖然距離容量問題的解決還有很大一段距離,但你已經擁有了開始的基礎。
我們什么時候調整空間?
為了削減成本
在基礎設施和其規劃上付出大量時間是很具有誘惑力的,因為你會遇到新奇困難的問題,并且還非常有趣。但是,它在應用程序的初期可能不會貢獻很多商業價值。
根據經驗來看,如果你每月在基礎設施上的花費少于1000美金,那么你根本不應該考慮優化空間。你更適合花上等量的工程來發展應用程序或事業的其他部分。
當你的花費增加到每個月幾萬美金之后——許多應用程序大概永遠也不會達到——你就有充足的理由定期重新評估非配源的方式,以及是否值得花費所需的工程時間來對源或應用程序進行修正。這與定期舉辦云修剪排派對一樣簡單。由于工作可以察覺到非常高產的小規模工作量,它非常適合活動項目,也使緩沖成為一個很良好的活動。許多工程師對于云花費很不理性,因為它具有神秘的有形性。浪費掉可以維持m3.medium的2.40美元也會很令人心痛。你要記住,比起未激活的實例,工程師在桌前遛彎的90秒更是一種浪費。
為了增加容量
總的來說,你想要增加超出需求的容量。超出多少,你決定沿著預期增長曲線增加多長,由你增加額外容量的進程有多可靠來決定。當擴充容量會帶來損失、風險和高成本時,你常常會想要過多的擴充容量。當擴充容量的成本降低時,你就可以更頻繁地進行小規模擴充。
根據經驗來看,如果擴充容量對于你來說需要一周,你很可能想要沿增長曲線購買6到12月的容量。如果僅需要一天,便可以縮短到一個月。如果僅需要幾分鐘,那么你可以每次只購買一周。手動進行大于每周一次的頻率則沒有什么必要。
如果你足夠精通DevOps,可以利用應用程序的使用周期,并且可以增加或減少復雜度,那么恭喜你!請連續運行它。達到這一步是非常非常困難的,而且即使知道很實際的基礎設施開銷,大部分的應用程序大概都無法評估它是否達到有限工程時間的最佳使用程度。
愿意承受失誤
云的內容規劃并不意味著要得到絕對正確的答案,也不意味著得到差不多對的答案。你是在最優化規劃過程,使它足夠輕量而不會阻礙傳送商業價值,使它足夠準確而保障生產不會崩潰。即使只是得到一個差不多的優化方案,也會讓你更智慧地分配時間和注意力,決定了公司的成功,例如合適的“產品/市場”比,以及可以吸引合適顧客的可擴展性。