架構設計:標準Web系統的架構分層

1、架構體系分層圖


架構設計:標準Web系統的架構分層

在上圖中我們描述了Web系統架構中的組成部分。並且給出了每一層常用的技術組件/服務實現。需要注意以下幾點:

  • 系統架構是靈活的,根據需求的不同,不一定每一層的技術都需要使用。例如:一些簡單的CRM系統可能在產品初期並不需要K-V作為緩存;一些系統訪問量不大,並且可能只有一臺業務服務器存在,所以不需要運用負載均衡層。
  • 業務系統間通信層並沒有加入傳統的HTTP請求方式。這是因為HTTP請求-響應的延遲比較高,並且有很多次和正式請求無關的通信(這在下面的內容中會詳細講到)。所以,傳統的HTTP請求方式並不適合在兩個高負載系統之間使用,其更多的應用場景是各種客戶端(WEB、IOS、Android等)->服務器端的請求調用。
  • 我們把業務編碼中常使用的緩存系統歸入到數據存儲層,是因為類似於Redis這樣的K-V存儲系統,從本質上講是一種鍵值數據庫。為什麼Redis會很快以至於可以作為緩存使用,我將在隨後的文章中進行詳細的描述。
  • 還有一點需要注意的是,上面架構圖中的每層之間實際上不存在絕對的聯繫(例如負載層一定會把請求轉送的業務層,這樣的必然性是不存在的),在通常情況下各層是可以跨越訪問的。舉例說明:如果HTTP訪問的是一張圖片資源,負載層不會把請求送到業務層,而是直接到部署的分佈式文件系統上尋找圖片資源並返回。再比如運用LVS做Mysql負載時,負載層是直接和數據存儲層進行合作。

2、負載分配層

實際上負載均衡的概念很廣泛,所述的過程是將來源於外部的處理壓力通過某種規律/手段分攤到內部各個處理節點上。在日常生活中我們隨時隨地在和負載技術打交道,例如:上下班高峰期的車流量引導、民航空管局的航空流量管制、銀行櫃檯的叫號系統。

這裡我們所說的負載分配層,是單指利用軟件實現的計算機系統上的狹義負載均衡。一個大型(日PV一億+)、中型(日PV一千萬+)Web業務系統,是不可能只有一個業務處理服務,而是多臺服務器同時進行某一個相同業務的服務。所以我們需要根據業務形態設計一種架構方式,將來自外部客戶端的業務請求分擔到每一個可用的業務節點上。如下圖所示:


架構設計:標準Web系統的架構分層


負載層還有一個作用,是根據用戶的請求規則,將不同的請求類型分派到不同的服務器上。例如:如果某一個HTTP請求是請求一張圖片,那麼負載層會直接到圖片存儲介質上尋找相應的圖片;如果某一個HTTP請求是提交的一張訂單,那麼負載層會根據規則將這張訂單提交發送到指定的“訂單服務”節點上。

不同的業務需求,使用的負載層方案也是不同的,這就考驗架構師的方案選擇能力。例如Nginx只能處理TCP/IP協議的之上應用層HTTP協議,如果要處理TCP/IP協議,則要按照第三方的TCP-Proxy-Module模。更好的直接在TCP/IP層負載的方案,是使用HAProxy。

常用的負載層架構方式包括:

- 獨立的Nginx負載或HAProxy方案

- LVS(DR)+ Nginx方案

- DNS輪詢 + LVS + Nginx方案

- 智能DNS(DNS路由) + LVS + Nginx方案

隨後的文章中將詳細介紹這些負載架構方案以及這些方案的變形。

3、業務服務層和通信層

3.1、概述

通俗來講就是我們的核心業務層,訂單業務、施工管理業務、診療業務、付款業務、日誌業務等等。如下圖所示:


架構設計:標準Web系統的架構分層


