分佈式系統設計原理與方案

一直在思考分佈式系統設計的問題,業務對象原封不動的狀況下部署在客戶端和服務器端,能夠根據配置文件選擇是鏈接服務器仍是鏈接本地的數據庫,這個問題讓我絞盡腦汁,我老是設想的客戶端與服務器端通訊的方式是最低端的Socket。花了兩個晚上研究CSLA.NET框架關於數據門戶這塊代碼,才發現問題的關鍵所在:客戶端與服務器端通訊不能採用最低端的Socket,而要用高端的WebService、.NET Remoting或者是本身定義一種協議等,只要它們支持客戶端直接根據服務器端的服務URL、類名、方法名和方法參數四個信息就能夠調用服務器對應的類和方法就行。php

說明:本文中所表達的思想與CSLA.NET有很大區別,不要看了本文就覺得是CSLA.NET的設計思想,也不要覺得本文錯誤的解釋了CSLA.NET,這不是一篇介紹CSLA.NET的文章,但純思想上它們是相同的。css

  • 分佈式系統的部署

  日常咱們都說三層架構,我認爲它是一個廣義的模型,更多層的設計能夠合併相鄰幾層的方式最終迴歸到三層這個寬泛的概念上來,個人意思是:這些都只是概念,忘記這些概念去實際分析設計會離這些概念更近一些。html

  接下來我要把三層變的更簡單點,兩層,數據訪問層合併到業務層,統稱爲業務層,由於咱們面對的問題不是分層的問題,而是分佈式系統中各層應該怎麼部署的問題。在CSLA.NET書中也說到業務層和數據訪問層放到同一臺機器上能夠提升性能和容錯性。所以他們倆的合併不影響分佈式系統的部署。前端

  不過要解釋的是數據庫系統(CSLA.NET中說的數據存儲和管理層)並無考慮到三層中來,也就是它不包含在數據訪問層中,若是把它算進來,那麼它是在數據訪問層之下單獨存在的。node

  綜上,在分佈式系統部署角度考慮的分層實際是三層:界面層、業務層(包含數據訪問層的業務層)、數據存儲層。mysql

  下面舉例說明可能的部署情景,帶陰影的框框表示一臺機器,虛線框表示根據使用場合無關緊要,虛橫線表示今後處劃開單獨出服務器。在B/S應用中,Web瀏覽器爲客戶端,其餘所有爲服務器。在C/S應用中,處在最上層的界面層+業務層爲客戶端,其餘爲服務器nginx

非分佈式系統的部署git

單機版

單機版github

 

分層2

兩三臺機器web

分佈式系統的部署

分層3

分佈式的Web系統

 

分層4

 

分佈式的C/S系統

有幾點要說明:
1. 客戶端上的驗證等業務邏輯是不可信的,所以任何一種部署都須要服務器端包含業務層;
2. 爲了開發、維護和部署中的高度可伸縮性,圖中的各業務層所包含的代碼都是如出一轍的;
3. 由於第2點,因此我遇到了業務層的同一個操做是與其餘機器上的業務層通訊仍是訪問數據庫這個難題。

解決業務層的數據訪問問題

  這個問題是關鍵問題,也就是上面幾點說明中的第3個問題,爲了解決這個問題咱們引入數據門戶的概念。

  下面以WebService爲例說明:界面層訪問本機的業務對象的增刪改查中的「查」方法時,跳過數據庫的查詢操做,訪問另外一臺機器中的同一個業務對象類的「查」方法。

請求

  以上是向另外一臺機器發送請求,該請求並不直接調用另外一臺機器上的業務對象類的「查」方法,而是將要調用的業務對象和方法參數信息轉爲一個「二進制包」,做爲參數去調用另外一臺機器上通用的「查」方法,另外一臺機器上的「查」方法再解開這個包,而後去調用解開的包中所表示的業務對象類型,下面的靜態圖是另外一臺機器接受到請求後的工做。

響應

