我們公司最近正在開始為擁有大用戶群的客戶構建應用程序。這意味著我們需要摒棄傳統的服務器設置,開始擴展服務器,以便一次性處理數百個請求。這要求我了解傳統服務器設置與目前更加現代的方法之間的區別。
向云進發
回想 “舊” 時代(整整 20 年前),向操作中添加更多服務器空間涉及到讓某人安裝硬件,然后讓人們為您維護該硬件。不僅購買和維護硬件需要成本,服務器上的物理空間也需要成本。考慮到每個服務器都僅擁有有限的空間,增長太快可能帶來問題。
如今,只需單擊幾次鼠標,就可以在云中獲得一個服務器:基本上講,其他人會負責為您維護硬件的問題,您可以在千里之外配置您的新硬件。您還可以添加許多的服務器,無需占用任何額外的空間。這使得擴展變得比過去容易得多。
傳統設置
傳統設置包括一個托管您應用程序的服務器和一個單獨的數據庫服務器。此設置通常非常適合小項目以及不需要擴展的項目。有時,過度優化您的設置并沒有意義。我們公司以這種方式托管著許多項目。
“我們正在將一些較大的項目遷移到更現代的基礎架構,該基礎架構會讓我們的應用程序能夠優雅地擴展。”
構建可擴展的基礎架構
我們正在使用可擴展的基礎架構創建可擴展的應用程序。抱著成為更優秀的開發場所的想法,我們決定遵循 Heroku 的 “12 因素(Twelve-Factor)應用程序” 方法,該流程是專為構建 SaaS(軟件即服務)應用程序而設計的。簡言之,該流程通過保持各部分分離,幫助您確保您的應用程序容易擴展。您應能夠取出組合中的某一部分,無需擔心會毀壞所有部分。換句話說,您的資源不應過度彼此依賴,以至于移動或更改一個組件會毀壞您的基礎架構。
12 因素應用程序方法很容易理解。不是我們的所有項目都符合該方法,但我們會努力讓項目盡可能符合該方法。談到擴展,請特別注意有關可處置性的因素 9:通過快速啟動和優雅的關閉實現最高的健壯性。
最佳實踐
您可以嘗試優化所有部分,或者可高效地使用時間,努力實現容易實現的目標,讓您的應用程序與該方法有 80% 相符。我們領先的基礎架構工程師喜歡 80/20 方法:20% 的工作實現 80% 的目標。這一節將介紹一些可幫助您接近想要實現的目標的簡單方法。讓我們看看一些例子。
1. 設置負載平衡
場景 A:您的網頁登上了 Reddit 的頭版,您突然獲得了異常高的流量。您會怎么做?
這時有一個負載平衡器并 讓一些服務器保持運行可能有所幫助。可以將負載平衡器視為空中交通指揮員。它接受所有傳入的流量,并將其定向到可處理它的服務器。它也知道,如果一臺服務器宕機,那么不應朝該方向發送任何流量。也可以將負載平衡器視為一個黑匣子:您不需要擔憂負載平衡如何 完成,只需放心地相信它將 會完成。新傳入的流量不會到達宕機的服務器,因為負載平衡器會將新流量定向到可以處理它的服務器。
場景 B:一次自然災難襲擊了整個東海岸。您的應用程序將會如何反應?
如果即將出現這種情況,那么應該一切正常,因為您會在不同的可用性區域運行服務器,對吧?您的負載平衡器會知道您在東海岸的所有服務器都已單擊,然后它會開始將流量發送到西海岸的服務器。
2. 保持不同的環境看起來一樣
我們公司有 4 個不同的環境:本地、開發、暫存和生產。我們嘗試保持它們彼此盡可能相似。這可以預防在各個階段發生任何可能歸咎于環境變量的問題。例如,您一定不要依靠在生產環境中無法訪問的開發環境中的任何資源。
3. 使用無狀態服務器
作為一條規則,不要將您需要訪問的信息存儲在 Web 應用程序的服務器中。服務器的每個副本看起來都應該是相同的,而且您不需要將信息從一個服務器復制到下一個服務器。理想情況下,您已經創建了應用程序的服務器鏡像,能夠使用該鏡像建立其他許多服務器。讓您的數據庫與應用服務器分開。
4. 經常停止您的服務器
應急訓練有時看起來可能很傻,但熟能生巧。至關重要的是,每個人都應該知道在發生緊急情況時如何應對,實際練習過實際發生緊急情況時如何做。發生火災時,人們可能知道他們應該前往緊急出口,但您不希望他們在實際發生火災時忘記緊急出口是什么樣的。
服務器問題也是如此。您可能認為您已做好應對最糟的情況的準備,但除非您知道在服務器宕機時系統將如何應對,否則您就沒有做好應對不是您導致的服務器宕機情況的準備。這正是使用無狀態服務器至關重要的原因。不要過度依賴您的服務器 —經常關閉它們。您應能夠停止并恢復服務器,而不害怕您將毀壞什么東西。
您希望能夠確信,一些服務器在晚上發生宕機時,系統將在您能夠在早上解決問題之前正常運行。
5. 集中精力解決瓶頸
瓶頸需要您確定是什么實際導致您的應用程序變慢。您不想盲目地追查可能不是實際問題的因素;查找最大的瓶頸并花時間嘗試修復這些問題。
我們公司使用了 Django,所以我們喜歡使用 Django Debug Toolbar 來確定是什么實際減緩了我們的運行速度。運行減慢可能是由不必要地頻繁查詢數據庫等操作導致的。消除瓶頸,可能對確保您的應用程序更高效地執行有很大幫助。
6. 運行后臺任務
如果您可將一些任務推遲到以后,可考慮使用后臺任務。例如,您可能需要執行一次很耗資源的 API 調用,所以您不需要立即向用戶返回信息。我們使用 Celery Task Queue 來管理我們可推遲到以后執行的任務。有時我們不需要用戶獲得即時反饋,所以只要可能,我們就會將該任務延后到我們能對它給予應得的關注時運行。
7. 盡可能緩存
如果您有一個提供大量靜態內容的網站,緩存無疑會加快您網站的反應速度。反復訪問您的網站的用戶只需加載新的內容。如果自他們上次訪問您的網站以來,內容沒有多大改變,那么加載將會很快。
可以采用多種緩存方式:瀏覽器緩存和使用內容分發網絡 (CDN),后者能提供具有高可用性和高性能的內容。您可以設置資源的有效期,所以一個不錯的想法是在不常更改的資源上設置較長的有效期,頻繁更改的資源則相反。例如,徽標圖像可能很少發生更改,而您的 HTML 網頁則會非常頻繁地更改。基本上講,緩存有助于提高性能,且無需更改您的硬件。
8. 設置自動擴展
您現在只需單擊一個按鈕即可建立新的服務器。由于擁有如此輕松地建立和銷毀服務器的能力,所以您可以確保您始終擁有足夠的服務器來處理您嘗試處理的流量。您甚至可以將服務器設置為在高流量期間運行,在低流量期間消失。如果知道用戶模式,您可以在任何時候增加和減少服務器數量。
9. 讓整個團隊都參與進來
團隊的每個人都可以從某種程度上幫助提高性能和擴展。每個人都可以出一份力,幫助確保團隊更輕松地實施保護措施,確保您的應用程序能夠處理峰值流量或一直很高的流量。
確保團隊的每個人詢問正確的問題。例如,某些特性是真的需要還是錦上添花?
10. 花時間執行測試
一定要在建立的時間表中給基礎架構測試留出時間。不是所有功能從一開始就能順利運行。您需要對應用程序執行壓力測試,需要在生產環境中檢查您的應用程序。如果時間表中沒有安排對應用程序進行擴展測試的時間,那么您可能會發現需要延誤工作才能修復的重大問題。
11. 考慮容器
我們公司正計劃采用一種更現代的 Web 應用程序處理方法。在理想情況下,我們希望將基礎架構更換為使用容器。
在聽到容器時,我腦海里想到的第一件事是,容器與虛擬機之間有何區別。對我而言,它們聽起來很相似。事實證明,容器能比虛擬機更好地保持了應用程序的可擴展性。它們類似于虛擬機,但它們沒有大量的重復硬件。我們現在可以運行單個 Linux 實例,在其上建立容器,讓所有容器都共享同一個操作系統。所以容器似乎是更加輕量的、具有更高成本效益的應用程序擴展解決方案。
結束語
盡管這些實踐可能無法預防所有問題,但它們會幫助您在開始構建應用程序時考慮到擴展功能,讓您為需要處理數千萬個用戶的時刻打好基礎。
要確保您正在朝建立高度可擴展的應用程序基礎架構的方向而努力,您應該采取以下行動:
使用一個負載平衡器。
使用自動擴展功能。
不要害怕隨機停止您的服務器。
修復需要修復的問題,而不是修復您認為應該修復的問題。
確保您擁有測試應用程序和修復任何問題所需的時間。