很明顯在中大型系統中,這些業務不可能是獨立存在的,一般的設計要求都會涉及到子系統間脫耦:即X1系統除了知曉底層支撐系統的存在外(例如用戶權限系統),X1系統不需要知道和它邏輯對等的X2系統的存在就可以工作。這種情況下要完成一個較複雜業務,子系統間調用又是必不可少的:例如A業務在處理成功後,會調用B業務進行執行;A業務在處理失敗後,會調用C業務進行執行;又或者A業務和D業務在某種情況下是不可分割的整體,只有同時成功才成功,其中有一個失敗整個大的業務過程都失敗。如下圖所示:


架構設計:標準Web系統的架構分層


這樣一來業務間的通信層又是一個逃不開的話題。 在隨後的文章中,我們將以Alibaba的Dubbo框架、基於AMQP協議的消息隊列和Kafka消息隊列技術的原理和使用方式,來講解業務通信層技術,特別是業務通信層的技術選型注意事項。


架構設計:標準Web系統的架構分層


3.2、不得不提的HTTP請求方式

有的讀者可能會問,為什麼業務系統間通信層沒有提到HTTP這樣的調用方式。畢竟很多公司目前都採用這種方式作為業務系統間的調用方式。我們首先通過一個圖來看看HTTP方式的調用過程。(注意,此過程不考慮http客戶端緩存的過程也不考慮DNS域名解析的過程,從HTTP建立可靠的TCP連接開始):


架構設計:標準Web系統的架構分層


從上圖中我們可以看出以下幾個問題:

  • 從技術原理層面看,HTTP請求是在需要進行調用時建立TCP連接,並且發送並等待數據回送,在得到請求結果後,可能需要再關閉這個TCP連接。這樣的原理使得很多時間浪費在和業務無關的技術特性上。
  • 另外,發送Head信息和接收Head這樣的數據,對業務數據來說是毫無意義的。在訪問量較小的情況下,這樣的過程都還是可以接收的,但是當帶寬資源吃緊的情況下,這樣的數據空間就是彌足珍貴的。
  • 獨立的HTTP請求由於沒有SOA結構中的“治理中心”的概念,所以單純的HTTP請求很難保證負責業務聯動中的上下文一致性。當然你可以自行編碼來保證,但那樣真的合理嗎?
  • 最後,需要說明的是,現在類似Apache HTTP Components這樣的組件提供了HTTP Pool來減少TCP連接時長,但這僅僅是優化了HTTP作為業務間通信時的一個問題,其他的問題依然存在。
基於以上的描述,本文並不推薦使用HTTP作為業務間通信/調用的方式,而建議HTTP方式僅限於WEB、iOS、Android等這樣的客戶端請求服務的方式。

4、數據存儲層

數據存儲將是這個系列文章中將要介紹的另一個重點。進行業務計算前的初始數據、計算過程中的臨時數據、計算完成後得到的計算結果都需要進行存儲。我們通過一張思維導圖首先從幾個維度闡述一下數據存儲的基本分類。

架構設計:標準Web系統的架構分層


4.1、文件存儲原理

我們通過一個最基本的在Centos6.5系統上創建Ext4文件系統的過程,講解文件系統的最基本原理。

  • 首先我們會通過fdisk命令對本地硬盤進行分區(即確定可控制的扇區的範圍),如下圖所示:


架構設計:標準Web系統的架構分層


  • 然後我們會在這個區上面通過mkfs命令創建我們想要的文件系統(Ext3、Ext4、LVM、XF、BTRFS等),如下圖所示:


架構設計:標準Web系統的架構分層


  • 最後我們掛載這個文件系統到指定的路徑,如下圖所示:


架構設計:標準Web系統的架構分層


  • 通過df命令查看掛載信息,如下圖所示:
架構設計:標準Web系統的架構分層


  • 萬變不離其宗的創建過程告訴我們一個什麼事實呢?