又有些說明:
1. 關於原理都已在圖中作了描述,不另寫大段文字解釋了;
2. 上面兩個圖中,除了「實際業務對象類」之外的部分所有屬於架構或者框架部分;
3. 若是用OO的思想去審查上面的兩個圖,你必定會爲這糟糕的設計而抱怨,這裏只是爲了儘量簡單的表述分佈式系統的工做原理,你能夠採用策略模式使數據門戶不改變的狀況下適應各類請求響應場合,採用工廠模式實現不一樣的請求響應場合的切換。

 

 

 關於數據庫的分佈

  爲了解決數據庫服務器的負擔,咱們可能但願把數據分佈存儲在多個服務器上,我設想的數據庫分佈方案是,各服務器上的數據庫在結構上如出一轍,而表裏的數據存儲到不一樣服務器上,這樣數據訪問層在查數據的時候分別向全部數據庫服務器發送一樣的sql命令,而後數據訪問層獲得數據後整合,這樣減輕每臺服務器的工做量。亦或者根據表裏的某個表明性的字段(如:省份)分佈數據到不一樣服務器。

 

 

0x01.大型網站演化

簡單說,分佈式是以縮短單個任務的執行時間來提高效率的,而集羣則是經過提升單位時間內執行的任務數來提高效率。

集羣主要分爲:高可用集羣(High Availability Cluster),負載均衡集羣(Load Balance Cluster,nginx便可實現),科學計算集羣(High Performance Computing Cluster)。

分佈式是指將不一樣的業務分佈在不一樣的地方;而集羣指的是將幾臺服務器集中在一塊兒,實現同一業務。分佈式中的每個節點,均可以作集羣。 而集羣並不必定就是分佈式的。

以前在網上看到一篇關於大型網站演化的博客。http://www.cnblogs.com/leefreeman/p/3993449.html

每一個大型網站都會有不一樣的架構模式,而架構內容也就是在處理均衡負載,緩存,數據庫,文件系統等,只是在不一樣的環境下,不一樣的條件下,架構的模型不同,目的旨在提升網站的性能。

最初的架構只有應用程序,數據庫,文件服務。

 

到後來,分佈式服務、集羣架設。

 

 

0x02.關於均衡負載方案

在上一篇,《Nginx反向代理實現均衡負載》討論過過的nginx現實均衡負載方案,這裏選擇另外一種HAProxy+Keepalived雙機高可用均衡負載方案。

HAProxy是免費、極速且可靠的用於爲TCP和基於HTTP應用程序提供高可用、負載均衡和代理服務的解決方案,尤爲適用於高負載且須要持久鏈接或7層處理機制的web站點。

不管是Haproxy仍是Keepalived甚至是上游服務器均提升生產力並加強可用性,也就是以下架構中Haproxy,Keepalived,Httpd服務器任意宕機一臺服務仍是能夠正常運行的。

HAProxy的優勢:

一、HAProxy是支持虛擬主機的,能夠工做在四、7層(支持多網段);

二、可以補充Nginx的一些缺點好比Session的保持,Cookie的引導等工做;

三、支持url檢測後端的服務器;

四、自己僅僅就只是一款負載均衡軟件;單純從效率上來說HAProxy更會比Nginx有更出色的負載均衡速度,在併發處理上也是優於Nginx的;

五、HAProxy能夠對Mysql讀進行負載均衡,對後端的MySQL節點進行檢測和負載均衡;

 

 

0x03.關於Redis緩存方案

緩存分爲服務器緩存和應用程序緩存。

關於應用程序內緩存,已經在Jue後臺框架裏面作了模塊處理了。

關於服務器緩存,主要緩存服務器文件,減小服務器和php交互,減小均衡負載服務器和應用程序服務器交互。

緩存裏面有一種典型的memcached,如今用的多的是redis輕量級緩存方案。

關於memcached與redis,看這篇 《Memcached vs Redis?》

Redis主要將數據存儲在各類格式:列表,數組,集合和排序集,一次能接受多個命令,阻塞讀寫,等待直到另外一個進程將數據寫入高速緩存。

 

 

一篇關於Reids緩存方案。《高可用、開源的Redis緩存集羣方案》

 

 

0x04.關於搜索引擎Sphinx方案

(第一期不作,後期需求時候考慮)

Sphinx是俄羅斯人開發的,號稱是很吊啦,千萬級數據檢索,每秒10MB/s,搭過環境。

Sphinx和MySQL是基於數據庫的全文引擎,建立索引是B+樹和hash key-value的方式。

原理相似於用底層C檢索MySQL,而後弄出一個sphinx.conf配置文件,索引與搜索均以這個文件爲依據進行,要進行全文檢索,首先就要配置好sphinx.conf,告訴sphinx哪些字段須要進行索引,哪些字段須要在where,orderby,groupby中用到。

Sphinx中文

 

 

0x05.關於NoSQL快速存儲方案

