如何打造一個高可用、高性能、易擴展、可伸縮且安全的應用系統?相信這是困擾着無數開發者的難題,在這裏咱們以一個網站爲例,來討論一下如何作好大型應用系統的架構設計。前端
大型網站的技術挑戰主要來自於龐大的用戶,高併發的訪問和海量的數據。算法
大型網站都是從小型網站發展而來,小型網站最開始時沒有太多人訪問,只須要一臺服務器就綽綽有餘,這時的網站架構如圖所示。數據庫
隨着業務的發展,一臺服務器逐漸不能知足需求:愈來愈多的用戶訪問致使性能愈來愈差,愈來愈多的數據致使存儲空間不足。這時就須要將應用和數據分離。後端
應用和數據分離後整個網站使用三臺服務器:應用服務器、文件服務器和數據庫服務器,如圖所示。瀏覽器
這三臺服務器對硬件資源的要求各不相同,應用服務器須要處理大量的業務邏輯,所以須要更快更強大的 CPU;數據庫服務器須要快速磁盤檢索和數據緩存,所以須要更快的硬盤和更大的內存;文件服務器須要存儲大量用戶上傳的文件,所以須要更大的硬盤。緩存
隨着用戶逐漸增多,網站又一次面臨挑戰:數據庫壓力太大致使訪問延遲,進而影響整個網站的性能,用戶體驗受到影響。安全
網站訪問遵循二八定律:80%的業務訪問集中在 20%的數據上。既然大部分的業務訪問集中在一小部分數據上,那麼若是把這一小部分數據緩存在內存中,是否是就能夠減小數據庫的訪問壓力,提升整個網站的數據訪問速度,改善數據庫的寫入性能了呢?服務器
網站使用的緩存能夠分爲兩種:緩存在應用服務器上的本地緩存和緩存在專門的分佈式緩存服務器上的遠程緩存。本地緩存的訪問速度更快一些,可是受應用服務器內存限制,其緩存數據量有限,並且會出現和應用程序爭用內存的狀況。遠程分佈式緩存可使用集羣的方式,部署大內存的服務器做爲專門的緩存服務器,能夠在理論上作到不受內存容量限制的緩存服務,如圖所示。markdown
使用緩存後,數據訪問壓力獲得有效緩解,可是單一應用服務器可以處理的請求鏈接有限,在網站訪問高峯期,應用服務器成爲整個網站的瓶頸。網絡
使用集羣是解決高併發、海量數據問題的經常使用手段。當一臺服務器的處理能力、存儲空間不足時,不要企圖去換更強大的服務器,對大型網站而言,無論多麼強大的服務器,都知足不了網站持續增加的業務需求。這種狀況下,更恰當的作法是增長一臺服務器分擔原有服務器的訪問及存儲壓力。
只要能經過增長一臺服務器的方式改善負載壓力,就能夠以一樣的方式持續增長服務器不斷改善系統性能,從而實現系統的可伸縮性。應用服務器集羣是可伸縮集羣架構設計中較爲簡單成熟的一種,如圖所示。
經過負載均衡調度服務器,可未來自用戶瀏覽器的訪問請求分發到應用服務器集羣中的任何一臺服務器上,若是有更多的用戶,就在集羣中加入更多的應用服務器,使應用服務器的負載壓力再也不成爲整個網站的瓶頸。
網站在使用緩存後,使絕大部分數據讀操做訪問均可以不經過數據庫就能完成,可是仍有一部分讀操做和所有的寫操做須要訪問數據庫,在網站的用戶達到必定規模後,數據庫由於負載壓力太高而成爲網站的瓶頸。
目前大部分的主流數據庫都提供主從熱備功能,經過配置兩臺數據庫主從關係,能夠將一臺數據庫服務器的數據更新同步到另外一臺服務器上。網站利用數據庫的這一功能,實現數據庫讀寫分離,從而改善數據庫負載壓力,如圖所示。
應用服務器在寫數據的時候,訪問主數據庫,主數據庫經過主從複製機制將數據更新同步到從數據庫,這樣當應用服務器讀數據的時候,就能夠經過從數據庫得到數據。爲了便於應用程序訪問讀寫分離後的數據庫,一般在應用服務器端使用專門的數據訪問模塊,使數據庫讀寫分離對應用透明。
隨着業務不斷髮展,用戶規模愈來愈大,不一樣地區的用戶訪問網站時,速度差異也極大。爲了提供更好的用戶體驗,網站須要加速網站訪問速度。主要手段有使用 CDN 和反向代理,如圖所示。
CDN 和反向代理的基本原理都是緩存,區別在於 CDN 部署在網絡提供商的機房,使用戶在請求網站服務時,能夠從距離本身最近的網絡提供商機房獲取數據;而反向代理則部署在網站的中心機房,當用戶請求到達中心機房後,首先訪問的服務器是反向代理服務器,若是反向代理服務器中緩存着用戶請求的資源,就將其直接返回給用戶。
數據庫通過讀寫分離後,從一臺服務器拆分紅兩臺服務器,可是隨着網站業務的發展依然不能知足需求,這時須要使用分佈式數據庫。文件系統也是同樣,須要使用分佈式文件系統,如圖所示。
分佈式數據庫是網站數據庫拆分的最後手段,只有在單表數據規模很是龐大的時候才使用。不到不得已時,網站更經常使用的數據庫拆分手段是業務分庫,將不一樣業務的數據庫部署在不一樣的物理服務器上。
隨着網站業務愈來愈複雜,對數據存儲和檢索的需求也愈來愈複雜,網站須要採用一些非關係數據庫技術如 NoSQL 和非數據庫查詢技術如搜索引擎,如圖所示。
大型網站爲了應對日益複雜的業務場景,經過使用分而治之的手段將整個網站業務分紅不一樣的產品線。具體到技術上,**將一個網站拆分紅許多不一樣的應用,每一個應用獨立部署維護。應用之間能夠經過一個超連接創建關係(在首頁上的導航連接每一個都指向不一樣的應用地址),也能夠經過消息隊列進行數據分發,固然最多的仍是經過訪問同一個數據存儲系統來構成一個關聯的完整系
隨着業務拆分愈來愈小,存儲系統愈來愈龐大,應用系統的總體複雜度呈指數級增長,部署維護愈來愈困難。
既然每個應用系統都須要執行許多相同的業務操做,好比用戶管理、商品管理等,那麼能夠將這些共用的業務提取出來,獨立部署。由這些可複用的業務鏈接數據庫,提供共用業務服務,而應用系統只須要管理用戶界面,經過分佈式服務調用共用業務服務完成具體業務操做,如圖所示。
大型網站的架構演化到這裏,基本上大多數的技術問題都得以解決。
爲了解決應用系統面臨的高併發訪問、海量數據處理、高可靠運行等一系列問題與挑戰,大型互聯網公司在實踐中提出了許多解決方案,以實現高性能、高可用、易伸縮、可擴展、安全等各類技術架構目標。這些解決方案又被更多公司重複使用,從而逐漸造成架構模式。
分層是企業應用系統中最多見的一種架構模式,將系統在橫向維度上切分紅幾個部分,每一個部分負責一部分相對比較單一的職責,而後經過上層對下層的依賴和調用組成一個完整的系統。
在網站架構中,一般將應用系統分爲應用層、服務層、數據層,以下圖所示。
經過分層,能夠更好地將一個龐大的軟件系統切分紅不一樣的部分,便於分工合做開發和維護。各層之間具備必定的獨立性,只要維持調用接口不變,各層能夠根據具體問題獨立演化發展而不須要其餘層必須作出相應調整。
**可是分層架構也有一些挑戰,就是必須合理規劃層次邊界和接口,在開發過程當中,嚴格遵循分層架構的約束,禁止跨層調用及逆向調用。**在實踐中,大的分層結構內部還能夠繼續分層。
分層架構是邏輯上的,三層結構能夠部署在同一個物理機器上。可是隨着網站業務的發展,必然須要對已經分層的模塊分離部署,使網站擁有更多的計算資源以應對愈來愈多的用戶訪問。
分層是將軟件在橫向方面進行切分,分割則是在縱向方面對軟件進行切分。
網站越大,功能越複雜,服務和數據處理的種類也越多。將這些不一樣的功能和服務分割開來,包裝成高內聚低耦合的模塊單元,一方面有助於軟件的開發和維護;另外一方面,便於不一樣模塊的分佈式部署,提升網站的併發處理能力和功能擴展能力。
大型網站分割的粒度可能會很小。好比在應用層,將不一樣業務進行分割,例如將購物、論壇、搜索、廣告分割成不一樣的應用,由獨立的團隊負責,部署在不一樣的服務器上。
對於大型網站,分層和分割的一個主要目的是爲了切分後的模塊便於分佈式部署,即將不一樣模塊部署在不一樣的服務器上,經過遠程調用協同工做。分佈式意味着可使用更多的資源完成一樣的功能,可以處理的併發訪問和數據量也更大。
但分佈式在解決網站高併發問題的同時也帶來了其餘問題。典型的有下面幾點:
意味着服務調用必須經過網絡,這可能會對性能形成比較嚴重的影響。
服務器越多,宕機的機率也就越大,形成的服務不可用可能會致使不少應用不可訪問,使網站可用性下降。
數據在分佈式的環境中保持數據一致性很是困難,分佈式事務也難以保證。
系統依賴錯綜複雜,開發管理維護困難。
所以分佈式設計要根據具體狀況量力而行。經常使用的分佈式方案有:分佈式服務、分佈式數據庫、分佈式計算、分佈式配置、分佈式鎖和分佈式文件系統等。
使用分佈式雖然已經將分層和分割後的模塊獨立部署,可是對於用戶訪問集中的模塊,還須要將獨立部署的服務器集羣化,即多臺服務器部署相同應用構成一個集羣,經過負載均衡設備共同對外提供服務。
由於服務器集羣有更多服務器提供相同服務,所以能夠提供更好的併發性,當有更多用戶訪問的時候,只須要向集羣中加入新的機器便可。同時當某臺服務器發生故障時,負載均衡設備或者系統的失效轉移機制會將請求轉發到集羣中其餘服務器上,提升系統的可用性。
緩存就是將數據存放在距離計算最近的位置以加快處理速度。緩存是改善軟件性能的第一手段,在複雜的軟件設計中,緩存幾乎無處不在。好比常見的反向代理、Redis(未開啓持久化)、CDN 等。
使用緩存有兩個前提條件,一是數據訪問熱點不均衡,某些數據會被更頻繁的訪問,這些數據應該放在緩存中;二是數據在某個時間段內有效,不會很快過時,不然緩存的數據就會因已經失效而產生髒讀,影響結果的正確性。
緩存除了能夠加快數據訪問速度,還能夠減輕後端應用和數據存儲的負載壓力,網站數據庫幾乎都是按照有緩存的前提進行負載能力設計的。
應用系統的一個重要目標是下降耦合性。系統解耦的手段除了前面提到的分層、分割、分佈式等,還有一個重要手段是異步,業務之間的消息傳遞不是同步調用,而是將一個業務操做分紅多個階段,每一個階段之間經過共享數據的方式異步執行進行協做。
**異步架構是典型的生產者消費者模式,二者不存在直接調用,只要保持數據結構不變,彼此功能實現能夠隨意變化而不互相影響,這對網站擴展新功能很是便利。**除此以外,使用異步消息隊列還有以下優勢:
**提升系統可用性。**消費者服務器發生故障,數據會在消息隊列服務器中存儲堆積,生產者服務器能夠繼續處理業務請求,系統總體表現無端障。消費者服務器恢復正常後,繼續處理消息隊列中的數據。
**加快網站響應速度。**處在業務處理前端的生產者服務器在處理完業務請求後,將數據寫入消息隊列,不須要等待消費者服務器處理就能夠返回,響應延遲減小。
**消除併發訪問高峯。**用戶訪問網站是隨機的,存在訪問高峯和低谷。使用消息隊列將忽然增長的訪問請求數據放入消息隊列中,等待消費者服務器依次處理,就不會對整個網站負載形成太大壓力。
但須要注意的是,使用異步方式處理業務可能會對用戶體驗、業務流程形成影響,須要網站產品設計方面的支持。
網站須要 7×24 小時連續運行,可是服務器隨時可能出現故障,特別是服務器規模比較大時,出現某臺服務器宕機是必然事件。要想保證在服務器宕機的狀況下網站依然能夠繼續服務,不丟失數據,就須要必定程度的服務器冗餘運行,數據冗餘備份,這樣當某臺服務器宕機時,能夠將其上的服務和數據訪問轉移到其餘機器上。
訪問和負載很小的服務也必須部署至少兩臺服務器構成一個集羣,其目的就是經過冗餘實現服務高可用。數據庫除了按期存檔進行冷備份外,還須要對數據庫進行主從分離,實時同步實現熱備份。
目前應用系統的自動化架構設計主要集中在發佈運維方面。包括自動化發佈、自動化代碼管理、自動化測試、自動化安全監測、自動化部署、自動化監控、自動化告警、自動化失效轉移與恢復、自動化降級和自動化分配資源等。
系統在安全架構方面也積累了許多模式:經過密碼和手機校驗碼進行身份認證;登陸、交易等操做須要對網絡通訊進行加密,網站服務器上存儲的敏感數據如用戶信息等也進行加密處理;爲了防止機器人程序濫用網絡資源攻擊網站,網站使用驗證碼進行識別;對於常見的用於攻擊網站的 XSS 攻擊、SQL 注入、進行編碼轉換等相應處理;對於垃圾信息、敏感信息進行過濾;對交易轉帳等重要操做根據交易模式和交易信息進行風險控制。
關於什麼是架構,維基百科是這樣定義的:「有關軟件總體結構與組件的抽象描述,用於指導大型軟件系統各個方面的設計」。
通常說來,除了功能需求外,軟件架構還須要關注性能、可用性、伸縮性、擴展性和安全性這 5 個要素。
性能是網站的一個重要指標,任何軟件架構設計方案都必須考慮可能會帶來的性能問題。也正是由於性能問題幾乎無處不在,因此優化網站性能的手段也很是多,主要的方式能夠總結以下:
瀏覽器:瀏覽器緩存、使用頁面壓縮、合理佈局頁面、減小 Cookie 傳輸等
CDN 和反向代理
本地緩存和分佈式緩存
異步消息隊列
應用層:服務器集羣
代碼層:多線程、改善內存管理等
數據層:索引、緩存、SQL 優化等,以及合理使用 NoSQL 數據庫
網站高可用的主要手段是冗餘,應用部署在多臺服務器上同時提供訪問,數據存儲在多臺服務器上互相備份,任何一臺服務器宕機都不會影響應用的總體可用,也不會致使數據丟失。
對於應用服務器而言,多臺應用服務器經過負載均衡設備組成一個集羣共同對外提供服務,任何一臺服務器宕機,只需把請求切換到其餘服務器便可,可是一個前提條件是應用服務器上不能保存請求的會話信息。
對於存儲服務器,須要對數據進行實時備份,當服務器宕機時須要將數據訪問轉移到可用的服務器上,並進行數據恢復以保證繼續有服務器宕機的時候數據依然可用。
除了運行環境,網站的高可用還須要軟件開發過程的質量保證。經過預發佈驗證、自動化測試、自動化發佈、灰度發佈等手段,減小將故障引入線上環境的可能。
衡量架構伸縮性的主要標準有:是否能夠用多臺服務器構建集羣,是否容易向集羣中添加新的服務器,加入新的服務器後是否能夠提供和原來的服務器無差異的服務,集羣中可容納的總的服務器數量是否有限制。
對於應用服務器集羣,經過使用合適的負載均衡設備就能夠向集羣中不斷加入服務器。對於緩存服務器集羣,須要使用高效的緩存路由算法,避免加入新服務器致使路由大面積失效。關係數據庫很難作到大規模集羣的可伸縮性,所以關係數據庫的集羣伸縮性方案必須在數據庫以外實現,經過路由分區等手段將部署有多個數據庫的服務器組成一個集羣。至於大部分 NoSQL 數據庫產品,因爲其先天就是爲海量數據而生,所以其對伸縮性的支持一般都很是好。
衡量架構擴展性的主要標準就是不一樣產品之間是否不多耦合。在網站增長新的業務產品時,是否能夠實現對現有產品透明無影響,不須要任何改動或者不多改動既有業務功能就能夠上線新產品。
網站可伸縮架構的主要手段是事件驅動架構和分佈式服務。
事件驅動架構在網站一般利用消息隊列實現,將用戶請求和其餘業務事件構形成消息發佈到消息隊列,消息的處理者做爲消費者從消息隊列中獲取消息進行處理。經過這種方式將消息產生和消息處理分離開來,能夠透明地增長新的消息生產者任務或者新的消息消費者任務。
分佈式服務則是將業務和可複用服務分離開來,經過分佈式服務框架調用。新增產品能夠經過調用可複用的服務實現自身的業務邏輯,而對現有產品沒有任何影響。可複用服務升級變動的時候,也能夠經過提供多版本服務對應用實現透明升級,不須要強制應用同步變動。
網站的安全架構就是保護網站不受惡意訪問和攻擊,保護網站的重要數據不被竊取。衡量網站安全架構的標準就是針對現存和潛在的各類攻擊與竊密手段,是否有可靠的應對策略。