架構設計:標準Web系統的架構分層


  • 物理塊,一個物理塊是我們上層文件系統能夠操作的最小單位(通常為512字節),一個物理塊在底層對應了多個物理扇區。通常一塊SATA硬盤會有若干機械手臂(決定於物理盤片數量),和若干個物理扇區(物理扇區的大小是磁盤出廠時就確定的,我們無法改變)。
  • 單個扇區的工作是單向的,那麼映射出來的一個物理塊的工作方式也是單向的。原理就是機械手臂在讀取這個扇區的數據時,硬件芯片是不允許機械手臂同時向這個扇區寫入數據的。
  • 通過上層文件系統(EXT、NTFS、BTRFS、XF)對下層物理塊的封裝,OS是不需要直接操作磁盤物理塊的,操作者通過ls這樣的命令看到的一個一個文件也不需要關心這些文件在物理塊的存儲格式。這就是為什麼不同的文件系統有不同的特性(有的文件系統支持快照,有的文件系統支持數據恢復),基本原理就是這些文件系統對下層物理塊的操作規範不一樣。

4.2、塊存儲和文件存儲

上一小節我們敘述了最簡單、最原始的物理塊和文件格式規範的工作方式,但是隨著服務器端不斷擴大的數據存儲容量的需求和數據安全性的需求,很顯然單機的存儲是沒辦法滿足要求的,目前存儲環境兩種大的需求類型是:

  • 穩定的擴展存儲容量,並且不破壞目前已存儲的數據信息,不影響整個存儲系統的穩定性。
  • 文件共享,讓多臺服務器能夠共享存儲數據,並且都可以對文件系統進行讀寫操作。

要解決這兩個問題,我們首先要將問題擴展到上一小節的圖例中,如下圖所示:

架構設計:標準Web系統的架構分層


很明顯圖中兩個問題的答案是肯定的,也就是我們將要介紹的塊存儲系統要解決的問題。

4.2.1、塊存儲系統

我們先來聊一下塊存儲。之前我們提到的最簡單的情況就是磁盤在本地物理機上,傳輸的物理塊I/O命令,也是通過本地物理機主板上的南橋進行的。但是為了擴展更大的磁盤空間,並且保證數據吞吐量,我們需要將磁盤介質和本地物理機分離,並且讓物理塊的I/O命令在網絡上進行傳輸:

架構設計:標準Web系統的架構分層


  • 雖然磁盤介質和本地物理機發生了分離,但是直接傳輸塊I/O命令的本質是沒有改變的。本地南橋傳輸I/O命令變成了光纖傳輸,只在本物理機內部傳輸I/O命令變成了網絡傳輸,並且I/O命令通過某種通信協議進行了規範(例如FC、SCSI等)。
  • 文件系統的映射卻是在本地進行,而非遠程的文件系統映射。上文中我們已經提到,由於塊操作的順序性(在一個扇區進行寫入的時候,是不會進行這個扇區的讀取操作的),且塊操作屬於底層物理操作無法向上層的文件邏輯層主動反饋變化。所以多個物理主機是無法通過這個技術進行文件共享的。
  • 塊存儲系統要解決的是大物理存儲空間、高數據吞吐量、強穩定性的共存問題。作為上層使用這個文件系統的服務器來說,它非常清楚,除了它以外沒有其他的服務器能夠對專屬於它的這些物理塊進行讀寫操作了。也就是說它認為這個龐大容量的文件存儲空間只是它本地物理機上的存儲空間。
  • 當然隨著技術的發展,現在已經有一些技術可以只用TCP/IP協議對標準的SCSI命令進行傳輸,以便減小這個塊存儲系統的建設成本(例如iSCSI技術)。但是這種折中方式也是以減弱整個系統的數據吞吐量為代價的。不同的業務需求可以根據實際情況進行技術選型。

4.2.2、文件存儲系統

那麼如果是將文件系統從本地物理機通過網絡移植到遠程呢?當然可以,典型的文件存儲系統包括了FTP、NFS、DAS:

架構設計:標準Web系統的架構分層


  • 文件存儲系統的關鍵在於,文件系統並不在本機。而是通過網絡訪問存在於遠程的文件系統,再由遠程的文件系統操作塊I/O命令完成數據操作。
  • 一般來說諸如本地文件系統NTFS/EXT/LVM/XF等是不允許直接網絡訪問的,所以一般文件存儲系統會進行一層網絡協議封裝,這就是NFS協議/FTP協議/NAS協議(注意我們說的是協議),再由協議操作文件存儲系統的服務器文件系統。
  • 文件存儲系統要解決的問題首要的文件共享,網絡文件協議可以保證多臺客戶端共享服務器上的文件結構。從整個架構圖上可以看到文件存儲系統的數據讀寫速度、數據吞吐量是沒辦法和塊存儲系統相比的(因為這不是文件存儲系統要解決的首要問題)。
