一個合理的生產環境的 Web 應用程式應該是什麼樣子的

展小白發表於2018-09-02

好的工具的產生使開發與部署變得十分容易,作為一個曾經的雲服務從業人員,鼓勵大家擁抱雲服務。擁抱這些現成的技術棧。

這是我在 stephenmann.io 上看到的一篇文章,對於 Web 應用程式架構演進的過程講解的十分通俗易懂,所以就把它翻譯了出來。

原載:stephenmann.io

譯者:展小白

一個產品的規劃可能會是迎合最普遍的需求,但是很多情況客戶希望解決具體的問題,這些問題可能將程式變得無限複雜,就必須提出有效的解決方案。

在過去的經驗教訓中,一些工程師傾向於深入瞭解各項技術,足以解決任何問題。對於有著良好溝通的團隊,這是非常好的。這些綜合的知識有效的填補了團隊個人的薄弱點。但對於行業或者經驗不足的工程師團隊,這些幾乎是不可能的。

如果你是在一個薄弱的技術團隊,然後從頭開始構建和部署整個 Web 應用程式,你可能很快意識到要深入瞭解每項技術,是很難的一件事情。

業界其實已經提供了很多旨在解決這些問題的方案:Web 託管服務(Beanstalk,AppEngine 等),容器管理服務(Kubernetes, ECS 等)以及其它很多解決方案。一旦你啟動並執行它們,便可以很好的正常進行工作,這種解決方案非常好,因為它規避了啟動和執行 Web 程式過程中大量複雜的操作,而且最終目的是為了使程式正常工作。

這裡可能需要下功夫的是,在你決定用哪種方案時,你需要更多的瞭解這些解決方案。

在這篇文章中,將介紹一個不靠譜的系統到具有合理可靠性的系統的過程。這裡不會介紹每一部分的具體細節,而是通過演進的過程,讓你擁有在何時應該採用哪些決策的良好背景。

入門

最基本的你需要購買一臺伺服器,比如可以從亞馬遜購買中配的伺服器。

你知道你的程式需要使用者登入,你需要儲存使用者資訊。因此你需要一個資料庫。由於預算有限,直接在你的伺服器上進行建立。最終得到的架構如下:

一個合理的生產環境的 Web 應用程式應該是什麼樣子的

這應該足夠了,事實上,使用這個架構,可以保障你的程式執行很長時間而沒有瓶頸。此時,你可能每天只需要處理 10 次訪問請求。其實一個最低配的伺服器已經足夠了,但是你的公司可能對業務持增長態度,所以選擇了中配的伺服器。

現在,你將有價值的業務資料儲存在例項中的資料庫中,如果伺服器發生故障,或者例項被刪除,很可能導致資料丟失,這是很可怕的。你應該確保資料備份到外部儲存。比如:S3 服務。所以讓我們設定它。你應該通過每隔一段時間恢復一次備份的方式來確保它正常執行。

你的架構應該如下所示:

一個合理的生產環境的 Web 應用程式應該是什麼樣子的

你已經提高了資料庫的可靠性,那麼你決定通過對伺服器進行負載測試來檢驗是否可以應對大規模的流量訪問。一切似乎進展順利,直到 500 錯誤出現,繼而是 404,所以你要排查是什麼原因造成的。

但實際上,你並不知道是什麼原因導致的,因為你把日誌寫到了控制檯,並沒有寫入到日誌檔案中。你看到該程式並沒有執行,因此你假設是這個原因導致了 404。

你可以通過建立 systemd 執行 Web 伺服器服務來解決自動啟動的問題,並解決你的日誌記錄問題。然後再進行新一輪的負載測試,以確保解決了所有的問題。

再一次,你看到了 500 錯誤,慶幸的是沒有 404,你檢查日誌看是哪裡出錯了。你發現資料庫的連線池已經飽和,該連線池設定了 10 個連線的限制。你更新了限制,重啟資料庫,然後再次執行負載測試。一切順利。所以你決定對你的網站進行推廣。

釋出日

哇!你的服務很受歡迎,在 30 分鐘內就獲得了 5000 次的點選,你看到有評論進來。他們怎麼說?

我訪問 404 了,於是我檢查我儲存的地址是否正確,竟然換地址了,如果有人需要,這是新的連結:……

……

什麼也沒有顯示,也許是因為我禁用了 JavaScript,但是,誰會需要 2MB 那麼大的 JS 檔案 ……

……

你們的主頁需要 4s 才能載入,而且訪問到的是離我很遠的一個地區的地址,另外,為什麼要載入 2MB 的 JS 檔案?

於是你拼命的進行了優化,你在伺服器通過 Nginx 設定了跳轉你應用程式的反向代理,你將靜態檔案進行了剝離,上傳到了 S3,這是很有效的,你可以通過 CDN 幫助加速你網站在不同地區的訪問。

一個合理的生產環境的 Web 應用程式應該是什麼樣子的

現在,你已經解決了當前的問題,那麼你可以通過訪問伺服器檢視日誌。你發現 SSH 連線非常慢,經過一番檢查,你發現你的日誌檔案已經耗盡了你的磁碟空間,這會使你的程式崩潰並阻止它再次啟動。你建立更大的磁碟儲存日誌,並且設定 logrotate 防止日誌檔案再次變得如此巨大。

效能問題

