一、大型網站系統的特點
高並發,大流量
需要面對高並發用戶,大流量訪問。Google 日均 PV 35 億,日 IP 訪問數 3 億;騰訊 QQ 的最大在線用戶數 1.4 億(2011年數據)。
高可用
系統 7 x 24 小時不間斷服務。
海量數據
需要存儲、管理海量數據,需要使用大量服務器。Facebook 每周上傳的照片數量接近 10 億,百度收錄的網頁數目有數百億,Google 有近百萬台服務器為全球用戶提供服務。
用戶分布廣泛,網絡情況復雜
許多大型互聯網站都是為全球用戶提供服務的,用戶分布范圍廣,各地網絡情況千差萬別。在國內,還有各個運營商網絡互通難的問題。
安全環境惡劣
由於互聯網的開放性,使得互聯網站更容易受到攻擊,大型網站幾乎每天都會被黑客攻擊。
需求快速變更,發布頻繁
和傳統軟件的版本發布頻率不同,互聯網產品為快速適應市場,滿足用戶需求,其產品發布頻率極高。一般大型網站的產品每周都有新版本發布上線,中小型網站的發布更頻繁,有時候一天會發布幾十次。
漸進式發展
幾乎所有的大型互聯網網站都是從一個小網站開始,漸進地發展起來的。Facebook 是扎克伯格同學在哈佛大學的
宿舍里開發的;Google 的第一台服務器部署在斯坦福大學的實驗室;阿里巴巴是在馬雲家的客廳誕生的。好的互
聯網產品都是慢慢運營出來的,不是一開始就開發好的,這也正好與網站架構的發展演化過程對應。
二、大型網站架構演化發展歷程
大型網站的技術挑戰主要來自於龐大的用戶,高並發的訪問和海量的數據,任何簡單的業務一旦需要處理數以 P 計的數據和面對數以億計的用戶,問題就會變得很棘手。大型網站架構主要解決這類問題。
初始階段的網站架構
大型網站都是從小型網站發展而來,網站架構也是一樣,是從小型網站架構逐步演化而來。小型網站最開始沒有太多人訪問,只需要一台服務器就綽綽有余,這時的網站架構如下圖所示:
應用程序、數據庫、文件等所有資源都在一台服務器上。
應用服務和數據服務分離
隨着網站業務的發展,一台服務器逐漸不能滿足需求:越來越多的用戶訪問導致性能越來越差,越來越多的數據導致存儲空間不足。這時就需要將應用和數據分離。應用和數據分離后整個網站使用3台服務器:應用服務器、文件服務器和數據庫服務器。這 3 台服務器對硬件資源的要求各不相同:
應用服務器需要處理大量的業務邏輯,因此需要更快更強大的CPU;
數據庫服務器需要快速磁盤檢索和數據緩存,因此需要更快的磁盤和更大的內存;
文件服務器需要存儲大量用戶上傳的文件,因此需要更大的硬盤。
此時,網站系統的架構如下圖所示:
應用和數據分離后,不同特性的服務器承擔不同的服務角色,網站的並發處理能力和數據存儲空間得到了很大改善,支持網站業務進一步發展。但是隨着用戶逐漸增多,網站又一次面臨挑戰:數據庫壓力太大導致訪問延遲,進而影響整個網站的性能,用戶體驗受到影響。這時需要對網站架構進一步優化。
使用緩存改善網站性能
網站訪問的特點和現實世界的財富分配一樣遵循二八定律:80% 的業務訪問集中在20% 的數據上。既然大部分業務訪問集中在一小部分數據上,那么如果把這一小部分數據緩存在內存中,就可以減少數據庫的訪問壓力,提高整個網站的數據訪問速度,改善數據庫的寫入性能了。 網站使用的緩存可以分為兩種:緩存在應用服務器上的本地緩存和緩存在專門的分布式緩存服務器上的遠程緩存。
本地緩存的訪問速度更快一些,但是受應用服務器內存限制,其緩存數據量有限,而且會出現和應用程序爭用內存的情況。
遠程分布式緩存可以使用集群的方式,部署大內存的服務器作為專門的緩存服務器,可以在理論上做到不受內存容量限制的緩存服務。
使用緩存后,數據訪問壓力得到有效緩解,但是單一應用服務器能夠處理的請求連接有限,在網站訪問高峰期,應用服務器成為整個網站的瓶頸。
使用應用服務器集群改善網站的並發處理能力
使用集群是網站解決高並發、海量數據問題的常用手段。當一台服務器的處理能力、存儲空間不足時,不要企圖去更換更強大的服務器,對大型網站而言,不管多么強大的服務器,都滿足不了網站持續增長的業務需求。這種情況下,更恰當的做法是增加一台服務器分擔原有服務器的訪問及存儲壓力。 對網站架構而言,只要能通過增加一台服務器的方式改善負載壓力,就可以以同樣的方式持續增加服務器不斷改善系統性能,從而實現系統的可伸縮性。應用服務器實現集群是網站可伸縮架構設計中較為簡單成熟的一種,如下圖所示:
通過負載均衡調度服務器,可以將來自用戶瀏覽器的訪問請求分發到應用服務器集群中的任何一台服務器上,如果有更多用戶,就在集群中加入更多的應用服務器,使應用服務器的壓力不再成為整個網站的瓶頸。
數據庫讀寫分離
網站在使用緩存后,使對大部分數據讀操作訪問都可以不通過數據庫就能完成,但是仍有一部分讀操作(緩存訪問不命中、緩存過期)和全部的寫操作都需要訪問數據庫,在網站的用戶達到一定規模后,數據庫因為負載壓力過高而成為網站的瓶頸。 目前大部分的主流數據庫都提供主從熱備功能,通過配置兩台數據庫主從關系,可以將一台數據庫服務器的數據更新同步到另一台服務器上。網站利用數據庫的這一功能,實現數據庫讀寫分離,從而改善數據庫負載壓力。如下圖所示:
應用服務器在寫數據的時候,訪問主數據庫,主數據庫通過主從復制機制將數據更新同步到從數據庫,這樣當應用服務器讀數據的時候,就可以通過從數據庫獲得數據。為了便於應用程序訪問讀寫分離后的數據庫,通常在應用服務器端使用專門的數據訪問模塊,使數據庫讀寫分離對應用透明。
使用反向代理和 CDN 加速網站響應
隨着網站業務不斷發展,用戶規模越來越大,由於中國復雜的網絡環境,不同地區的用戶訪問網站時,速度差別也極大。有研究表明,網站訪問延遲和用戶流失率正相關,網站訪問越慢,用戶越容易失去耐心而離開。為了提供更好的用戶體驗,留住用戶,網站需要加速網站訪問速度。主要手段有使用 CDN 和方向代理。如下圖所示:
CDN 和反向代理的基本原理都是緩存。
CDN 部署在網絡提供商的機房,使用戶在請求網站服務時,可以從距離自己最近的網絡提供商機房獲取數據反向代理則部署在網站的中心機房,當用戶請求到達中心機房后,首先訪問的服務器是反向代理服務器,如果反向代理服務器中緩存着用戶請求的資源,就將其直接返回給用戶
使用 CDN 和反向代理的目的都是盡早返回數據給用戶,一方面加快用戶訪問速度,另一方面也減輕后端服務器的負載壓力。
使用分布式文件系統和分布式數據庫系統
任何強大的單一服務器都滿足不了大型網站持續增長的業務需求。數據庫經過讀寫分離后,從一台服務器拆分成兩台服務器,但是隨着網站業務的發展依然不能滿足需求,這時需要使用分布式數據庫。文件系統也一樣,需要使用分布式文件系統。如下圖所示:
分布式數據庫是網站數據庫拆分的最后手段,只有在單表數據規模非常龐大的時候才使用。不到不得已時,網站更常用的數據庫拆分手段是業務分庫,將不同業務的數據部署在不同的物理服務器上。
使用 NoSQL 和搜索引擎
隨着網站業務越來越復雜,對數據存儲和檢索的需求也越來越復雜,網站需要采用一些非關系數據庫技術如NoSQL 和非數據庫查詢技術如搜索引擎。如下圖所示:
NoSQL 和搜索引擎都是源自互聯網的技術手段,對可伸縮的分布式特性具有更好的支持。應用服務器則通過一個統一數據訪問模塊訪問各種數據,減輕應用程序管理諸多數據源的麻煩。
業務拆分
大型網站為了應對日益復雜的業務場景,通過使用分而治之的手段將整個網站業務分成不同的產品線。如大型購物交易網站都會將首頁、商鋪、訂單、買家、賣家等拆分成不同的產品線,分歸不同的業務團隊負責。具體到技術上,也會根據產品線划分,將一個網站拆分成許多不同的應用,每個應用獨立部署。應用之間可以通過一個超鏈接建立關系(在首頁上的導航鏈接每個都指向不同的應用地址),也可以通過消息隊列進行數據分發,當然最多的還是通過訪問同一個數據存儲系統來構成一個關聯的完整系統,如下圖所示:
分布式微服務
隨着業務拆分越來越小,存儲系統越來越龐大,應用系統的整體復雜度呈指數級增加,部署維護越來越困難。由於所有應用要和所有數據庫系統連接,在數萬台服務器規模的網站中,這些連接的數目是服務器規模的平方,導致數據庫連接資源不足,拒絕服務。既然每一個應用系統都需要執行許多相同的業務操作,比如用戶管理、商品管理等,那么可以將這些共用的業務提取出來,獨立部署。由這些可復用的業務連接數據庫,提供共用業務服務,而應用系統只需要管理用戶界面,通過分布式服務調用共用業務服務完成具體業務操作。如下圖所示:
三、拆分 VS 集群
1. 拆分:不同的多台服務器上面部署不同的服務模塊,模塊之間通過RPC通信和調用,用於拆分業務功能,獨立部署,多個服務器共同組成一個整體對外提供服務。
2. 集群:不同的多台服務器上面部署相同的服務模塊,通過分布式調度軟件進行統一的調度,用於分流容災,降低單個服務器的訪問壓力。
四、微服務 VS SOA
創始人:martin fowler https://martinfowler.com/articles/microservices.html
單體應用:ALL IN ONE
微服務是一種架構風格,一個大型復雜軟件應用由一個或多個微服務組成。系統中的各個微服務可被獨立部署,各個微服務之間是松耦合的。每個微服務僅關注於完成一件任務並很好地完成該任務。在所有情況下,每個任務代表着一個小的業務能力
微服務,從本質意義上看,還是 SOA 架構。但內涵有所不同,微服務並不綁定某種特殊的技術,在一個微服務的系統中,可以有 Java 編寫的服務,也可以有 Python編寫的服務,他們是靠Restful架構風格統一成一個系統的。所以微服務本身與具體技術實現無關,擴展性強。
五、前后端完全分離與Rest規范
http是目前在互聯網上使用最多的協議,沒有之一。可是http的創始人一直都覺得,在過去10幾年來,所有的人都在錯誤的使用Http。這句話怎么說呢?如果說你要刪除一個數據,以往的做法通常是 delete/{id},如果你要更新一個數據,可能是Post數據放Body,然后方法是 update/{id}, 或者是artichle/{id}?method=update。這種做法讓我很暴燥,我覺得這個世界不該這樣的,所有的人都在誤解而且在嚴重錯誤的誤解Http的設計初衷,好比是發明了火葯卻只用它來做煙花爆竹。那么正確的使用方式是什么呢?如果你要看Rest各種特性,你恐怕真的很難理解Rest,但是如果你看錯誤的使用http的人倒底兒了哪些錯,什么是Rest就特別容易理解了。
第一條,混亂。一萬個人心里有一萬個Url的命名規則,Url是統一資源定位符,重點是資源。而很多人卻把它當成了萬金油,每一個獨立的虛擬的網頁都可以隨意使用,各種操作都能夠迭加。這是混亂的來源之一。
第二條,貪婪。有狀態和無狀態全部混在一起。特別是在購物車或者是登錄的應用中,經常刷新就丟失帶來的用戶體驗簡直棒棒噠。每一個請求並不能單獨的響應一些功能,很多的功能混雜在一起里。這是人性貪婪的本質,也是各種Hack的起源,只要能夠把問題解決掉,總會有人用他認為最方便的方式去解決問題,比如說汽車門把手壞掉了直接系根繩子當把手,emmmm這樣確實很棒啊。
第三條,無序。返回的結果往往是很隨意,各種錯誤信息本來就是用Http的狀態碼構成的,可是很多人還是喜歡把錯誤信息返回在返回值中。最常見的就是Code和Message,當然對於這一點,我個人是保留疑問的,我的觀點是,Http本身的錯誤和服務器的內部錯誤還是需要在不斷層面分開的,不能混在一起。可是在大神眼里並非如此,這個再議。
好了我編不下去了。那么怎么解決這些問題呢?強迫症患者的福音就是先頒規則,第一個規則就是明確Url是什么,該怎么用。就是所有的Url本質來講,都應該是一種資源。一個獨立的Url地址,就是對應一個獨一無二的資源。怎么樣?這種感覺是不是棒棒噠?一個冰淇淋,一個老師,一間房子,在Url上對應的都是一個資源,不會有多余的Url跟他對應,也不會表示有多個Url地址~~注意,這里點的是Url地址,並不是單獨的參數,他就是一個/room/{room_id}這樣的東西,舉個栗子,/room/3242 這就表示3242號房間。這是一個清爽的世界啊,你想想,之前的Url是什么都要,我開房,可能是/open/room/3242 我要退房可能是/exit/3242/room,我要打理房間,可能是room/3242?method=clean.夠了!這些亂七八糟的東西全夠了,讓世界回歸清爽的本質,一間房,就是/room/3242 沒有別的Url地址了。 那我想要對這個資源有操作怎么辦?這就是棒棒噠大神想出來的了,http有幾種Method來着?get ,put,post,delete,還有其他隱藏的4種。在過去的混亂世界里,經常用的就是Get和Post。如果不是因為Get不支持大數據傳輸,我想連Post都會有人使用。(想像一下Roy Fielding在憤怒的對着電腦屏幕喊,Http的Method一共有八個,你們為毛只逮着Get一只羊的毛薅薅薅薅薅)。而對資源最常見的操作是什么?CRUD,對不對,就是創建,讀,更新,刪除。再看Http的Method?是不是非常完美?其實也怪Fielding老爺子一開始命名不准確,如果剛開始就是把Get方法叫做Read,Put方法叫做Update,Post叫做Create這該多好。。。你用一個Get,大家又發現沒什么限制沒什么所謂,又很難理解Put和Post的差別,法無禁止即可為啊,呃,老爺子不要瞪我,我瞎說的。總之,這四種方法夠不夠你浪?你有本身找出來更多的對資源的操作來啊,我還有4個Method沒用過呢。如果這4個真的不夠了,有什么問題,大不了我再重新更改http協議啊。其實簡單說,對於Rest理解到這里就夠了。后續的東西,都是在這一條基礎上空想出來的,比強迫症更強迫症,當然,無狀態我是百分百支持的。以上的各種表述可能不太准確,也純屬是我的意淫和各種小道資料,並未考據,但是憑良心講,我是早就看不慣黑暗年代里的Url命名風格了,所以當時最早接觸到Rest的時候,瞬間就找到了真愛,我靠,這不就是我一直想要的答案嗎?但是我一直想的僅僅是命名規范,從來沒有把自己的思考角度放在一個url就是一個資源,所有的操作都是對資源的更改而言的角度上啊。所以你能理解到的程度,更多的就是在於你要弄清楚你要解決的什么問題,如果你的問題只是理解Rest,恐怕你很理解,如果你的問題是怎么解決Url混亂的問題,你反而很快能弄懂了~
Rest操作最佳實踐:現在在很多企業中,雖然都在支持Rest規范,但是真正嚴格遵守的幾乎沒有,因為按照Rest規范,刪除需要發送Delete請求,插入需要發送PUT請求,過於繁瑣,並且有些框架,例如ajax,Springmvc等,對Delete和PUT請求的支持不太友好,所以實際應用中很少使用這兩種請求,一般還是只是用Get和Post請求,使用接口名字來區分,所以,對於Rest規范,只需要記得傳遞數據只使用JSON,而不是后端去渲染模板,從而實現前后端的完全分離。
六、CAP三進二和Base定理
關系型數據庫遵循ACID規則
事務在英文中是transaction,和現實世界中的交易很類似,它有如下四個特性:
1、A (Atomicity) 原子性 原子性很容易理解,也就是說事務里的所有操作要么全部做完,要么都不做,事務成功的條件是事務里的所有操作都成功,只要有一個操作失敗,整個事務就失敗,需要回滾。比如銀行轉賬,從A賬戶轉100元至B賬戶,分為兩個步驟:1)從A賬戶取100元;2)存入100元至B賬戶。這兩步要么一起完成,要么一起不完成,如果只完成第一步,第二步失敗,錢會莫名其妙少了100元。
2、C (Consistency) 一致性 一致性也比較容易理解,也就是說數據庫要一直處於一致的狀態,事務的運行不會改變數據庫原本的一致性約束。
3、I (Isolation) 獨立性 所謂的獨立性是指並發的事務之間不會互相影響,如果一個事務要訪問的數據正在被另外一個事務修改,只要另外一個事務未提交,它所訪問的數據就不受未提交事務的影響。比如現有有個交易是從A賬戶轉100元至B賬戶,在這個交易還未完成的情況下,如果此時B查詢自己的賬戶,是看不到新增加的100元的
4、D (Durability) 持久性 持久性是指一旦事務提交后,它所做的修改將會永久的保存在數據庫上,即使出現宕機也不會丟失。
CAP三進二
在分布式系統中,講究C:Consistency(強一致性)、A:Availability(可用性)、P:Partition tolerance(分區容錯性)
CAP的證明基於異步網絡,異步網絡也是反映了真實網絡中情況的模型。真實的網絡系統中,節點之間不可能保持同步,即便是時鍾也不可能保持同步,所有的節點依靠獲得的消息來進行本地計算和通訊。這個概念其實是相當強的,意味着任何超時判斷也是不可能的,因為沒有共同的時間標准。之后我們會擴展CAP的證明到弱一點的異步網絡中,這個網絡中時鍾不完全一致,但是時鍾運行的步調是一致的,這種系統是允許節點做超時判斷的。CAP的證明很簡單,假設兩個節點集{G1, G2},由於網絡分片導致G1和G2之間所有的通訊都斷開了,如果不滿足P,則整個網絡不可用,如果在G1中寫,在G2中讀剛寫的數據, G2中返回的值不可能G1中的寫值。由於A的要求,G2一定要返回這次讀請求,由於P的存在,導致C一定是不可滿足的。CAP理論就是說在分布式存儲系統中,最多只能實現上面的兩點。 而由於當前的網絡硬件肯定會出現延遲丟包等問題,所以分區容忍性是我們必須需要實現的。所以我們只能在一致性和可用性之間進行權衡,沒有任何分布式系統能同時保證這三點。C:強一致性 A:高可用性 P:分布式容忍性 CA 傳統Oracle數據庫AP 大多數網站架構的選擇CP Redis、Mongodb注意:分布式架構的時候必須做出取舍。 一致性和可用性之間取一個平衡。多余大多數web應用,其實並不需要強一致性。因此犧牲C換取P,這是目前分布式數據庫產品的方向
一致性與可用性的決擇
對於web2.0網站來說,關系數據庫的很多主要特性卻往往無用武之地
數據庫事務一致性需求 很多web實時系統並不要求嚴格的數據庫事務,對讀一致性的要求很低, 有些場合對寫一致性要求並不高。允許實現最終一致性。
數據庫的寫實時性和讀實時性需求 對關系數據庫來說,插入一條數據之后立刻查詢,是肯定可以讀出來這條數據的,但是對於很多web應用來說,並不要求這么高的實時性,比方說發一條消息之 后,過幾秒乃至十幾秒之后,我的訂閱者才看到這條動態是完全可以接受的。
對復雜的SQL查詢,特別是多表關聯查詢的需求 任何大數據量的web系統,都非常忌諱多個大表的關聯查詢,以及復雜的數據分析類型的報表查詢,特別是SNS類型的網站,從需求以及產品設計角 度,就避免了這種情況的產生。往往更多的只是單表的主鍵查詢,以及單表的簡單條件分頁查詢,SQL的功能被極大的弱化了。
CAP理論的核心是:一個分布式系統不可能同時很好的滿足一致性,可用性和分區容錯性這三個需求, 最多只能同時較好的滿足兩個。 因此,根據 CAP 原理將 NoSQL 數據庫分成了滿足 CA 原則、滿足 CP 原則和滿足 AP 原則三大類:
- CA - 單點集群,滿足一致性,可用性的系統,通常在可擴展性上不太強大。
- CP - 滿足一致性,分區容忍必的系統,通常性能不是特別高。
- AP - 滿足可用性,分區容忍性的系統,通常可能對一致性要求低一些。
BASE定理
BASE就是為了解決關系數據庫強一致性引起的問題而引起的可用性降低而提出的解決方案。
BASE其實是下面三個術語的縮寫:
- 基本可用(Basically Available)
- 軟狀態(Soft state)
- 最終一致(Eventually consistent)
它的思想是通過讓系統放松對某一時刻數據一致性的要求來換取系統整體伸縮性和性能上改觀。為什么這么說呢,緣由就在於大型系統往往由於地域分布和極高性能的要求,不可能采用分布式事務來完成這些指標,要想獲得這些指標,我們必須采用另外一種方式來完成,這里BASE就是解決這個問題的辦法
分布式一致性理論paxos、raft、zab算法
演示 Raft http://thesecretlivesofdata.com/raft/