從上面的簡介中我們可以清楚的知曉,當面對大量的數據讀寫壓力的時候,文件存儲系統肯定不是我們的首要選擇,而當我們需要選擇塊存儲系統時又面臨成本和運維的雙重壓力(SAN系統的搭建是比較複雜的,並且設備費用昂貴)。並且在實際生產環境中我們經常遇到數據讀取壓力大,且需要共享文件信息的場景。那麼這個問題怎麼解決呢?

4.3、對象存儲系統

兼具塊存儲系統的高吞吐量、高穩定性和文件存儲的網絡共享性、廉價性的對象存儲就是為了滿足這樣的需求出現的。典型的對象存儲系統包括:MFS、Swift、Ceph、Ozone等。下面我們簡單介紹一下對象存儲系統的特點,在後面的文章中,我們將選擇一款對象存儲系統進行詳細說明。

對象存儲系統一定是分佈式文件系統。但分佈式文件系統不一定是對象存儲系統


架構設計:標準Web系統的架構分層


  • 我們知道文件信息是由若干屬性進行描述的,包括文件名、存儲位置、文件大小、當前狀態、副本數量等信息。我們將這些屬性抽離出來,專門使用服務器進行存儲(元數據服務器)。這樣一來文件操作的客戶端要訪問某一個文件,首先會詢問元數據節點這個文件的基本信息。
  • 由於是分佈式系統,那麼數據一致性、資源爭奪、節點異常問題都需要進行統一的協調。所以對象存儲系統中一般會有監控/協調節點。不同的對象存儲系統,支持的元數據節點和監控/協調節點的數量是不一致的。但總的趨勢都是“去中心化”。
  • OSD節點(基於對象的存儲設備)用於存儲文件內容信息。這裡要注意,雖然OSD節點的底層和塊存儲底層一樣都是依靠塊I/O進行操作的,但是上層構造兩者完全不同:OSD節點並非向塊存儲設備那樣,通過塊操作命令跳過本地文件系統直接進行物理塊操作。
  • 隨後的文章中我們將選擇一款流行的對象存儲系統,詳細剖析對象存儲系統,並且對分佈式存儲系統中三個核心概念和取捨進行說明(CAP):一致性、擴展性和容錯性。

4.3、數據庫存儲

這篇文章已經寫了很多存儲層的概要描述了,所以我們熟悉或者不熟悉的數據庫存儲技術的概述就不在這裡介紹了。

後續的文章我將使用Mysql講解幾個常用的架構方案和性能優化點,當然也會講到Mysql中,諸如Innodb這樣的核心數據引擎的工作方式。這些架構方案主要解決的是Mysql的單機I/O瓶頸、機房內數據容災、數據庫穩定性、跨機房數據容災等核心問題。

後續的文章我還會選取目前流行的數據緩存系統,講解其工作原理、核心算法和架構方案。以便讀者們根據自己的業務情況設計符合業務的存儲集群。當然還有非關係型數據庫Cassandra、HBase、MongoDB的深入介紹。

5、評價架構的特性

我們如何來評價一個服務系統的頂層設計是否優秀呢?拋開八股文式的擴展性、穩定性、健壯性、安全性這樣的套話不說。我從實際工作中為大家總結了一下幾個評價要點。

5.1、建設成本

任何系統架構在進行生產環境實施的時候,都是需要付出建設成本的。顯然各個公司/組織對成本的承受度是不一樣的(這些成本包括:設計成本、資產採購成本、運維成本、第三方服務成本),所以如何利用有限的成本建設出符合業務需求、適應訪問規模的系統,就是一個複雜的問題。另外,這種要求下架構師是不能進行過度設計的。