幾個月過去了,你的使用者數持續增長,你的網站開始變得很慢。你在監控中注意到,這種情況似乎只發生在午夜到中午之間。由於變慢開始和結束的時間比較固定,你猜測應該是伺服器上的定時任務造成的。你檢查 crontab 意識到你在午夜安排了備份任務。果然,你的備份過程需要持續 12 個小時,並且導致資料庫超載,導致了站點訪問明顯拖慢。

你覺得應該在從庫進行資料庫的備份,但是你記得,你並沒有建立從庫,所以你需要建立一個。在同一臺伺服器執行從庫沒有太大的意義,因此,你決定對伺服器進行擴充套件,建立了兩個新的伺服器:一個用於 master 資料庫,另一個用於 slave 資料庫。你將備份改為依據從庫執行。

一個合理的生產環境的 Web 應用程式應該是什麼樣子的

發展團隊

一切都很平穩,執行了一段時間。幾個月過去了。你擴充了開發團隊,其中一位新的開發人員為了檢查一個錯誤,導致了生產伺服器的故障。客戶把錯誤歸咎到了你沒有對生產測試環境進行區分。你覺得說的有道理,你是個虛心學習並且有追求的人,你把這次故障看做是一次學習的機會。

現在是到了構建規範的開發部署流程的時候了:分期開發,測試,然後部署。幸運的是,一開始你建立了良好的基礎架構,因此這變得很容易。因為你從第一天起,就良好的踐行了持續交付,你可以輕鬆的在一個新的分支進行構建。

業務部門希望推出 2.0 版本,但並沒有具體的業務需求,但是你還是去做了。你覺得是時候進行一次效能的改造。你的 Web 伺服器的執行現在已經接近峰值的利用率,因此你決定對流量進行負載均衡。而亞馬遜 ELB 使你很容易上手。與此同時你覺得你的架構圖應該是這樣的:

一個合理的生產環境的 Web 應用程式應該是什麼樣子的

另外還可以通過 Redis 等做一些快取策略。相信你的優化能夠承擔更大的負載,所以你再次對你的網站進行了大力推廣,不出所料,流量飆升,但執行很穩定。

一切看起來都那麼好,直到你需要去檢查日誌。這花費了你一個小時,因為要檢查 12 臺伺服器(每個環境有 4 臺伺服器)。那是一件麻煩事,幸運的是,你現在已經賺了足夠的錢可以實現 ELK 堆疊(ElasticSearch,LogStash,Kibana)。新的架構圖:

一個合理的生產環境的 Web 應用程式應該是什麼樣子的

現在,你可以再次閱讀你的日誌了,你發現了一些奇怪的情況。裡面充滿了:

GET /wp-login.php HTTP/1.1" 404 169 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1
GET /wp-login.php HTTP/1.1" 404 169 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1
GET /wp-login.php HTTP/1.1" 404 169 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1
GET /wp-login.php HTTP/1.1" 404 169 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1
GET /wp-login.php HTTP/1.1" 404 169 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1
GET /wp-login.php HTTP/1.1" 404 169 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1
GET /wp-login.php HTTP/1.1" 404 169 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1
GET /wp-login.php HTTP/1.1" 404 169 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1
GET /wp-login.php HTTP/1.1" 404 169 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1
GET /wp-login.php HTTP/1.1" 404 169 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1
複製程式碼

你並沒有執行 PHP 或 WordPress,所以很令人擔憂。你在資料庫伺服器上注意到類似的可疑日誌,你想怎麼把他們暴露在公網上了。所以是時候進行公網和本地訪問的隔離了。

一個合理的生產環境的 Web 應用程式應該是什麼樣子的

再次,你檢查了日誌,雖然仍然可能被黑客攻擊,但是僅限於負載均衡伺服器上的 80 埠,而你的應用伺服器,資料伺服器和 ELK 堆疊不再暴露在公網上。你可以輕鬆許多了。

雖然對日誌進行了集中式的記錄管理,但是還不得不手動檢查日誌。這時候使用伺服器提供商的監控,設定磁碟、CPU 和 網路報警,以便在達到 80% 的使用率時通過郵件等途徑通知你,是個不錯的選擇。

一帆風順

開玩笑,沒有哪個程式的執行是一帆風順的,總有事情會發生,幸運的是,你有很多工具可以處理這些問題。

現在,我們已經構建了一個可擴充套件的 Web 應用程式,包括備份,回滾,集中式日誌記錄管理,監控和警報。可以告一段落了,因為下面的改變往往取決於特定應用的需求。

業界提供了許多託管選項,可以為你處理大部分內容。你可以依靠 Beanstalk,AppEngine,GKE,ECS 等而不是自己構建所有這些服務。大多數這些服務都會自動設定合理的許可權,負載均衡,子網等。可以確保你的站點可以長時間執行。

瞭解這些平臺提供的功能以及什麼時候使用它們是非常有用的,這樣,你可以根據你的需要輕鬆選擇平臺。一旦你在相關平臺上執行了你的程式,你應該瞭解這些工具的工作原理,這是很重要的,有助於在遇到問題時,快速解決問題。

結尾

這篇文章省略了很多細節,不包括如何自動建立基礎架構,如何配置伺服器。不包括任何開發環境的建立,如何實踐持續交付,如何執行部署和回滾。不包括網路安全,私密共享或最小許可權原則。它不涵蓋不可變基礎架構,無狀態服務以及遷移的重要性。其實每個主題都可以獨立開闢一篇文章。

本文的主要目的是提供一個合理的生產環境的 Web 應用程式應該是什麼樣子的。

感謝你的閱讀!


關注公眾號「展白說」,獲取更多有價值的資訊。

相關文章