NoSQL在這裏的使用價值是處理一些雜事,好比用戶我的網站的一些css值,height,width,color等等的小而繁多的數據,採用NoSQL旨在提高數據庫速度,減小對MySQL的SELECT請求。

關於NoSQL的方案不少了,選一個簡單的MongDB好了。

 

 

0x06.關於分佈式MySQL方案

(作分佈式MySQL還沒嘗試過,初期也不清楚mysql所須要的壓力,因此第一期不打算作分佈式MySQL)

《標準MySQL數據庫外的5個開源兼容方案》

 

 

0x07.分佈式集羣方案

綜合起來,大體就是以下模型,初探分佈式架構,不少模塊將就形勢作調整,時時更新中,待續。。。

 

 

系統的目標很明確,針對千萬級以上PV的網站,設計一套用於後臺的高併發的分佈式處理系統。這套系統包含業務邏輯的處理、各類計算、存儲、日誌、備份等方面內容,可用於類微博,SNS,廣告推送,郵件等有大量線上併發請求的場景。

        如何抗大流量高併發?(不要告訴我把服務器買的再好一點)提及來很簡單,就是「分」,如何「分」,簡單的說就是把不一樣的業務分拆到不一樣的服務器上去跑(垂直拆分),相同的業務壓力分拆到不一樣的服務器去跑(水平拆分),並時刻不要忘記備份、擴展、意外處理等討厭的問題。提及來都比較簡單,但設計和實現起來,就會比較困難。之前個人文章,都是「從整到零」的方式來設計一個系統,此次我們就反着順序來。

        那咱們首先來看,咱們的數據應該如何存儲和取用。根據咱們以前肯定的「分」的方法,先肯定如下2點:

      (1)咱們的分佈式系統,按不一樣的業務,存儲不一樣的數據;(2)一樣的業務,同一個數據應存儲多份,其中有的存儲提供讀寫,而有的存儲只提供讀。

 

        好,先解釋下這2點。對於(1)應該容易理解,好比說,我這套系統用於微博(就假想咱們作一個山寨的推特吧,給他個命名就叫「山推」 好了,如下都叫山推,Stwi),那麼,「我關注的人」這一個業務的數據,確定和「我發了的推文」這個業務的數據是分開存儲的,那麼咱們如今把,每個業務所負責的數據的存儲,稱爲一個group。即以group的方式,來負責各個業務的數據的存儲。接下來講(2),如今咱們已經知道,數據按業務拆到group裏面去存取,那麼一個group裏面又應該有哪些角色呢?天然的,應該有一臺主要的機器,做爲group的核心,咱們稱它爲Group Master,是的,它就是這個group的主要表明。這個group的數據,在Group Master上應該都能找到,進行讀寫。另外,咱們還須要一些輔助角色,咱們稱它們爲Group Slaves,這些slave機器作啥工做呢?它們負責去Group Master處拿數據,並儘可能保持和它同步,並提供讀服務。請注意個人用詞,「儘可能」,稍後將會解釋。如今咱們已經有了一個group的基本輪廓:

 

        一個group提供對外的接口(廢話不然怎麼存取數據),group的底層能夠是實際的File System,甚至是HDFS。Group Master和Group Slave能夠共享同一個File System(用於不能丟數據的強一致性系統),也能夠分別指向不一樣的File System(用於弱一致性,容許停寫服務和系統宕機時丟數據的系統),但總之應認爲這個"File System"是無狀態,有狀態的是Group Master和各個Group Slave。

        下面來講一個group如何工做,同步等核心問題。首先,一個group的Group Master和Group Slave
間應保持強一致性仍是弱一致性(最終一致性)應取決於具體的業務需求,以咱們的「山推」來講,Group Master和Group Slave並不要求保持強一致性,而弱一致性(最終一致性)即能知足要求,爲何?由於對於「山推」來說,一個Group Master寫了一個數據,而另外一個Group Slave被讀到一個「過時」(由於Group Master已經寫,但此Group Slave還未更新此數據)的數據一般並不會帶來大問題,好比,我在「山推」上發了一個推文,「關注個人人」並無即時同步地看到個人最新推文,並無太大影響,只要「稍後」它們能看到最新的數據便可,這就是所謂的最終一致性。但當Group Master掛掉時,寫服務將中斷一小段時間由其它Group Slave來頂替,稍後還要再講這個問題。假如咱們要作的系統不是山推,而是淘寶購物車,支付寶一類的,那麼弱一致性(最終一致性)則很難知足要求,同時寫服務掛掉也是不能忍受的,對於這樣的系統,應保證「強一致性」,保證不能丟失任何數據。

        接下來仍是以咱們的「山推「爲例,看看一個group如何完成數據同步。假設,如今我有一個請求要寫一個數據,因爲只有Group Master能寫,那麼Group Master將接受這個寫請求,並加入寫的隊列,而後Group Master將通知全部Group Slave來更新這個數據,以後這個數據才真正被寫入File System。那麼如今就有一個問題,是否應等全部Group Slave都更新了這個數據,纔算寫成功了呢?這裏涉及一些NWR的概念,咱們做一個取捨,即至少有一個Group Slave同步成功,才能返回寫請求的成功。這是爲何呢?由於假如這時候Group Master忽然掛掉了,那麼咱們至少能夠找到一臺Group Slave保持和Group Master徹底同步的數據並頂替它繼續工做,剩下的、其它的Group Slave將「異步」地更新這個新數據,很顯然,假如如今有多個讀請求過來併到達不一樣的Group Slave節點,它們極可能讀到不同的數據,但最終這些數據會一致,如前所述。咱們作的這種取捨,叫「半同步」模式。那以前所說的強一致性系統應如何工做呢?很顯然,必須得等全部Group Slave都同步完成才能返回寫成功,這樣Group Master掛了,沒事,其它Group Slave頂上就行,不會丟失數據,可是付出的代價就是,等待同步的時間。假如咱們的group是跨機房、跨地區分佈的,那麼等待全部Group Slave同步完成將是很大的性能挑戰。因此綜合考慮,除了對某些特別的系統,採用「最終一致性」和「半同步」工做的系統,是符合高併發線上應用需求的。並且,還有一個很是重要的緣由,就是一般線上的請求都是讀>>寫,這也正是「最終一致性」符合的應用場景。

        好,繼續。剛纔咱們曾提到,若是Group Master宕機掛掉,至少能夠找到一個和它保持同不的Group Slave來頂替它繼續工做,其它的Group Slave則「儘可能」保持和Group Master同步,如前文所述。那麼這是如何作到的呢?這裏涉及到「分佈式選舉」的概念,如Paxos協議,經過分佈式選舉,總能找到一個最接近Group Master的Group Slave,來頂替它,從而保證系統的可持續工做。固然,在此過程當中,對於最終一致性系統,仍然會有一小段時間的寫服務中斷。如今繼續假設,咱們的「山推」已經有了一些規模,而負責「山推」推文的這個group也有了五臺機器,並跨機房,跨地區分佈,按照上述設計,不管哪一個機房斷電或機器故障,都不會影響這個group的正常工做,只是會有一些小的影響而已。

        那麼對於這個group,還剩2個問題,一是如何知道Group Master掛掉了呢?二是在圖中咱們已經看到Group Slave是可擴展的,那麼新加入的Group Slave應如何去「偷」數據從而逐漸和其它節點同步呢?對於問題一,咱們的方案是這樣的,另外提供一個相似「心跳」的服務(由誰提供呢,後面咱們將講到的Global Master將派上用場),group內全部節點不管是Group Master仍是Group Slave都不停地向這個「心跳」服務去申請一個證書,或認爲是一把鎖,而且這個鎖是有時間的,會過時。「心跳」服務按期檢查Group Master的鎖和其有效性,一旦過時,若是Group Master工做正常,它將鎖延期並繼續工做,不然說明Group Master掛掉,由其它Group Slave競爭獲得此鎖(分佈式選舉),從而變成新的Group Master。對於問題二,則很簡單,新加入的Group Slave不斷地「偷」老數據,而新數據總因爲Group Master通知其更新,最終與其它全部結點同步。(固然,「偷」數據所用的時間並不樂觀,一般在小時級別)

 

上篇(連接)咱們完成了在此分佈式系統中,一個group的設計。那麼接下來,咱們設計系統的其餘部分。如前文所述,咱們的業務及其數據以group爲單位,顯然在此係統中將存在many many的groups(別告訴我你的網站總共有一個業務,像咱們的「山推」,那業務是一堆一堆地),那麼由誰來管理這些groups呢?由Web過來的請求,又將如何到達指定的group,並由該group處理它的請求呢?這就是咱們要討論的問題。

        咱們引入了一個新的角色——Global Master,顧名思義,它是管理全局的一個節點,它主要完成以下工做:(1)管理系統全局配置,發送全局控制信息;(2)監控各個group的工做狀態,提供心跳服務,若發現宕機,通知該group發起分佈式選舉產生新的Group Master;(3)處理Client端首次到達的請求,找出負責處理該請求的group並將此group的信息(location)返回,則來自同一個前端請求源的該類業務請求自第二次起不須要再向Global Master查詢group信息(緩存機制);(4)保持和Global Slave的強一致性同步,保持自身健康狀態並向全局的「心跳」服務驗證自身的狀態。

        如今咱們結合圖來逐條解釋上述工做,顯然,這個系統的完整輪廓已經初現。

 

 

        首先要明確,無論咱們的系統如何「分佈式」,總之會有至少一個最主要的節點,術語可稱爲primary node,如圖所示,咱們的系統中,這個節點叫Global Master,也許讀過GFS + Bigtable論文的同窗知道,在GFS + Bigtable裏,這樣的節點叫Config Master,雖然名稱不同,但所作的事情卻差很少。這個主要的Global Master可認爲是系統狀態健康的標誌之一,只要它在正常工做,那麼基本能夠保證整個系統的狀態是基本正常的(什麼?group或其餘結點會不正常不工做?前面已經說過,group內會經過「分佈式選舉」來保證本身組內的正常工做狀態,不要告訴我group內全部機器都掛掉了,那個機率我想要忽略它),假如Global Master不正常了,掛掉了,怎麼辦?顯然,圖中的Global Slave就派上用場了,在咱們設計的這個「山推」系統中,至少有一個Global Slave,和Global Master保持「強一致性」的徹底同步,固然,若是有不止一個Global Slave,它們也都和Global Master保持強一致性徹底同步,這樣有個好處,假如Global Master掛掉,不用停寫服務,不用進行分佈式選舉,更不會讀服務,隨便找一個Global Slave頂替Global Master工做便可。這就是強一致性最大的好處。那麼有的同窗就會問,爲何咱們以前的group,不能這麼搞,非要搞什麼最終一致性,搞什麼分佈式選舉(Paxos協議屬於既難理解又難實現的坑爹一族)呢?我告訴你,仍是壓力,壓力。咱們的系統是面向日均千萬級PV以上的網站(「山推」嘛,推特是億級PV,咱們千萬級也不過度吧),但系統的壓力主要在哪呢?細心的同窗就會發現,系統的壓力並不在Global Master,更不會在Global Slave,由於他們根本不提供數據的讀寫服務!是的,系統的壓力正是在各個group,因此group的設計纔是最關鍵的。同時,細心的同窗也發現了,因爲Global Master存放的是各個group的信息和狀態,而不是用戶存取的數據,因此它更新較少,也不能認爲讀>>寫,這是不成立的,因此,Global Slave和Global Master保持強一致性徹底同步,正是最好的選擇。因此咱們的系統,一臺Global Master和一臺Global Slave,暫時能夠知足需求了。

        好,咱們繼續。如今已經瞭解Global Master的大概用途,那麼,一個來自Client端的請求,如何到達真正的業務group去呢?在這裏,Global Master將提供「首次查詢」服務,即,新請求首次請求指定的group時,經過Global Master得到相應的group的信息,之後,Client將使用該信息直接嘗試訪問對應的group並提交請求,若是group信息已過時或是不正確,group將拒絕處理該請求並讓Client從新向Global Master請求新的group信息。顯然,咱們的系統要求Client端緩存group的信息,避免屢次重複地向Global Master查詢group信息。這裏其實又挖了許多爛坑等着咱們去跳,首先,這樣的工做模式知足基本的Ddos攻擊條件,這得經過其餘安全性措施來解決,避免group老是收到不正確的Client請求而拒絕爲其服務;其次,當出現大量「首次」訪問時,Global Master儘管只提供查詢group信息的讀服務,仍有可能不堪重負而掛掉,因此,這裏仍有很大的優化空間,比較容易想到的就是採用DNS負載均衡,由於Global Master和其Global Slave保持徹底同步,因此DNS負載均衡能夠有效地解決「首次」查詢時Global Master的壓力問題;再者,這個工做模式要求Client端緩存由Global Master查詢獲得的group的信息,萬一Client不緩存怎麼辦?呵呵,不用擔憂,Client端的API也是由咱們設計的,以後才面向Web前端。

         以後要說的,就是圖中的「Global Heartbeat」,這又是個什麼東西呢?可認爲這是一個管理Global Master和Global Slave的節點,Global Master和各個Global Slave都不停向Global Heartbeat競爭成爲Global Master,若是Global Master正常工做,按期更新其狀態並延期其得到的鎖,不然由Global Slave替換之,原理和group內的「心跳」同樣,但不一樣的是,此處Global Master和Global Slave是強一致性的徹底同步,不須要分佈式選舉。有同窗可能又要問了,假如Global Heartbeat掛掉了呢?我只能告訴你,這

