如何實現可擴展的架構?

作者 | Miloslav Voloskov

譯者 | 平川

策劃 | 萬佳

本文爲實現可擴展架構提出了幾個原則:使用合適的工具。不要把寫入優先和讀取優先數據庫弄混了。什麼東西都配置多份。要實現多份配置,就必須讓它們保持無狀態。不要讓後端完成數據庫的工作,那樣總是更慢。

可擴展性被認爲是一個很難解決的問題。人們總是把它看成是一種神奇的東西,是用神祕而特殊的工具完成的,只有身價百萬的大塊頭才能使用。這當然不是真的。其實,那並沒有什麼神奇之處——那也不過是用普通編程語言編寫的普通代碼。

首先,要針對工作選擇合適工具。你已經看過基準測試了,你知道有些語言在某些方面表現得更好。有些數據庫的讀取速度更快,而有些數據庫的寫入速度更快。即使你已經爲任務選擇了合適的技術棧,一臺服務器也是不夠的。這就是有趣的地方。當然,你可以直接從不同的 AWS 服務級別中進行選擇。但是,如果想知道其中的原理,你就應該知道如何在裸金屬上實現可擴展的設置。

1 基本原則

 選擇恰當的工具

不同的編程語言適用於不同的任務。

例如,Python 有非常豐富的語法糖,非常適合處理數據,而且代碼簡短而富有表現力。但爲了實現這一點,它需要運行在解釋器上,在默認情況下,這比編譯後在裸金屬上運行的 Go 或 C 是要慢的。

NodeJS 的外部工具可能是最豐富的,但它是單線程的。要在多核機器上運行 NodeJS,必須使用像 PM2 這樣的東西,但這樣的話,就必須保持代碼是無狀態的。

http://pm2.keymetrics.io/?fileGuid=gr8wsimng4sTPe0C

數據庫也是一樣。SQL 提供了圖靈完備性來查詢和處理數據,但這是有代價的——沒有緩存,SQL 幾乎總是比 NoSQL 慢。

除此之外,數據庫通常是讀取優先或寫入優先的。這就意味着,它們中的一些在寫入數據時速度更快,而另一些在大量讀取時性能更佳。

例如,對於需要大量寫入、偶爾讀取的分析及其他任務,你可能想要選擇 “寫入優先” 的數據庫,如 Cassandra。

對於顯示新聞這樣的讀取優先任務,最好使用像 MongoDB 這樣的東西。

如果兩者都需要,就安裝兩個數據庫!這不是不行。這不會造成什麼破壞。事情就應該這樣做。

 多服務器

當一臺計算機不夠用的時候,可以用兩臺。當兩臺不夠用的時候,可以買三臺,以此類推。

但也有一個陷阱:從 1 到 2 比從 2 到 3 或從 10 到 20 要難得多。

要使用多臺計算機,後端應該是無狀態的。這意味着你必須將所有數據都存儲到數據庫中,而後端不保存任何數據。這就是函數式語言在後端如此流行的原因,這也是 Scala 被髮明的原因。函數代碼默認是無狀態的。

無論如何,不同服務器的行爲應該完全相同。如果你有大量的有狀態服務器,那麼根據定義,對相同的輸入,它們很容易返回不同的數據作爲響應,因爲有兩個事實來源:數據庫和服務器狀態。相信我,你不會想讓這種事情發生的。

儘快實現無狀態。最好從一開始就選擇無狀態。如果你在使用 NodeJS 和 PM2,如果你想讓 PM2 幫你增加運行時以實現負載均衡,那你就必須讓代碼保持無狀態。

負載均衡器會將請求重新路由到最空閒的服務器。顯然,對於相同的請求,服務器應該提供完全相同的響應。這就是我們轉向無狀態的原因。對 NodeJS 來說,PM2 是一個很好的負載均衡選項。如果你用的不是 Node,就選擇 Nginx。

會話?把它們保存在 Redis 中,並讓所有服務器都可以訪問。

 緩存和速率限制

想象一下,每 100 毫秒針對每個用戶做同樣的計算。這將使服務器很容易受到 Slashdot 效應的影響——基本上只是用戶訪問數據就會導致 DDOS。