5.2、擴展/規劃水平

根據業務的發展,整個系統是需要進行升級的(這包括已有模塊的功能升級、合併已有的模塊、加入新的業務模塊或者在模塊功能不變的情況下提高數據吞吐量)。那麼如何儘量不影響原業務的工作,以最快的速度、最小的工作量來進行系統的橫向、縱向擴展,也就是一個複雜的問題了。好的系統架構是可以在用戶無任何感覺的情況下進行升級的,或者只需要在某些關鍵子系統升級時才需要短暫的停止服務。

5.3、抗攻擊水平

對系統的攻擊肯定是瞄準整個系統最薄弱的環節進行的,攻擊可能來自於外部(例如Dos/DDos攻擊)也可能來自於內部(口令入侵)。好架構的系統不是“絕對不能攻破”的系統,而是“預防很好”的系統。所謂預防,就是預防可能的攻擊,分階段對可能遇到的各種攻擊進行模擬;所謂隱藏,就是利用各種手段對整個系統的關鍵信息進行涉密管理,ROOT權限、物理位置、防火牆參數、用戶身份。

5.3、容災恢復等級

好的架構應該考慮不同等級的容災。集群容災,在集群中某一個服務節點崩潰的情況下,集群中另外一臺主機能夠接替馬上接替他的工作,並且故障節點能夠脫離;分佈式容災:分佈式系統一般會假設整個系統中隨時都在發生單點故障/多點故障,當產生單點故障/多點故障時,整個分佈式系統都還可以正常對外提供服務,並且分佈式系統中的單點故障/多點故障區可以通過自動/人工的方式進行恢復,分佈式系統會重新接納它們;異地容災(機房等級容災):在機房產生物理災難的情況下(物理網絡斷裂、戰爭摧毀、地震等),在某個相隔較遠的異地,備份系統能夠發現這樣的災難發生,並主動接過系統運行權,通知系統運維人員(根據系統不同的運行要求,可能還有多個備份系統)。異地容災最大的挑戰性是如何保證異地數據的完整性。

5.4、業務適應性水平

系統架構歸根結底還是為業務服務的,系統架構的設計選型一定是以服務當前的業務為前提。在上文中提到的業務通信層中,選擇SOA組件還是消息隊列組件,又或者選擇什麼樣的消息隊列,就是一個很好的業務驅動事件。例如,A業務是一種WEB前端服務,需要及時反饋給客戶操作結果,B業務的服務壓力又非常大。A業務在調用B業務時,B業務無法在毫秒級的時間內返回給A業務調用結果。這種業務場景下可以使用AMQP類型的消息隊列服務。另外說明兩點,目前行業內有很多為解決相同業務場景存在的不同方案,架構師在進行方案選型的過程中,一定要對各種解決方案的特點足夠掌握,這樣才能做出正確的選擇;另外行業內的解決方案已經足夠多,架構師在業務沒有特殊要求的情況下一定不要做“ 重複發明輪子”的事情。

5.5、維護難易程度

一套服務系統從架設之初就需要運維團隊不斷的進行投入。顯然根據系統的複雜程度和物理機器的數量,運維團隊的知識複雜性也是不一樣的。在架構師進行頂層架構設計時,必須還要考慮系統的運維難度和運維成本。

6、其他說明

  • 負載層、業務層、業務通信層、數據存儲層的詳細架構方案在後續文章中我們會用若干文章進行深入講解,包括核心算法、架設原理、架設案例。隨後的文章中我們將首先介紹系統負載層。
  • 在很多系統中我們還涉及存儲的數據進行分析,形成數據分析結果。這涉及到數據分析層的架構知識。Hadoop生態系統是目前行業公認的高效率、高穩定性、高擴展性的數據分析生態系統。這個系列的博文暫時不會介紹數據分析層的架構設計和開發知識,後續將會獨立成文。


如果您覺得不錯,請別忘了轉發、分享、點贊讓更多的人去學習, 您的舉手之勞,就是對小編最好的支持,非常感謝!


分享到:


相關文章: