手把手教你構建一個高效能、高可用的大型分散式網站
本文是學習大型分散式網站架構的技術總結,對構建一個高效能、高可用、可伸縮及可擴充套件的分散式網站進行了概要性描述,並給出一個架構參考。
文中一部分為讀書筆記,一部分是個人經驗總結,對大型分散式網站架構有較好的參考價值。
大型分散式網站架構技術
大型網站的特點
- 大型網站一般有如下特點:
- 使用者多,分佈廣泛
- 大流量,高併發
- 海量資料,服務高可用
- 安全環境惡劣,易受網路攻擊
- 功能多,變更快,頻繁釋出
- 從小到大,漸進發展
- 以使用者為中心
- 免費服務,付費體驗
大型網站架構目標
大型網站的架構目標有如下幾個:
- 高效能:提供快速的訪問體驗。
- 高可用:網站服務一直可以正常訪問。
- 可伸縮:通過硬體增加/減少,提高/降低處理能力。
- 擴充套件性:方便地通過新增/移除方式,增加/減少新的功能/模組。
- 安全性:提供網站安全訪問和資料加密、安全儲存等策略。
- 敏捷性:隨需應變,快速響應。
大型網站架構模式
如上圖是大型網站的架構模式:
- 分層:一般可分為應用層、服務層、資料層、管理層與分析層。
- 分割:一般按照業務/模組/功能特點進行劃分,比如應用層分為首頁、使用者中心。
- 分散式:將應用分開部署(比如多臺物理機),通過遠端呼叫協同工作。
- 叢集:一個應用/模組/功能部署多份(如:多臺物理機),通過負載均衡共同提供對外訪問。
- 快取:將資料放在距離應用或使用者最近的位置,加快訪問速度。
- 非同步:將同步的操作非同步化。客戶端發出請求,不等待服務端響應,等服務端處理完畢後,使用通知或輪詢的方式告知請求方。一般指:請求——響應——通知模式。
- 冗餘:增加副本,提高可用性、安全性與效能。
- 安全:對已知問題有有效的解決方案,對未知/潛在問題建立發現和防禦機制。
- 自動化:將重複的、不需要人工參與的事情,通過工具的方式,使用機器完成。
- 敏捷性:積極接受需求變更,快速響應業務發展需求。
高效能架構
高效能的架構是以使用者為中心,提供快速的網頁訪問體驗,主要引數有較短的響應時間、較大的併發處理能力、較高的吞吐量與穩定的效能引數。
可分為前端優化、瀏覽器優化、應用層優化、程式碼層優化與儲存層優化:
- 前端優化:網站業務邏輯之前的部分。
- 瀏覽器優化:減少 HTTP 請求數,使用瀏覽器快取,啟用壓縮,CSS JS 位置,JS 非同步,減少 Cookie 傳輸;CDN 加速,反向代理。
- 應用層優化:處理網站業務的伺服器。使用快取,非同步,叢集。
- 程式碼優化:合理的架構,多執行緒,資源複用(物件池,執行緒池等),良好的資料結構,JVM調優,單例,Cache 等。
- 儲存優化:快取、固態硬碟、光纖傳輸、優化讀寫、磁碟冗餘、分散式儲存(HDFS)、NoSQL 等。
高可用架構
大型網站應該在任何時候都可以正常訪問,正常提供對外服務。因為大型網站的複雜性,分散式,廉價伺服器,開源資料庫,作業系統等特點,要保證高可用是很困難的,也就是說網站的故障是不可避免的。
如何提高可用性,就是需要迫切解決的問題。首先,需要從架構級別考慮,在規劃的時候,就考慮可用性。
行業內一般用幾個 9 表示可用性指標,比如四個 9(99.99),一年內允許的不可用時間是 53 分鐘。
不同層級使用的策略不同,一般採用冗餘備份和失效轉移解決高可用問題:
- 應用層:一般設計為無狀態的,對於每次請求,使用哪一臺伺服器處理是沒有影響的。一般使用負載均衡技術(需要解決 Session 同步問題)實現高可用。
- 服務層:負載均衡,分級管理,快速失敗(超時設定),非同步呼叫,服務降級,冪等設計等。
- 資料層:冗餘備份(冷,熱備[同步,非同步],溫備),失效轉移(確認,轉移,恢復)。資料高可用方面著名的理論基礎是 CAP 理論。(永續性,可用性,資料一致性[強一致,使用者一致,最終一致])
可伸縮架構
伸縮性是指在不改變原有架構設計的基礎上,通過新增/減少硬體(伺服器)的方式,提高/降低系統的處理能力:
- 應用層:對應用進行垂直或水平切分。然後針對單一功能進行負載均衡(DNS、HTTP[反向代理]、IP、鏈路層)。
- 服務層:與應用層類似。
- 資料層:分庫、分表、NoSQL 等;常用演算法 Hash,一致性 Hash。
可擴充套件架構
可以方便地進行功能模組的新增/移除,提供程式碼/模組級別良好的可擴充套件性:
- 模組化,元件化:高內聚,低耦合,提高複用性,擴充套件性。
- 穩定介面:定義穩定的介面,在介面不變的情況下,內部結構可以“隨意”變化。
- 設計模式:應用面向物件思想,原則,使用設計模式,進行程式碼層面的設計。
- 訊息佇列:模組化的系統,通過訊息佇列進行互動,使模組之間的依賴解耦。
- 分散式服務:公用模組服務化,提供其他系統使用,提高可重用性,擴充套件性。
安全架構
對已知問題有有效的解決方案,對未知/潛在問題建立發現和防禦機制。對於安全問題,首先要提高安全意識,建立一個安全的有效機制,從政策層面,組織層面進行保障。
比如伺服器密碼不能洩露,密碼每月更新,並且三次內不能重複;每週安全掃描等。
以制度化的方式,加強安全體系的建設。同時,需要注意與安全有關的各個環節。
安全問題不容忽視,包括基礎設施安全,應用系統安全,資料保密安全等:
- 基礎設施安全:硬體採購,作業系統,網路環境方面的安全。一般採用正規渠道購買高質量的產品,選擇安全的作業系統,及時修補漏洞,安裝防毒軟體防火牆。
防範病毒,後門。設定防火牆策略,建立 DDOS 防禦系統,使用攻擊檢測系統,進行子網隔離等手段。
- 應用系統安全:在程式開發時,對已知常用問題,使用正確的方式,在程式碼層面解決掉。
防止跨站指令碼攻擊(XSS),注入攻擊,跨站請求偽造(CSRF),錯誤資訊,HTML 註釋,檔案上傳,路徑遍歷等。
還可以使用 Web 應用防火牆(比如:ModSecurity),進行安全漏洞掃描等措施,加強應用級別的安全。
- 資料保密安全:儲存安全(儲存在可靠的裝置,實時,定時備份),儲存安全(重要的資訊加密儲存,選擇合適的人員複雜儲存和檢測等),傳輸安全(防止資料竊取和資料篡改)。
常用的加解密演算法(單項雜湊加密[MD5、SHA],對稱加密[DES、3DES、RC]),非對稱加密[RSA]等。
敏捷性
網站的架構設計,運維管理要適應變化,提供高伸縮性,高擴充套件性。方便的應對快速的業務發展,突增高流量訪問等要求。
除上面介紹的架構要素外,還需要引入敏捷管理,敏捷開發的思想。使業務,產品,技術,運維統一起來,隨需應變,快速響應。
大型架構舉例
以上採用七層邏輯架構:
- 第一層客戶層:支援 PC 瀏覽器和手機 App。差別是手機 App 可以直接通過IP訪問,反向代理伺服器。
- 第二層前端層:使用 DNS 負載均衡,CDN 本地加速以及反向代理服務。
- 第三層應用層:網站應用叢集;按照業務進行垂直拆分,比如商品應用,會員中心等。
- 第四層服務層:提供公用服務,比如使用者服務,訂單服務,支付服務等。
- 第五層資料層:支援關係型資料庫叢集(支援讀寫分離),NOSQL 叢集,分散式檔案系統叢集;以及分散式 Cache。
- 第六層大資料儲存層:支援應用層和服務層的日誌資料收集,關係資料庫和 NOSQL 資料庫的結構化和半結構化資料收集。
- 第七層大資料處理層:通過 Mapreduce 進行離線資料分析或 Storm 實時資料分析,並將處理後的資料存入關係型資料庫。
(實際使用中,離線資料和實時資料會按照業務要求進行分類處理,並存入不同的資料庫中,供應用層或服務層使用)
大型電商網站系統架構演變過程
一個成熟的大型網站(如淘寶、天貓、騰訊等)的系統架構並不是一開始設計時就具備完整的高效能、高可用、高伸縮等特性的,它是隨著使用者量的增加,業務功能的擴充套件逐漸演變完善的。
在這個過程中,開發模式、技術架構、設計思想也發生了很大的變化,就連技術人員也從幾個人發展到一個部門甚至一條產品線。
所以成熟的系統架構是隨著業務的擴充套件而逐步完善的,並不是一蹴而就;不同業務特徵的系統,會有各自的側重點。
例如淘寶,要解決海量的商品資訊的搜尋、下單、支付;例如騰訊,要解決數億使用者的實時訊息傳輸;百度要處理海量的搜尋請求。
他們都有各自的業務特性,系統架構也有所不同。儘管如此,我們也可以從這些不同的網站背景中,找出其中共用的技術。
這些技術和手段廣泛運用在大型網站系統的架構中,下面就通過介紹大型網站系統的演化過程,來認識這些技術和手段。
最開始的網站架構
最初的架構,應用程式、資料庫、檔案都部署在一臺伺服器上,如下圖:
應用、資料、檔案分離
隨著業務的擴充套件,一臺伺服器已經不能滿足效能需求,所以將應用程式、資料庫、檔案各自部署在獨立的伺服器上,並且根據伺服器的用途配置不同的硬體,達到最佳的效能效果。
利用快取改善網站效能
在硬體優化效能的同時,也通過軟體進行效能優化,在大部分的網站系統中,都會利用快取技術改善系統的效能。
使用快取主要源於熱點資料的存在,大部分網站訪問都遵循 28 原則(即 80% 的訪問請求,最終落在 20% 的資料上),所以我們可以對熱點資料進行快取,減少這些資料的訪問路徑,提高使用者體驗。
快取實現常見的方式是本地快取、分散式快取。當然還有 CDN、反向代理等。
本地快取,顧名思義是將資料快取在應用伺服器本地,可以存在記憶體中,也可以存在檔案,OSCache 就是常用的本地快取元件。
本地快取的特點是速度快,但因為本地空間有限所以快取資料量也有限。
分散式快取的特點是,可以快取海量的資料,並且擴充套件非常容易,在門戶類網站中常常被使用,速度按道理沒有本地快取快,常用的分散式快取是 Memcached、Redis。
使用叢集改善應用伺服器效能
應用伺服器作為網站的入口,會承擔大量的請求,我們往往通過應用伺服器叢集來分擔請求數。
應用伺服器前面部署負載均衡伺服器排程使用者請求,根據分發策略將請求分發到多個應用伺服器節點。
常用的負載均衡技術硬體的有 F5,價格比較貴,軟體的有 LVS、Nginx、HAProxy。
LVS 是四層負載均衡,根據目標地址和埠選擇內部伺服器,Nginx 和 HAProxy 是七層負載均衡,可以根據報文內容選擇內部伺服器。
因此 LVS 分發路徑優於 Nginx 和 HAProxy,效能要高些;而 Nginx 和 HAProxy 則更具配置性,如可以用來做動靜分離(根據請求報文特徵,選擇靜態資源伺服器還是應用伺服器)。
資料庫讀寫分離和分庫分表
隨著使用者量的增加,資料庫成為最大的瓶頸。改善資料庫效能常用的手段是進行讀寫分離以及分庫分表,讀寫分離顧名思義就是將資料庫分為讀庫和寫庫,通過主備功能實現資料同步。
分庫分表則分為水平切分和垂直切分,水平切分是對一個數據庫特大的表進行拆分,例如使用者表。
垂直切分則是根據業務的不同來切分,如使用者業務、商品業務相關的表放在不同的資料庫中。
使用 CDN 和反向代理提高網站效能
假如我們的伺服器都部署在成都的機房,對於四川的使用者來說訪問是較快的,而對於北京的使用者訪問是較慢的。
這是由於四川和北京分別屬於電信和聯通的不同發達地區,北京使用者訪問需要通過互聯路由器經過較長的路徑才能訪問到成都的伺服器,返回路徑也一樣,所以資料傳輸時間比較長。
對於這種情況,常常使用 CDN 解決,CDN 將資料內容快取到運營商的機房,使用者訪問時先從最近的運營商獲取資料,這樣大大減少了網路訪問的路徑。比較專業的 CDN 運營商有藍汛、網宿。
而反向代理,則是部署在網站的機房,當用戶請求達到時首先訪問反向代理伺服器,反向代理伺服器將快取的資料返回給使用者。
如果沒有快取資料才會繼續訪問應用伺服器獲取,這樣做減少了獲取資料的成本。反向代理有 Squid、Nginx。
使用分散式檔案系統
使用者一天天增加,業務量越來越大,產生的檔案越來越多,單臺的檔案伺服器已經不能滿足需求,這時就需要分散式檔案系統的支撐。常用的分散式檔案系統有 GFS、HDFS、TFS。
使用 NoSQL 和搜尋引擎
對於海量資料的查詢和分析,我們使用 NoSQL 資料庫加上搜索引擎可以達到更好的效能。並不是所有的資料都要放在關係型資料中。
常用的 NoSQL 有 MongoDB、HBase、Redis,搜尋引擎有 Lucene、Solr、Elasticsearch。
將應用伺服器進行業務拆分
隨著業務進一步擴充套件,應用程式變得非常臃腫,這時我們需要將應用程式進行業務拆分,如百度分為新聞、網頁、圖片等業務。
每個業務應用負責相對獨立的業務運作。業務之間通過訊息進行通訊或者共享資料庫來實現。
搭建分散式服務
這時我們發現各個業務應用都會使用到一些基本的業務服務,例如使用者服務、訂單服務、支付服務、安全服務,這些服務是支撐各業務應用的基本要素。
我們將這些服務抽取出來利用分步式服務框架搭建分散式服務。阿里的 Dubbo 是一個不錯的選擇。
一張圖說明電商架構
大型電商網站架構案例
採用電商案例的原因
分散式大型網站,目前看主要有幾類:
- 大型門戶,比如網易,新浪等。
- SNS 網站,比如校內,開心網等。
- 電商網站,比如阿里巴巴,京東商城,國美線上,汽車之家等。
大型門戶一般是新聞類資訊,可以使用 CDN,靜態化等方式優化,開心網等互動性比較多,可能會引入更多的 NoSQL,分散式快取,使用高效能的通訊框架等。
電商網站具備以上兩類的特點,比如產品詳情可以採用 CDN,靜態化,互動性高的需要採用 NoSQL 等技術。因此,我們採用電商網站作為案例,進行分析。
電商網站需求
客戶需求:
- 建立一個全品類的電子商務網站(B2C),使用者可以線上購買商品,可以線上支付,也可以貨到付款。
- 使用者購買時可以線上與客服溝通。
- 使用者收到商品後,可以給商品打分,評價。
- 目前有成熟的進銷存系統;需要與網站對接。
- 希望能夠支援 3~5 年,業務的發展。
- 預計 3~5 年,使用者數達到 1000 萬。
- 定期舉辦雙 11、雙 12、三八男人節等活動。
- 其他的功能參考京東或國美線上等網站。
客戶就是客戶,不會告訴你具體要什麼,只會告訴你他想要什麼,我們很多時候要引導,挖掘客戶的需求。好在提供了明確的參考網站。
因此,下一步要進行大量的分析,結合行業,以及參考網站,給客戶提供方案。
需求功能矩陣
這是需求管理傳統的做法,會使用用例圖或模組圖(需求列表)進行需求的描述。
這樣做常常忽視掉一個很重要的需求(非功能需求),因此推薦大家使用需求功能矩陣,進行需求描述。
本電商網站的需求矩陣如下:
網站初級架構
一般網站,剛開始的做法,是三臺伺服器,一臺部署應用,一臺部署資料庫,一臺部署 NFS 檔案系統。
這是前幾年比較傳統的做法,之前見到一個網站 10 萬多會員,垂直服裝設計門戶,N 多圖片。
使用了一臺伺服器部署了應用,資料庫以及圖片儲存。出現了很多效能問題,如下圖:
但是,目前主流的網站架構已經發生了翻天覆地的變化。一般都會採用叢集的方式,進行高可用設計。
至少是上面這個樣子:
使用叢集對應用伺服器進行冗餘,實現高可用。(負載均衡裝置可與應用一塊部署)
使用資料庫主備模式,實現資料備份和高可用。
系統容量預估
預估步驟:
- 註冊使用者數-日均 UV 量-每日的 PV 量-每天的併發量。
- 峰值預估:平常量的 2~3 倍。
- 根據併發量(併發,事務數),儲存容量計算系統容量。
根據客戶需求:3~5 年使用者數達到 1000 萬註冊使用者,可以做每秒併發數預估:
- 每天的 UV 為 200 萬(二八原則)。
- 每日每天點選瀏覽 30 次。
- PV 量:200*30=6000 萬。
- 集中訪問量:24*0.2=4.8 小時會有 6000 萬*0.8=4800 萬(二八原則)。
- 每分併發量:4.8*60=288 分鐘,每分鐘訪問 4800/288=16.7 萬(約等於)。
- 每秒併發量:16.7萬/60=2780(約等於)。
- 假設:高峰期為平常值的三倍,則每秒的併發數可以達到 8340 次。
- 1 毫秒=1.3 次訪問。
沒好好學數學後悔了吧?!(不知道以上算是否有錯誤,呵呵~~)
伺服器預估:(以 Tomcat 伺服器舉例)
按一臺 Web 伺服器,支援每秒 300 個併發計算。平常需要 10 臺伺服器(約等於);[tomcat 預設配置是 150],高峰期需要 30 臺伺服器。
容量預估:70/90 原則
系統 CPU 一般維持在 70% 左右的水平,高峰期達到 90% 的水平,是不浪費資源,並比較穩定的。記憶體,IO 類似。
以上預估僅供參考,因為伺服器配置,業務邏輯複雜度等都有影響。在此 CPU,硬碟,網路等不再進行評估。
網站架構分析
根據以上預估,有幾個問題:
- 需要部署大量的伺服器,高峰期計算,可能要部署 30 臺 Web 伺服器。並且這三十臺伺服器,只有秒殺,活動時才會用到,存在大量的浪費。
- 所有的應用部署在同一臺伺服器,應用之間耦合嚴重。需要進行垂直切分和水平切分。
- 大量應用存在冗餘程式碼。
- 伺服器 Session 同步耗費大量記憶體和網路頻寬。
- 資料需要頻繁訪問資料庫,資料庫訪問壓力巨大。
大型網站一般需要做以下架構優化(優化是架構設計時,就要考慮的,一般從架構/程式碼級別解決,調優主要是簡單引數的調整,比如 JVM 調優;如果調優涉及大量程式碼改造,就不是調優了,屬於重構):
- 業務拆分
- 應用叢集部署(分散式部署,叢集部署和負載均衡)
- 多級快取
- 單點登入(分散式 Session)
- 資料庫叢集(讀寫分離,分庫分表)
- 服務化
- 訊息佇列
- 其他技術
網站架構優化
業務拆分
根據業務屬性進行垂直切分,劃分為產品子系統,購物子系統,支付子系統,評論子系統,客服子系統,介面子系統(對接如進銷存,簡訊等外部系統)。
根據業務子系統進行等級定義,可分為:
- 核心系統,產品子系統,購物子系統,支付子系統。
- 非核心繫統,評論子系統,客服子系統,介面子系統。
業務拆分作用:提升為子系統可由專門的團隊和部門負責,專業的人做專業的事,解決模組之間耦合以及擴充套件性問題;每個子系統單獨部署,避免集中部署導致一個應用掛了,全部應用不可用的問題。
等級定義作用:用於流量突發時,對關鍵應用進行保護,實現優雅降級;保護關鍵應用不受到影響。
拆分後的架構圖:
參考部署方案 2:
如上圖每個應用單獨部署,核心系統和非核心繫統組合部署。
應用叢集部署(分散式,叢集,負載均衡)
分散式部署:將業務拆分後的應用單獨部署,應用直接通過 RPC 進行遠端通訊。
叢集部署:電商網站的高可用要求,每個應用至少部署兩臺伺服器進行叢集部署。
負載均衡:是高可用系統必須的,一般應用通過負載均衡實現高可用,分散式服務通過內建的負載均衡實現高可用,關係型資料庫通過主備方式實現高可用。
叢集部署後架構圖:
多級快取
快取按照存放的位置一般可分為兩類本地快取和分散式快取。本案例採用二級快取的方式,進行快取的設計。
一級快取為本地快取,二級快取為分散式快取。(還有頁面快取,片段快取等,那是更細粒度的劃分)
一級快取,快取資料字典,和常用熱點資料等基本不可變/有規則變化的資訊,二級快取快取需要的所有快取。
當一級快取過期或不可用時,訪問二級快取的資料。如果二級快取也沒有,則訪問資料庫。
快取的比例,一般 1:4,即可考慮使用快取。(理論上是 1:2 即可):
根據業務特性可使用以下快取過期策略:
- 快取自動過期
- 快取觸發過期
單點登入(分散式 Session)
系統分割為多個子系統,獨立部署後,不可避免的會遇到會話管理的問題。一般可採用 Session 同步,Cookies,分散式 Session 方式。電商網站一般採用分散式 Session 實現。
再進一步可以根據分散式 Session,建立完善的單點登入或賬戶管理系統。
流程說明如上圖:
- 使用者第一次登入時,將會話資訊(使用者 ID 和使用者資訊),比如以使用者 ID 為 Key,寫入分散式 Session。
- 使用者再次登入時,獲取分散式 Session,是否有會話資訊,如果沒有則調到登入頁。
- 一般採用 Cache 中介軟體實現,建議使用 Redis,因此它有持久化功能,方便分散式 Session 宕機後,可以從持久化儲存中載入會話資訊。
- 存入會話時,可以設定會話保持的時間,比如 15 分鐘,超過後自動超時。
結合 Cache 中介軟體,實現的分散式 Session,可以很好的模擬 Session 會話。
資料庫叢集(讀寫分離,分庫分表)
大型網站需要儲存海量的資料,為達到海量資料儲存,高可用,高效能一般採用冗餘的方式進行系統設計。一般有兩種方式讀寫分離和分庫分表。
讀寫分離:一般解決讀比例遠大於寫比例的場景,可採用一主一備,一主多備或多主多備方式。
本案例在業務拆分的基礎上,結合分庫分表和讀寫分離,如上圖:
- 業務拆分後:每個子系統需要單獨的庫。
- 如果單獨的庫太大,可以根據業務特性,進行再次分庫,比如商品分類庫,產品庫。
- 分庫後,如果表中有資料量很大的,則進行分表,一般可以按照 ID,時間等進行分表;(高階的用法是一致性 Hash)
- 在分庫、分表的基礎上,進行讀寫分離。
相關中介軟體可參考 Cobar(阿里,目前已不在維護),TDDL(阿里),Atlas(奇虎360),MyCat。
分庫分表後序列的問題,JOIN,事務的問題,會在分庫分表主題分享中介紹。
服務化
將多個子系統公用的功能/模組,進行抽取,作為公用服務使用。比如本案例的會員子系統就可以抽取為公用的服務。
訊息佇列
訊息佇列可以解決子系統/模組之間的耦合,實現非同步,高可用,高效能的系統。它是分散式系統的標準配置。
本案例中,訊息佇列主要應用在購物,配送環節:
- 使用者下單後,寫入訊息佇列,後直接返回客戶端。
- 庫存子系統:讀取訊息佇列資訊,完成減庫存。
- 配送子系統:讀取訊息佇列資訊,進行配送。
目前使用較多的 MQ 有 Active MQ、Rabbit MQ、Zero MQ、MS MQ 等,需要根據具體的業務場景進行選擇,建議可以研究下 Rabbit MQ。
其他架構(技術)
除了以上介紹的業務拆分,應用叢集,多級快取,單點登入,資料庫叢集,服務化,訊息佇列外,還有 CDN,反向代理,分散式檔案系統,大資料處理等系統。
架構彙總
大型網站的架構是根據業務需求不斷完善的,根據不同的業務特徵會做特定的設計和考慮。
本文只是講述一個常規大型網站會涉及的一些技術和手段,希望能給大家帶來啟發。