增加緩存中間件。只有第一個用戶將觸發數據查詢,其他所有用戶將直接從 RAM 接收完全相同的數據。

這也有缺點——默認情況下,數據會過期。通常,緩存中間件允許設置緩存重置時間,數據最終會刷新。

考慮用戶和他們的需求,配置相應的緩存。永遠不要緩存用戶輸入。只有服務器輸出應該被緩存。

Varnish 是一個很好的 HTTP 響應緩存選項,所以它可以用於任何後端。

https://varnish-cache.org/?fileGuid=gr8wsimng4sTPe0C

即使有了緩存,每 10 毫秒就會出現不同的請求,也可能會導致服務器宕機,因爲服務器會爲它們計算不同的響應。這就是爲什麼你需要一個速率限制器——如果距離上次請求的時間不夠長,正在進行的請求將被拒絕。這將使你的服務器保持活躍。

 劃分職責

如果你正在使用 SQL 數據庫,並且仍然使用後端計算外鍵,那麼你沒有充分利用數據庫的能力。只需設置記錄之間的關係並允許數據庫爲你計算外鍵——查詢規劃器總是比後端更快。

後端應該有不同的職責:哈希、從數據和模板構建網頁、管理會話等等。

對於任何與數據管理或數據模型相關的內容,將其作爲存儲過程或查詢移到數據庫中。

 大數據量

即使是使用數據庫集羣,最大容量也受限於服務器的主板。你不能只是把無限多的硬盤放在那裏。如果想要無限增長,除了使用分佈式數據庫之外,沒有其他選擇。它將數據存儲在不同的服務器上,最大容量接近所有服務器容量的總和。如果存儲空間不足,只需添加另一臺服務器即可。

通過主從複製,你可以將 DB 加倍並實現負載均衡,但容量不會無限增長。

 可能存在的瓶頸

2 設置舉例

 小貓

這是你一個晚上就可以在 LAMP 技術棧上構建的基本設置。它是有狀態的——它在內存中存儲會話和其他雜七雜八的東西。你猜對了,它根本無法擴展。但是,它仍然非常適合小型週末項目。

 大貓

我們添加了緩存。雖然速度提升了,但由於架構是有狀態的,所仍然不可擴展。當你的週末項目用戶增加時,你應該這樣做。

 獵豹

這是可擴展的!你可以擁有任意數量的服務器。現在,你可以處理所有可能導致 “大貓” 宕機的請求,但數據庫仍然是運行單個實例,必須處理所有請求。儘管如此,它還是非常適合小型項目、電子商店或類似的東西。

 老虎

這個架構速度很快,而且可擴展。看它有多漂亮。DB 和後端都做了負載均衡。這裏的瓶頸是,當你運行單個服務器或數據中心時,海外用戶可能會面臨高延遲,因爲他們距離很遠。但是,這種設置仍然可以應對許多用戶,非常適合新聞網站。

 獅子

這是一個 CDN——一種完全不同的東西。你在世界各地有多臺服務器,它們可以像主服務器一樣爲請求提供服務。這不像緩存,它們是全功能的。

來自不同大洲的用戶通過 DNS 進行隔離。

儘管服務器速度很快,但你仍然受限於一臺服務器的容量。你的數據庫是主數據庫的副本,因此你受限於主數據庫的容量。

這非常適合託管提供商、大型電子商務之類的東西。

 劍齒虎

這是終極形式。有了 Riak 這樣的圖形數據庫,容量將不再受限。當存儲資源不足時,你只需購買一個新的存儲服務器並將其添加進去。

非常適合創建像谷歌或 Facebook 那樣的應用。

3 總結

我們回顧了幾乎每類項目的一些最常見的設置。不一定非要使用上述設置——根據自己的需要進行設計。只要記住,每個工具都有它的用途,務必選擇適合你的工作的合適工具。

保證可擴展,保證無狀態!

原文鏈接:

https://mvoloskov.hashnode.dev/scalable-architecture-without-magic-and-how-to-build-it-if-youre-not-google?fileGuid=gr8wsimng4sTPe0C

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/9_EueIQxrpPzvOYmvwczzw