分布式系統
特點:
1.系統各組件分布於網絡上多個計算機上
2.我們部署的各功能組件彼此之間僅僅通過消息傳遞來通信,達到協調行動的目的。
滿足這兩點,你的系統就是分布式系統
分布式系統存在的意義:
向上擴展達到瓶頸:
1.即單機上無論你增加內存,磁盤,CPU個數,其性價比很難再提不上去了。
2.性能達到臨界點后,性能將不升反降。
3.單點故障無法避免,故障后一切擴展都將不可用。
基於馮諾依曼的計算機架構,對於當前來說已經無法從單機上得到更好的整體系統性能。摩爾定律說計算機硬件技術會每18個月更新一次,在當今世界也在改變,硬件的提升會逐漸達到提升瓶頸,而數據則會在18個月后翻一倍,所以我們已經進入一個大數據的時代。另外,摩爾定義也向我們說明了一個問題,今天你花多大的價錢買的硬件,在一年半(18個月)后都會落后。
多CPU:
硬件技術進步,讓單機計算能力出現了太多空閑,因此多線程編程技術就成為了最佳的提高性價比的方式。
多線程編程模型:
1. 互不通信的線程模型: 這些模型的性能是最好的,執行效率也是最高效的,但實用性可能不高。
2. 基於共享容器協同工作的模型:
A線程運行過程中,需要從B線程哪里獲取一個結果,才能繼續運行,若此時A線程直接去啟動B線程,
這其實是相當麻煩的事,若借助中間容器,這里指隊列,A線程通過將請求發給隊列,然后,B線程
從隊列中獲取請求,執行結束后將結果再放回隊列中,A線程從隊列中獲取結果后,就可以繼續執行了。
這種就是共享容器模型,它可以實現讓多個線程並行協同運行。
為了使這種共享容器模型在多線程並行時,訪問數據更加安全,它又分為兩種類型:
a. 線程安全
指A線程修改了共享容器中的A數據,而C去訪問A數據或修改A數據也一樣可以,它們之間都是
互相獨立,互不干擾的,這種就稱為線程安全的模型。
b. 線程不安全
指A線程修改了共享容器中的A數據,而C線程此時也去修改A數據,就可能導致A數據損壞,這種
就稱為線程不安全。 對於線程不安全的類型,通常使用加鎖的機制 或 Copy on Write(COW)
的方式來保障數據安全,在使用加鎖的機制時,若並發線程數很多時,通常會使用互斥鎖。
這種方式中線程之間是需要互相通信的,因此就會造成等待結果的一方將不能繼續運行,所以這其實
就會降低多線程並行執行的效率了。
3.通過事件協調的多線程模型
B的某個執行流程依賴於A完成了某種特定操作之后才能進行。那么A就需要在某個特定操作完成之后,
觸發一個事件,這個事件可以通知給B,所以B拿到這個事件后,就可以繼續運行了,所以在A觸發這個
事件之前,B就只能處於等待事件的狀態。
多線程 和 多進程模型的區別:
線程之間是可共享父進程內部的很多資源,如:父進程打開的文件句柄,內部信號等等。
進程之間是互相隔離的,它們僅能通過進程間通信模式進行交互通信,所以多進程模型比多線程模型,在資源控制方面更為簡單。
這些模型的出現,主要是為了使用多CPU,因為,單個CPU已經不能通過提升頻率來提升其性能,目前芯片廠商都是通過增加CPU的核心數,借助於多線程編程,來解決單機上面性能的提升問題。但多線程編程又非常復雜,若程序員不能很好的利用多核心來編程,對於多核來說效益是很小的。
網絡I/O:
1.通過阻塞模型,即一個請求過來,在處理它時,其它請求都被阻塞等待第一個請求處理完才能被接入進來進行處理,所以這種模型目前已不在使用。
2.多進程模型,即每個進程響應一個請求;
3.多線程,多進程,即每個進程生成多個線程,每個線程響應一個用戶請求。
4.多線程,每個線程直接響應多個請求。
但是無論是那種方式,每一個請求進來都需要有一個對應的套接字。
基於socket實現網絡通信開發,其實現方式主要有三類:
BIO: Blocking IO,即阻塞式IO:一個Socket套接字需要一個進程或一個線程來處理,那么連接的建立讀數據寫數據的過程都有可能產生阻塞,這種機制就是每進程 或 每線程響應一個請求的模式。
缺點:每個連接都要占用一個套接字. 【注:套接字有兩種:連接和監聽套接字】
NIO: Nonblocking IO,非阻塞I/O,它是基於事件驅動(Linux是epoll實現事件驅動的.)的思想,采用Reactor模式,實現響應。
優點: 一個套接字分配個一個線程,而一個線程可以處理多個套接字相關的工作。
AIO:異步IO模式,它也是基於事件驅動的思想,但它采用Proactor模式
如何把應用從單機擴展到多機?
輸入、輸出設備如何變化?
控制器如何變化?
實現的模式:
透明代理: 即用戶訪問時,已經給我們響應的就是服務器,其實可能是以下這些,這種就屬於對用戶透明的.
而且中間的轉發控制器就成為網絡的中心。如下:
LVS的NAT模型,
Haproxy, Nginx的反向代理
旁路代理
LVS的DR模型
名稱服務模式:
DNS: 用戶僅第一次訪問時,需要查詢,DNS通過名稱給客戶端反饋不同的解析IP,實現調度控制。
規則服務模式:
規則服務器:在數據庫服務中,當數據庫很大時,需要分庫,分表時,就需要規則服務器在中間做為一個向導,
告訴第一次訪問數據的客戶端,你需要的數據是分散在多個主機上,還是一個節點上。
Master/Slave機制:
Master能夠處理所有請求,Slave僅做為運算器分擔部分讀運算任務,Master需要控制給Slave發送數據,
所以Master也是一種控制器。
運算器的變化: 【暫時理解不深】
存儲器的變化: 【暫時理解不深】
分布式系統實現的難點:
1.缺乏全局時鍾: 在單機中,CPU的每秒中能產生很多個時鍾頻率,但是其它部件的功能頻率相對與CPU來說是極慢的,為了達到步調一致,單機內部通過中斷等機制實現協同工作。
2.面對故障時的獨立性
3.處理單點故障
4.事務處理:
ACID
2PC(兩段式提交)、BASE、CAP、Paxos(帕克索斯:希臘神話中的天馬)
大型網站站點的架構演進方式:
LAMT, LNMT(Tomcat)
應用從資源占用的角度分兩類:
CPU Bound: CPU密集型,ApplicationServer對CPU占用多。
IO Bound: IO密集型, 數據庫對IO占用多。
網站從最開始一台主機上運行一個Nginx代理 + Tomcat應用服務器 + MySQL數據庫.
當網站訪問量增大時,首先出現告警的可能是MySQL數據庫,因為磁盤I/O天生是系統的瓶頸,因此數據庫先被分離出來,這樣數據庫壓力就變小了。
引入MySQL主從面臨的問題:
1. 數據復制的問題
2. 應用選擇數據源的問題
接着網站訪問量繼續增大,Tomcat這類應用服務器,Nginx代理等都屬於CPU密集型,它們在單機上出現了CPU資源爭用的問題,這僅是小問題,更重要的是應用服務器出現了數據訪問的熱區,基本上會遵循二八定律,這時就必須分離,並且增加應用服務器,你的系統就變成了兩台應用服務器,這時前端必須有一個反向代理,所以加上MySQL就是四台主機.但應用服務器分開后,就需要用戶訪問的會話保存問題,有以下三種解決方案:
Session sticky:會話粘性,存在單點故障,一定其中一台Server宕機,會話將丟失。
ip based:
cookie based:它帶來的額外問題是,帶寬占用將非常巨大,若一個cookie僅50字節,但是若一天一億個請求,就有一億個50字節,有多大?
Session replication: 會話復制,不適合大規模使用,因為一方面會消耗Server的內存,另一方會帶來大量的內網同步Session的流量,影響整體網絡環境。
Session server:通過Memcached來集中存儲用戶會話,擴展性好,適合大規模擴展。
若考慮到網站在一年內可能出現幾何增長的可能,如:從200並發到過萬的並發,這時使用前兩種會話保存就不合適了,就必須使用第三種方案。
引入搜索引擎實現全文搜索:
網站演變到這里,我們需要知道問題的核心在哪里,數據庫中的數據最終是要讓用戶可以查詢到的,因為 用戶不能在你的網站一個一個網頁去翻,然后去找到自己需要的商品,通常都是通過搜索定位到他們需要的商品,那這時僅靠MySQL很難實現了,因為我們的電商網站的數據庫是需要支持事務,但MyISAM存儲引擎支持全文索引,但不支持事務,所以它並非最佳途徑,我們就需要另拿一台服務器專門安裝MySQL使用支持全文索引的存儲引擎,將現有MySQL的Slave節點上將數據都讀出來,在它上面做全文索引,然后,前端自己開發的索引引擎,通過搜索全文索引數據庫,來響應用戶的搜索請求,所以Slave讀取Master上數據的及時性就顯得很重要了,因為新上架是商品能否讓用戶看到,取決於搜索庫中有沒有從Slave庫中讀到新商品數據。
引入緩存
當我們的網站中應用服務器的壓力主要集中在對很多靜態內容的處理上時,那我們就需要使用動靜分離技術,但比它更使用的此時應該是緩存,在負載均衡器后面第一級,先引入緩存,把不變化的靜態內容直接緩存在應用服務器的前端緩存服務器中,甚至還可以使用AJAX技術實現緩存網頁中的一部分數據,另外一部分變化的數據,到后端去計算后得到,比如一個淘寶頁面,第一用戶看商品頁面和第二個用戶看的商品頁面是一樣的,這時就可以緩存這個頁面,但有可能第二個用戶看時,這個商品已經賣出去了2個,所以僅需要從后端應用服務器上獲取這部分變化的庫存量信息就可以了,這樣可以更大程度減少后端的壓力。
引入緩存要考慮兩個方面的問題:
1.頁面緩存
varnish, squid
2.數據庫緩存
因為數據庫節點可能也會逐漸增加,而查詢緩存僅在數據庫本地有效,為了提高命中率,增加數據庫緩存也是必須的。
對於數據庫緩存,要使用Key-Value類型的存儲,而Memcached是其中最具代表性的。
若引入Memcached,將會引入新問題:
a. 需要自行開發程序調用Memcached的API實現存儲。
b. 需要自行管理其數據有效期。
注意:
引入緩存,可能不會只有一台,或者說會逐漸增加成多台,這時我們就可以稱這種緩存架構為分布式緩存,在分布式緩存中,要提高數據的命中率,就必須使用哈希算法,來提高命中率。
當網站規模繼續增大時,接下來面臨壓力的一定就是數據庫的寫庫。
對於數據庫寫庫的分擔,只有數據庫拆分這一條路.
垂直拆分:把數據庫中不同的業務的數據拆分到不同的數據庫中,它緩解的是讀壓力.
假如以電商網站來說:將它的用戶表,交易表,商品表分別分到三個庫,但我們知道,
我們到淘寶上買的東西,我們會去搜索用戶嗎?會搜索其他人的交易信息嗎?
不會,甚至也不允許,所以商品表被讀的壓力就會很大,因此它是一定要做主從的,
其它庫可以從數據安全性角度來說,也可以做主從。
由於數據庫級別拆分成多個了,這時我們訪問數據庫就必須要知道我們訪問的數據在哪里
所以前端應該還要有規則服務器來告知前端應用數據在那台后端數據庫上。
靜態內容: 如用戶證書,用戶生物信息,交易歷史記錄,商品圖片等
FTP上傳: 如: 商品圖片,用戶身份證圖片,文檔等
水平拆分:把一個單獨的表中的數據拆分到多個不同的數據庫服務器中,它緩解的是寫壓力。
假如馬上要到剁手節,將產生大量用戶產生交易信息,交易表可能受不了,那怎么辦?
這就需要分擔對交易表的寫壓力,對交易表我們可以根據用戶年齡來拆分,將年輕群體
中消費能力弱的18-20的分到一張表,消費能力較強的21-25分一張表,26-29分一張表,
等等,來拆分表,但是表拆分完了后,該怎么去訪問?前端應用怎么知道我要訪問的數據
在哪里存儲?由此規則服務就更加重要了。
引入NoSQL: 非關系型數據庫
文檔數據庫
列式數據庫
....
DFS: 非結構化數據
TFS, MogileFS: 適用於海量小文件
HDFS, GFS: 少量大文件
CDN的使用:
越向后,系統的訪問量越大,這時內部整個機房的擴容若在繼續擴大,不在是解決問題最有效的手段,而且主機數量也總有上限,但是前端的壓力已經讓負載和緩存吃不消了,在這時最佳的手段就是引入CDN,目前國內比較知名的CDN廠家有 BAT,藍汛等。 CDN它能夠實現讓用戶直接在家門口的緩存服務器上獲取要我們的網站數據,這樣就有效的分散了到達我們主站的流量壓力,當用戶訪問我們網站時,智能DNS通常會,根據用戶所在地區為用戶解析域名,它會依據緩存服務器距離用戶地理位置最近,或帶寬最大等信息,做智能判斷並返回用戶一個域名,這個域名通常是一個負載均衡器的域名,用戶進行二次解析后,得到距離自己最近的緩存集群,該緩存集群的負載均衡器將用戶請求接入進來,在后端緩存服務器上查詢,若命中,則直接返回數據給用戶,若未命中,則向最近的緩存節點查詢,無數據則由該緩存節點,向我們網站發起請求,網站響應該請求時,先查詢本地緩存,命中則直接返回,未命中則繼續向下,到應用服務器,由應用服務器處理此請求,並通過查詢數據庫等一系列業務邏輯處理,返回結果給CDN的緩存節點,由該節點再向用戶返回數據。
應用拆分:
根據業務特性拆分
根據用戶拆分
如: 用戶注冊應用
用戶登錄應用
用戶信息維護應用
根據對底層應用的調用進行拆分
異步: 解耦
消息中間件:
它是協調多個應用之間,通過消息傳遞的方式來實現其功能協調的機制,它的整個工作過程是
通過異步方式實現的。所以它在分布式系統中,是消息接收和發送的基礎性軟件。
它最大的特點就是:異步和解耦。
MOM:Message-oriented middleware.
現有的比較知名的消息中間件:
RabbitMQ, ActiveMQ, ZeroMQ(ZMQ)
注: 它們僅能工作於它們支持的模型中。
模塊化:
服務化:
當網站的結構發展到服務化后,每個層都可能出現大量重復代碼,但這是不可避免的。
一旦架構進入這樣的級別,無論是垂直還是水平拆分都會面臨ACID被打破的問題,此時只有兩種選擇,放棄事務 或 引入分布式事務!
在進行Join查詢時,也將變得異常困難,原來依賴與外鍵實現的約束將無從保證等等問題,都將面臨巨大的挑戰。
面對這些挑戰,我們唯一能做到就是從理論出發,結合實際去構建適合自己實際需求的解決方案。