高併發服務端分佈式系統設計概要(上)html
======張峻崇 原創。轉載請註明出處。======服務器
又是快一年沒寫博客了,2013年也只剩尾巴,也不知道今年都忙了些什麼。寫這篇文章的目的,主要是把今年以來學習的一些東西積澱下來,同時做爲以前文章《高性能分佈式計算與存儲系統設計概要》的補充與提高,然而本人水平很是有限,回頭看以前寫的文章也有許多不足,甚至是錯誤,但願同窗們看到了錯誤多多見諒,更歡迎與我討論並指正。併發
好了,下面開始說咱們今天要設計的系統。異步
這個系統的目標很明確,針對千萬級以上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。spa
下面來講一個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通知其更新,最終與其它全部結點同步。(固然,「偷」數據所用的時間並不樂觀,一般在小時級別)
中篇連接:http://www.cnblogs.com/ccdev/p/3340484.html
下篇連接: http://www.cnblogs.com/ccdev/p/3341234.html