警告:本文內容是入門級的,大佬請按秩序有序撤離。
原文地址:Web Architecture 101
上圖很好的展示了我們在Storyblocks的架構。如果你是一個新手工程師,可能會覺得這個架構非常複雜。在我們深入研究每個元件的細節之前,首先應該對它們有個大概的瞭解。
當一個使用者在Google搜尋“Strong Beautiful Fog And Sunbeams In The Forest”時,第一條結果來自Storyblocks,我們主要的照片網站。使用者點選結果就會在瀏覽器中跳轉到圖片詳情頁。在引擎下,使用者的瀏覽器想DNS伺服器傳送一個請求,查詢如何連線Storyblocks,然後向Storyblocks傳送請求。
請求會先到達我們的負載均衡器,負載均衡器會隨機選擇一個正在執行的伺服器來處理請求。伺服器先從快取中查詢一部分關於圖片的資訊,並從資料庫查詢剩餘資訊。我們注意到此時還沒有對圖片的顏色進行配置,因此我們傳送“color profile”任務到我們的任務佇列,處理任務的伺服器會非同步執行佇列中的任務,並且將結果適時更新到資料庫中。
接下來,我們試圖從使用照片標題在全文檢索服務中找到與輸入的照片相似的照片。如果登入使用者是Storyblocks的會員,我們會去賬號服務中查詢使用者的相關資訊。最後,我們會把頁面訪問資料傳送到資料“firehose”,以便儲存到我們的雲端儲存系統上,並最終落地到資料倉儲中。資料分析師會使用資料倉儲中的資料來解決商業問題。
到這裡,伺服器已經呈現了一個HTML頁面,並通過負載均衡器將它返回給使用者。頁面包含的JavaScript和CSS會放到連線了CDN的雲端儲存系統中,所以使用者的瀏覽器連線CDN取回資料。最後,由瀏覽器給使用者呈現完整的頁面。
接下來,我會對每個元件挨個進行簡單的介紹,以求給你建立一個良好的關於學習架構的思維模型。我會在另外一個系列的文章中分享我在Storyblocks這段時間的實踐經驗,給你提供良好的建議。
1. DNS
DNS是“Domain Name System”的縮寫,它是使全球資訊網成為可能的核心技術。最基礎的DNS提供了域名(例如google.com)和IP地址的(例如85.129.83.120)的鍵值對以供查詢,這是計算機路由請求到指定伺服器所必需的。類別電話號碼,域名和IP地址的區別就像是“打給哲少”和“撥打201-867–5309”。就像過去你需要一個電話本來查詢哲少的電話號碼,如今你需要DNS伺服器來查詢域名對應的IP地址。所以你可以認為DNS就是網際網路上的電話本。
關於DNS的細節我們還可以展開講很多,但這裡我們略過,因為這不是入門級介紹所關心的。
2. Load Balancer
在介紹負載均衡器之前,我們先來討論一下應用的水平和垂直擴充套件。它們有什麼不同呢?這篇帖子介紹的很明白,水平擴充套件是通過向資源池中增加更多的機器,垂直擴充套件是在已有的機器中增加更高的配置(CPU、記憶體等)。
在Web開發中,為了應對伺服器當機,網路波動,資料中心不可用等突發情況,你一定經常使用橫向擴充套件,因為它既簡單又快捷。擁有一臺以上的伺服器使你的應用程式在部分伺服器掉電時仍然可以正常執行。換句話說,你的程式具有較好的容錯性。其次,橫向擴充套件允許你通過讓每個部分執行在不同的伺服器上來解耦後端的依賴(Web伺服器、資料庫、服務 X等)。最後,當你的伺服器達到一定規模時可能無法再進行垂直擴充套件。因為這個世界上沒有任何一臺計算機的效能好到可以支撐你所有應用的計算。舉一個典型的栗子——Google的搜尋平臺。當然一原則對於多數規模較小的公司也適用,例如Storyblocks就部署了150到400個AWS EC2例項。對於這樣的情況,要想通過垂直擴充套件來提供全部計算是一項艱難的挑戰。
我們再說回負載均衡器,它們使水平擴充套件成為可能。它們將傳入進來的請求路由到眾多伺服器中的一個,並將響應結果返回給客戶端。這些伺服器通常是彼此的克隆或映象,它們中的任何一個都應該以相同的方式處理,這樣就通過分發請求的方式解決避免某臺機器出現過載問題。
負載均衡的概念非常簡單,但是實現起來非常複雜。我們暫且不介紹。
3. Web Application Servers
在上層的Web應用服務描述起來非常簡單。它們用來執行主要的業務邏輯,處理使用者請求,並將HTML返回到使用者的瀏覽器。為了完成任務,它們通常要與各種後端基礎元件互動,比如資料庫、快取、任務佇列、檢索服務、其他微服務、資料/日誌佇列等等。如上所述,為了處理使用者請求,你至少有兩個,通常更多的負載均衡器。
你應該知道應用服務的實現需要選擇一種語言(Node.js、Ruby、PHP、 Scala、 Java、 C# 、.NET等)和對應MVC框架(Node.js的Express,Ruby的Rails,Scala的Play,PHP的Laravel等)。然而深挖這些語言和框架的細節也超出了本文的討論範圍。
4. Database Servers
每個Web應用專案都利用一個或多個資料庫來儲存資訊。資料庫提供了定義資料結構、對資料的增刪改查、跨資料計算的方法。多數情況下,Web應用伺服器和任務佇列直接通訊。另外每個後端服務可能都擁有獨立的資料庫。
雖然我一直強調本文不會介紹某個元件的細節,但是如果不提SQL和NOSQL也是一種不負責任的行為。
SQL的全稱是“結構化查詢語言”,它在18世紀70年代被髮明。它給大家提供了查詢關係型資料集的標準方法。SQL資料庫將資料儲存在通過公共ID(通常是整數)連線在一起的表中。讓我們來看一個儲存使用者歷史地址資訊的例子。你可能需要兩張表,使用者表和使用者地址表,它們通過使用者ID連線在一起。下圖展示了一個簡化版本。兩個表通過外來鍵連線。
如果你不是很瞭解SQL,我強烈推薦你學習一下Khan Academy的一門課程。SQL現在已經非常普及了,因此你至少要了解一些基礎知識才能構建你的應用程式。
NoSQL代表“非SQL”,是一種新的資料庫技術集,用於處理大規模Web應用產生的大量資料(大多數SQL不支援水平擴充套件,並且垂直擴充套件也只能擴充套件到某個點)。如果你不瞭解NoSQL,可以看下面這些介紹:
但是總的來說,業界還是要將SQL作為資料庫的統一介面,即使是對菲關係型資料庫,所以如果你還不瞭解SQL的話,就真的要趕快去學習一下了。
5. Caching Service
快取服務提供了簡單的kv儲存資料,儘可能使儲存和查詢資料的時間複雜度接近O(1)。應用程式一般把計算比較複雜的結果儲存到快取服務中,以便再次取值時直接從快取中讀取而不用重新進行復雜的計算。應用可能快取的資訊包括,資料庫查詢的結果,呼叫外部服務的返回值,一個URL返回的HTML等等。下面是一些實際的例子:
- Google會將搜尋結果快取
- Facebook在你登入後會快取你看到的大部分資訊,比如帖子、好友等。關於Facebook的快取技術快取可以看這篇文章
- Storyblocks快取來自伺服器端React渲染,搜尋結果和預輸入結果等的HTML輸出。
目前應用最廣泛的兩種快取服務是Redis和Memcache。我會在另一篇文章中對它們進行更深入的介紹。
6. Job Queue & Servers
很多應用程式需要在後臺非同步處理一些和返回結果無關的邏輯。比如,Google為了提供搜尋服務,需要爬取網頁並進行索引。它並不是在你每次搜尋的時候都去做這件事,而是非同步爬取,並更新索引。
雖然現在有很多不同的架構都支援非同步操作,但最普及的是我所說的“任務佇列”架構。它包含兩個元件:一個任務佇列和至少一個任務伺服器來執行佇列中的任務。
任務佇列通常儲存一系列需要非同步執行的任務。最簡單的規則是先進先出(FIFO),大多數應用按照優先順序給任務排序。當應用需要執行一個任務時,無論是定時任務還是使用者操作,都會把任務放到佇列中去。
還拿Storyblocks舉例,我們使用一個後臺的任務佇列為我們的市場提供支援。我們會跑一些視訊圖片解碼,處理CSV後設資料標記,彙總使用者統計資訊,傳送重置密碼郵件等任務。我們一開始採用FIFO的原則,後來改為優先順序佇列,以保證有些具有時效性的任務能儘快完成,比如傳送重置密碼郵件。
任務伺服器用來處理任務。它們輪詢任務佇列以確定是否有任務要執行以及是否有任務,如果有,就從任務佇列中彈出一個任務來執行。底層語言和框架的選擇非常多,但它們不在本文討論範圍。
7. Full-text Search Service
許多web應用支援某種搜尋功能——使用者輸入文字,應用返回“相關”的結果。支撐這種功能的技術一般稱為全文檢索,它利用反向索引快速找到包含關鍵字的文件。
現在某些資料庫也支援檢索功能(比如MySQL已經支援全文檢索),通常是執行獨立的搜尋服務來計算和儲存反向索引,並提供查詢介面。目前最受歡迎的全文檢索平臺是Elasticsearch,另外還有一些其他比較好的平臺 例如Sphinx和Apache Solr。
8. Services
一旦一個APP達到一定的規模,就會有某些服務被獨立出來執行。它們不會對外暴露,但是可以和應用內部的服務之間互動。Storyblocks有幾個運營和計劃的服務:
- Account service儲存我們所有網站上的使用者資料,這使我們可以更輕鬆的提供交叉銷售機會並建立更統一的使用者體驗
- Content service儲存我們所有的視訊、音訊和圖片的後設資料。也提供了下載介面和檢視歷史下載記錄的介面。
- Payment service提供對使用者信用卡進行計費的介面
- HTML → PDF service提供了一個簡單的HTML轉PDF的介面
9. Data
當下,一家公司的生死由他們駕馭資料的能力決定。如今幾乎每個APP一旦達到一定規模,就需要通過資料管道來收集、儲存和分析資料。典型的管道有三個步驟:
- APP傳送資料,典型的關於使用者互動的事件,資料傳送到“firehose”——提供獲取和處理資料的介面。原始資料通常需要進行轉換、增強併傳送到另一個firehose。AWS Kinesis和Kafka是兩個公共工具。
- 原始資料和轉換/增強後的資料都被儲存到雲端。AWS Kinesis提供了一個名為firehose的設定,可以將原始資料儲存到其雲端儲存(S3),配置起來非常容易。
- 轉換/增強後的資料通常會被載入進資料倉儲用作資料分析。我們使用的是AWS Redshift,大部分創業公司和增長的部分也是如此,儘管大公司會使用Oracle或其他專有的倉庫技術。
另外一個沒有在架構圖中畫出來的一個步驟:將資料從應用程式和服務的運算元據庫載入到資料倉儲中。例如在Storyblocks,我們每晚將VideoBlocks, AudioBlocks, Storyblocks, account service和貢獻值入口網站的資料載入到Redshift。通過將核心業務資料與我們的使用者互動事件資料放在一起,為我們的分析師提供了一整個資料集。
10. Cloud storage
“雲端儲存是一種簡單、可靠且可擴充套件的儲存、檢索和共享資料的方法”——來自AWS。你可以使用它儲存或多或少的儲存和訪問本地檔案系統的任何內容,並且可以通過HTTP上的RESTful API與其進行互動。Amazon的S3是目前最流行的雲端儲存產品,也是我們在Storyblocks廣泛依賴的產品,用於儲存我們的視訊、照片和音訊資產,我們的CSS和JavaScript,我們的使用者資料等等。
11. CDN
CDN的全稱是“Content Delivery Network”,該技術提供了通過Web獲取靜態HTML,CSS,JavaScript和影象資源的方式,比直接從單個源伺服器提供服務要快得多。它的工作原理是在世界各地的許多“邊緣”伺服器上分發內容,以便使用者從“邊緣”伺服器而不是源伺服器下載資源。例如下圖中,一個使用者從西班牙請求源伺服器在紐約的網站,但是靜態資源會從在英國的CDN邊緣伺服器載入,防止許多緩慢的跨大西洋HTTP請求。
這篇文章進行了更詳盡的介紹。通常web應用應該始終使用CDN來提供CSS,JavaScript,圖片,視訊和其他資源。某些應用也可能利用CDN來提供靜態HTML頁面。
總結
這是一篇入門級的Web架構總結。希望能夠對你有幫助。我希望釋出一系列的進階文章,在接下來一兩年內我會對這些元件進行深入研究。