個很不常見,由於它沒有任何壓力,並且掛掉了必須人工干預才能修復。在GFS + Bigtable裏,這個Global Heartbeat叫作Lock Service。

 

如今接着設計咱們的「山推」系統。有了前面兩篇的鋪墊,咱們的系統如今已經有了五臟六腑,剩下的工做就是要讓其羽翼豐滿。那麼,是時候,放出咱們的「山推」系統全貌了:

 

        前面囉嗦了半天,也許很多同窗看的不明不白,好了,如今開始看圖說話環節:

      (1)整個系統由N臺機器組合而成,其中Global Master一臺,Global Slave一臺到多臺,二者之間保持強一致性並徹底同步,可由Global Slave隨時頂替Global Master工做,它們被Global Heartbeat(一臺)來管理,保證有一個Global Master正常工做;Global Heartbeat因爲無壓力,一般認爲其不能掛掉,若是它掛掉了,則必須人工干預才能恢復正常;

      (2)整個系統由多個groups合成,每個group負責相應業務的數據的存取,它們是數據節點,是真正抗壓力的地方,每個group由一個Group Master和一個到多個Group Slave構成,Group Master做爲該group的主節點,提供讀和寫,而Group Slave則只提供讀服務且保證這些Group Slave節點中,至少有一個和Group Master保持徹底同步,剩餘的Group Slave和Group Master可以達到最終一致,它們之間以「半同步」模式工做保證最終一致性;

      (3)每個group的健康狀態由Global Master來管理,Global Master向group發送管理信息,並保證有一個Group Master正常工做,若Group Master宕機,在該group內經過分佈式選舉產生新的Group Master頂替原來宕機的機器繼續工做,但仍然有一小段時間須要中斷寫服務來切換新的Group Master;

      (4)每個group的底層是實際的存儲系統,File system,它們是無狀態的,即,由分佈式選舉產生的Group Master能夠在原來的File system上繼續工做;

      (5)Client的上端可認爲是Web請求,Client在「首次」進行數據讀寫時,向Global Master查詢相應的group信息,並將其緩存,後續將直接與相應的group進行通訊;爲避免大量「首次」查詢沖垮Global Master,在Client與Global Master之間增長DNS負載均衡,可由Global Slave分擔部分查詢工做;

    (6)當Client已經擁有足夠的group信息時,它將直接與group通訊進行工做,從而真正的壓力和流量由各個group分擔,並處理完成須要的工做。

       好了,如今咱們的「山推」系統設計完成了,可是要將它編碼實現,還有很遠的路要走,細枝末節的問題也會暴露更多。若是該系統用於線上計算,若有大量的Map-Reduce運行於group中,系統將會更復雜,由於此時不光考慮的數據的存儲同步問題,操做也須要同步。如今來檢驗下咱們設計的「山推」系統,主要分佈式指標:

       一致性:如前文所述,Global機器強一致性,Group機器最終一致性;

       可用性:Global機器保證了HA(高可用性),Group機器則不保證,但知足了分區容錯性;

       備份Replication:Global機器採用徹底同步,Group機器則是半同步模式,均可以進行橫向擴展;

       故障恢復:如前文所述,Global機器徹底同步,故障可不受中斷由slave恢復工做,但Group機器採用分佈式選舉和最終一致性,故障時有較短期的寫服務須要中斷並切換到slave機器,但讀服務可不中斷。

       還有其餘一些指標,這裏就再也不多說了。還有一些細節,須要提一下,好比以前的評論中有同窗提到,group中master掛時,由slave去頂替,但這樣一來該group內其餘全部slave須要分擔以前成這新master的這個slave的壓力,有可能繼續掛掉而形成雪崩。針對此種狀況,可採用以下作法:即在一個group內,至少還存在一個真正作「備份」用途的slave,平時不抗壓力,只同步數據,這樣當出現上述狀況時,可由該備份slave來頂替成爲新master的那個slave,從而避免雪崩效應。不過這樣一來,就有新的問題,因爲備份slave平時不抗壓力,加入抗壓力後必然產生必定的數據遷移,數據遷移也是一個較麻煩的問題。常採用的分攤壓力作法如一致性Hash算法(環狀Hash),可將新結點加入對整個group的影響降到較小的程度。

        另外,還有一個較爲棘手的問題,就是系統的日誌處理,主要是系統宕機後如何恢復以前的操做日誌。比較常見的方法是對日誌做快照(Snapshot)和回放點(checkpoint),並採用Copy-on-write方式按期將日誌做snapshot存儲,當發現宕機後,找出對應的回放點並恢復以後的snapshot,但此時仍可能有新的寫操做到達,併產生不一致,這裏主要依靠Copy-on-write來同步。

       最後再說說圖中的Client部分。顯然這個模塊就是面向Web的接口,後面鏈接咱們的「山推」系統,它能夠包含諸多業務邏輯,最重要的,是要緩存group的信息。在Client和Web之間,還能夠有諸如Nginx之類的反向代理服務器存在,作進一步性能提高,這已經超出了本文的範疇,但咱們必須明白的是,一個高併發高性能的網站,對性能的要求是從起點開始的,何爲起點,即用戶的瀏覽器。

       如今,讓咱們來看看GFS的設計:

 

       很明顯,這麼牛的系統我是設計不出來的,咱們的「山推」,就是在學習GFS + Bigtable的主要思想。說到這,也必須提一句,可能我文章中,名詞擺的有點多了,如NWR,分佈式選舉,Paxos包括Copy-on-write等,有興趣的同窗可自行google瞭解。由於說實在的,這些概念我也無法講透徹,只是只知其一;不知其二。另外,你們可參考一些分佈式項目的設計,如Cassandra,包括淘寶的Oceanbase等,以加深理解。

1、前言

在計算機領域,當單機性能達到瓶頸時,有兩種方式能夠解決性能問題,一是堆硬件,進一步提高配置,二是分佈式,水平擴展。固然,二者都是同樣的燒錢。
今天聊聊我所理解的分佈式系統的架構思路。

2、分佈式系統的兩種方式

平時接觸到的分佈式系統有不少種,好比分佈式文件系統,分佈式數據庫,分佈式WebService,分佈式計算等等,面向的情景不一樣,但分佈式的思路是不是同樣的呢?

1.簡單的例子

假設咱們有一臺服務器,它能夠承擔1百萬/秒的請求,這個請求能夠的是經過http訪問網頁,經過tcp下載文件,jdbc執行sql,RPC調用接口…,如今咱們有一條數據的請求是2百萬/秒,很顯然服務器hold不住了,會各類拒絕訪問,甚至崩潰,宕機,怎麼辦呢。一臺機器解決不了的問題,那就兩臺。因此咱們加一臺機器,每臺承擔1百萬。若是請求繼續增長呢,兩臺解決不了的問題,那就三臺唄。這種方式咱們稱之爲水平擴展。如何實現請求的平均分配即是負載均衡了。

另外一個栗子,咱們如今有兩個數據請求,數據1 90萬,數據2 80萬,上面那臺機器也hold不住,咱們加一臺機器來負載均衡一下,每臺機器處理45萬數據1和40萬數據2,可是平分太麻煩,不如一臺處理數據1,一臺處理數據2,一樣能解決問題,這種方式咱們稱之爲垂直拆分

水平擴展垂直拆分是分佈式架構的兩種思路,但並非一個二選一的問題,更多的是兼併合用。下面介紹一個實際的場景。這也是許多互聯網的公司架構思路。

2.實際的例子

我此時所在的公司的計算機系統很龐大,天然是一個整的分佈式系統,爲了方便組織管理,公司將整個技術部按業務和平臺拆分爲部門,訂單的,會員的,商家的等等,每一個部門有本身的web服務器集羣,數據庫服務器集羣,經過同一個網站訪問的連接可能來自於不一樣的服務器和數據庫,對網站及底層對數據庫的訪問被分配到了不一樣的服務器集羣,這個即是典型的按業務作的垂直拆分,每一個部門的服務器在hold不住時,會有彈性的擴展,這即是水平擴展

在數據庫層,有些表很是大,數據量在億級,若是隻是純粹的水平的擴展並不必定最好,若是對錶進行拆分,好比能夠按用戶id進行水平拆表,經過對id取模的方式,將用戶劃分到多張表中,同時這些表也能夠處在不一樣的服務器。按業務的垂直拆庫和按用戶水平拆表是分佈式數據庫中通用的解決方案。

3、負載均衡

前面咱們談到了分佈式來解決性能問題,但其附帶的問題是怎麼分佈,即如何負載均衡。這裏要解決的問題是當客戶端請求時,應該讓它請求分佈式系統中哪一臺服務器,一般的作法是經過一臺中間服務器來給客服端分配目標服務器。

這裏一樣拿兩個不一樣的分佈式系統作說明,下圖左邊是分佈式文件系統FastDFS,右邊是一個用於分佈式的RPC中間件。

  • FastDFS的一次文件下載請求過程是這樣的
    1.client詢問tracker能夠下載指定文件的storage;
    2.tracker返回一臺可用的storage;
    3.client直接和storage通訊完成文件下載。

其中tracker即是負載均衡服務器,storage是存儲文件和處理上傳下載請求的服務器。

  • 而另外一個RPC中間件Hedwig也是相似的
    1.client詢問zookeeper哪臺server能夠執行請求;
    2.zookeeper返回一臺可用server;
    3.client直接與service完成一次RPC。

zookeeper是分佈式系統中一個負載均衡框架,google的chubby的一個開源實現,是是Hadoop和Hbase的重要組件。

一樣的在http中,常據說的nginx也是一個負載均衡服務器,它面向的是分佈式web服務器。至於具體的負載均衡算法輪詢,hash等這裏就不深刻了。

4、同步

 

 

分佈式系統中,解決了負載均衡的問題後,另一個問題就是數據的一致性了,這個就須要經過同步來保障。根據不一樣的場景和需求,同步的方式也是有選擇的。

在分佈式文件系統中,好比商品頁面的圖片,若是進行了修改,同步要求並不高,就算有數秒甚至數分鐘的延遲都是能夠接受的,由於通常不會產生損失性的影響,所以能夠簡單的經過文件修改的時間戳,隔必定時間掃描同步一次,能夠犧牲一致性來提升效率。

但銀行中的分佈式數據庫就不同了,一丁點不一樣步就是沒法接受的,甚至能夠經過加鎖等犧牲性能的方式來保障徹底的一致。

在一致性算法中paxos算法是公認的最好的算法,chubby、zookeeper中paxos是它保證一致性的核心。這個算法比較難懂,我目前也沒弄懂,這裏就不深刻了。

5、結語

接觸過這麼多分佈式系統後發現,它們的設計思路是如此的類似,這或許就是萬法歸一吧。

擴展閱讀

做者:弓長張
連接:https://www.zhihu.com/question/19699884/answer/32253702
來源:知乎
著做權歸做者全部,轉載請聯繫做者得到受權。
 

Q1.爲甚麼會有分佈式框架的出現? A:計算量和數據量的爆炸,好比要你統計10個1MB文本文件裏的相異單詞數目,很簡單,一個一個讀出來計算就能夠實現,10個文本文件最多10MB,能夠徹底讀到單機(普通我的計算機)的內存裏。或者讓你對一組數據進行很簡單的幾回四則運算,這些計算和任務在普通機器上都可以很流暢運行。可是,換一種狀況,若是要你讀取100000個文件的相異單詞數目,那麼單單總文件大小就有100GB,普通機器在這個任務上就遇到兩個瓶頸,第一個是從外存儲器到內存的,一個是從內存到CPU的,這樣的任務在通常機器上沒法再可接受的時間內完成。另外一個狀況,你要對一組數據(數據量不是很大)進行數千億(極大量)的迭代複雜運算,單單靠一個普通機器的CPU和內存也不能在可接受的時間內完成。因此人們爲了解決這些狀況,才推出了分佈式這個東西。 Q2分佈式框架如何解決以上問題的? A:我說簡單點,就是經過縱向和橫向的並行實現的。若是1000臺機器(節點)同時處理這個任務,每臺機器只會去處理10個文件了,這個道理是很簡單易懂的,這就是橫向上的並行。而縱向上的並行主要是靠神馬創建緩衝池,分解任務之類實現的,道理很簡單,爲了達到最大效率,就要讓CPU何內存在任什麼時候候都最大發揮,通常的方法可能會出現一些時候IO空閒,運算負載和一些時候運算空閒,IO負載的問題,縱向的優化就是要讓IO和運算任什麼時候候都不空閒。 Q3分佈式框架的基本核心問題。 A:1.對於實際任務來講,橫向的並行每每不是把數據文件分紅若干份運算那麼簡單。 2.分佈式要解決的問題每每是能夠線性分割的。 3.如今分佈式解決的主要問題其實仍是對於大數據量的解決

相關文章
相關標籤/搜索