應用架構經過不同階段,逐漸由單一發展至分布式,由功能化發展至服務化,主要的幾類架構如下:
單一應用架構(ORM)-> 垂直應用架構(MVC)-> ?分布式服務架構(RPC)-> 流動計算架構(SOA)
以電商系統為例,按演變階段介紹各個應用架構。該系統功能:用戶模塊、商品模塊以及交易模塊。
Phase 1:單機構建網站
單機構建網站,是一個高內聚版本,所有功能部署在一起。通過一個容器和JSP/Servlet技術或通過一些開源的框架如SSM以及SSH,通過數據庫管理系統來存儲數據。
單機下的系統結構如下:
優點:
1. 成本比較低,適合功能少又簡單的應用場景。
缺點:
1. 無法適應高流量
2. 部署成本高
Phase 2:?數據庫應用服務器分離
隨著訪問量上升,服務器的負載也隨之逐漸提高,相較于單機系統的無法適應高流量,提升網站的負載能力成為了首要課題。若代碼層面難以優化,通過增加機器的數量是提升整體性能一個方式。
優點:
1. 提高系統的負載能力
2. 較高的性價比
通過增加機器的數量,將數據庫服務器和web服務器拆分開來。
優點:
1. 提高單機的負載能力
2. 提高單機的容災能力
此架構下的系統結構:
Phase 3:分布式服務器
雖然我們已經將服務和存儲分離,但隨著訪問量繼續增加,單臺應用服務器也無法滿足需求。在假設數據庫服務器沒有壓力的情況下,此時通過將服務器部署至更多的機器,即應用服務器從一臺變成多臺,把用戶的請求分散到不同的服務器中進響應,進而提高負載能力。
而服務器之間不存在直接交互,所有的服務器都是依賴數據庫各自對外提供服務。此架構下系統結構如下:
此階段有4個問題隨之而來:
1. 負載均衡的問題?
通常有以下幾種解決方案:
1.1?HTTP重定向
即應用層的請求轉發。當用戶的請求到了HTTP重定向負載均衡服務器,服務器根據算法要求用戶重定向,用戶收到重定向請求后,再次請求真正的集群。
優點:簡單易用
缺點:性能較差?
1.2?DNS域名解析負載均衡
即在用戶請求DNS服務器,獲取域名對應的IP地址時,DNS服務器直接給出負載均衡后的服務器IP。
優點:交給DNS處理,無需人為維護負載均衡服務器
缺點:
1. 當一個應用服務器出現問題,無法及時通知DNS
2. DNS負載均衡的控制權在域名服務商,不利于管理
1.3?反向代理服務器
在用戶的請求到達反向代理服務器時,由反向代理服務器根據算法轉發到具體的服務器。
優點:部署簡單
缺點:代理服務器可能成為性能瓶頸,針對大文件
1.4?IP層負載均衡
在請求到達負載均衡器后,負載均衡器通過修改請求的目的IP地址,從而實現請求的轉發,做到負載均衡。
優點:性能更好
缺點:負載均衡器的寬帶成為瓶頸
1.5?數據鏈路層負載均衡
在請求到達負載均衡器后,負載均衡器通過修改請求的MAC地址,從而做到負載均衡,與IP負載均衡不一樣的是,當請求訪問完服務器之后,直接返回客戶。而無需再經過負載均衡器。
2. 調度的算法和策略?
常用的集群調度算法如下:
2.1?rr輪詢調度算法
輪詢分發請求。
優點:容易實現
缺點:未考慮每臺服務器的處理能力
2.2?wrr加權調度算法
為每個服務器設置權值Weight,負載均衡調度器根據權值調度服務器,服務器被調用的次數跟權值成正比。
優點:考慮不同服務器處理能力不同
2.3?sh原地址散列算法
提取用戶IP,根據散列函數得出一個key,再根據靜態映射表,查處對應的value,即目標服務器IP。過目標機器超負荷,則返回空。
優點:實現同一個用戶訪問同一個服務器
2.4?lc最少連接算法
優先把請求轉發給連接數少的服務器。
優點:使集群中各個服務器的負載更加均勻
2.5?dh目標地址散列算法
原理同上,只是現在提取的是目標地址的IP來做哈希。
優點:實現同一個用戶訪問同一個服務器
2.6?wlc加權最少連接算法
在lc的基礎上,為每臺服務器加上權值。算法為:(活動連接數 * 256 + 非活動連接數) ÷ 權重,計算出來的值小的服務器優先被選擇。
優點:根據服務器的能力分配請求
2.7 sed最短期望延遲算法
其實sed跟wlc類似,區別是不考慮非活動連接數。算法為:(活動連接數 +1 ) * 256 ÷ 權重,同樣計算出來的值小的服務器優先被選擇。
2.8?nq永不排隊算法
改進的sed算法。我們想一下什么情況下才能“永不排隊”,那就是服務器的連接數為0的時候,那么假如有服務器連接數為0,均衡器直接把請求轉發給它,無需經過sed的計算。
3. 集群請求返回模式問題?
3.1?NAT
負載均衡器接收用戶的請求,轉發給具體服務器,服務器處理請求返回給均衡器,均衡器再重新返回給用戶。
3.2?DR
負載均衡器接收用戶的請求,轉發給具體服務器,服務器處理請求后直接返回給用戶。
缺點:系統需支持IP Tunneling協議,不易跨平臺
3.3?TUN
同DR,但無需IP Tunneling協議,跨平臺性好,可以支持大部分系統都。
4. 集群Session一致性問題
用戶如果每次訪問到的服務器不一樣,那么如何維護session的一致性??
4.1?Session Sticky
即把同一個用戶在某一個會話中的請求,都分配到固定的某一臺服務器中。
優點:易于實現
缺點:應用服務器重啟則session消失
4.2?Session Replication
即在集群中復制session,使得每個服務器都保存有全部用戶的session數據。
優點:減輕負載均衡服務器的壓力
缺點:復制時網絡帶寬開銷大,若訪問量大的話session占用內存大且浪費。
4.3??Session數據集中存儲
即利用數據庫來存儲session數據,實現了session和應用服務器的解耦。
優點:相比Session Replication的方案,集群間對于寬帶和內存的壓力大幅減少
缺點:需要額外維護存儲session的數據庫
4.4?Cookie Base
即把session存在cookie中,通過瀏覽器來告知應用服務器session,同樣實現了session和應用服務器的解耦。
優點:實現簡單,基本免維護
缺點:cookie長度限制,安全性低,帶寬消耗
根據不同的場景,選擇不同解決方案來應對上述這些問題后,此時系統結構:
Phase 4 :數據庫讀寫分離化
同樣的,隨著訪問量的增加,數據庫的負載也在慢慢增大。對于這種情況,可以先考慮使用讀寫分離和主從復制的方式。
讀寫分離后的系統結構:
2個問題:
4.1 主從數據庫之間數據同步問題
使用MySQL自帶的Master + Slave的方式實現主從復制。
4.2 應用服務對數據源的選擇問題
采用第三方數據庫中間件。螞蟻金服目前采用zdal作為數據庫分庫分表中間件。
Phase 5 :?緩存緩解讀庫壓力
常用的緩存機制包括頁面級緩存、應用數據緩存和數據庫緩存。
5.1?頁面緩存
除了頁面緩存帶來的性能提升外,對于并發訪問且頁面置換頻率小的頁面,應盡量使用頁面靜態化技術。例如HTML5的localstroage或者cookie。
緩存集群的調度算法最好采用一致性哈希算,以此提高命中率。
優點:減輕數據庫的壓力, 大幅度提高訪問速度
缺點:需要維護緩存服務器,提高了編碼的復雜性
5.2??應用層和數據庫層的緩存
隨著訪問量的增加,會出現許多用戶訪問同一部分熱門內容的情況,對于這些比較熱門的內容,不需要每次都從數據庫讀取??梢酝ㄟ^緩存。例如,可以使用Google的開源緩存技術Guava或者使用Memecahed作為應用層的緩存,也可以使用Redis作為數據庫層的緩存。
加入緩存后的系統結構:
Phase 6 :數據庫水平拆分與垂直拆分
隨著數據庫的壓力繼續增加,數據庫數據量的瓶頸越來越突出,此時,可以采取數據垂直拆分和水平拆分兩種選擇。
6.1?數據垂直拆分
即根據不同的業務數據拆分到不同的數據庫中。
結合現在的例子,就是把交易、商品、用戶的數據分開。
優點:
1. 解決了原來把所有業務放在一個數據庫中的壓力問題
2. 可以根據業務的特點進行更多的優化
缺點:
1. 需要維護多個數據庫的狀態一致性和數據同步。
垂直拆分同時存在著2個問題:
6.1.1?需考慮之前跨業務的事務
解決方案:
應該在應用層盡量避免跨數據庫的分布式事務
6.1.2 跨數據庫的Join
解決方案:
通過數據庫中間件來解決。
垂直拆分后的系統結構:
6.2 數據庫水平拆分
即把同一個表中的數據拆分到兩個甚至多個數據庫中。產生數據水平拆分的原因是某個業務的數據量或者更新量到達了單個數據庫的瓶頸。
水平分庫存在3個問題:
6.2.1?SQL路由
訪問用戶信息的應用系統需要解決SQL路由的問題,因為現在用戶信息分在了兩個數據庫中,需要在進行數據操作時了解需要操作的數據在哪里。
解決方案:
通過可以解決第三方數據庫中間件,如MyCat。MyCat可以通過SQL解析模塊對SQL進行解析,再根據我們的配置,把請求轉發到具體的某個數據庫。
6.2.2 主鍵的處理發生變化
例如原來自增字段,現在不能簡單地繼續使用。
解決問題方案:
可以通過UUID保證唯一或自定義ID方案來解決。
6.2.3 不易于分頁查詢
解決問題方案:
可以通過第三方數據庫中間件,如?MyCat也提供了豐富的分頁查詢方案,比如先從每個數據庫做分頁查詢,再合并數據做一次分頁查詢等等。?
數據水平拆分后的結構如下:
Phase 7 :應用的拆分
按微服務拆分應用
隨著業務的發展,業務越來越多,應用越來越大。我們需要考慮如何避免讓應用越來越臃腫。這就需要把應用拆開,從一個應用變為倆個甚至更多。
還是以上面的例子,可以把用戶、商品、交易拆分開。變成“用戶、商品”和“用戶,交易”兩個子系統。
拆分后的結構:
產生的問題:產生相同冗余的代碼
如用戶相關的代碼,商品和交易都需要用戶信息,所以在兩個系統中都保留差不多的操作用戶信息的代碼。如何保證這些代碼可以復用是一個需要解決的問題。
解決方案:
通過服務化SOA的解決頻繁公共的服務。
7.1?SOA服務化
為了解決上面拆分應用后所出現的問題,把公共的服務拆分出來,形成一種服務化的模式,簡稱SOA。
優點:
1. 相同的代碼不會散落在不同的應用中,這些代碼實現放在各個服務中心,易于更好的維護
2. 把對數據庫的交互業務放在各個服務中心,讓前端web應用更專心與瀏覽器的交互工作
可以通過引入消息中間件來解決遠程的服務調用。
Phase 8 :引入消息中間件
系統中可能會出現不同語言開發的子模塊和部署在不同平臺的子系統。此時需要一個平臺來傳遞可靠的,與平臺和語言無關的數據,并能夠把負載均衡透明化,能在調用過程中收集并分析調用數據,推測出網站的訪問增長率等等一系列需求,對于網站應該如何成長做出預測。
開源消息中間件有阿里的Dubbo,可以搭配Google開源的分布式程序協調服務Zookeeper實現服務器的注冊與發現。
引入消息中間件后的結構: