講給普通人聽(tīng)的分布式數(shù)據(jù)存儲(chǔ)
關(guān)系型數(shù)據(jù)庫(kù)到底有什么問(wèn)題?
正如你們中的很多人可能已經(jīng)知道的,關(guān)系型數(shù)據(jù)庫(kù)(RDB)技術(shù)自從1970年代就已經(jīng)存在,直到1990年代末一直是結(jié)構(gòu)化存儲(chǔ)的事實(shí)標(biāo)準(zhǔn)。RDB幾十年來(lái)很出色地支持了高度一致性事務(wù)的工作負(fù)載,并依然保持強(qiáng)勁。隨著時(shí)間的推移,該項(xiàng)古老的技術(shù)為應(yīng)對(duì)客戶的需求獲得了新的能力,比如BLOB存儲(chǔ)、XML/文檔存儲(chǔ)、全文檢索、在數(shù)據(jù)庫(kù)中執(zhí)行代碼、使用星形數(shù)據(jù)結(jié)構(gòu)的數(shù)據(jù)倉(cāng)庫(kù)、以及地理空間擴(kuò)展。只要一切都能擠進(jìn)關(guān)系型數(shù)據(jù)結(jié)構(gòu)的定義中,并且適合于單機(jī),就可以在關(guān)系型數(shù)據(jù)庫(kù)中實(shí)現(xiàn)。
然后,互聯(lián)網(wǎng)的商業(yè)化發(fā)生了,并且徹底改變了一切,使得關(guān)系型數(shù)據(jù)庫(kù)不再能夠滿足所有的存儲(chǔ)需求。相比于一致性,可用性、性能和擴(kuò)展正在變得同樣重要——有時(shí)甚至更重要。
性能一直很重要,但是隨著互聯(lián)網(wǎng)商業(yè)化的出現(xiàn),改變的是規(guī)模。事實(shí)證明,要達(dá)到規(guī)?;男阅?,要求的技巧和技術(shù)是前互聯(lián)網(wǎng)時(shí)代無(wú)法接受的。關(guān)系型數(shù)據(jù)庫(kù)圍繞著ACID(原子性Atomicity、一致性Consistency、隔離性Isolation和持久性Durability)的概念而建立,實(shí)現(xiàn)ACID最簡(jiǎn)單的方法就是把一切保持在單機(jī)上。因此,傳統(tǒng)的RDB規(guī)?;姆椒ㄊ谴怪睌U(kuò)展(scale up),用白話說(shuō),就是使用更大的機(jī)器。
哦-哦,我想我需要一臺(tái)更大的機(jī)器使用一臺(tái)更大的機(jī)器的解決方案一直很好,直到互聯(lián)網(wǎng)帶來(lái)的負(fù)載大到單機(jī)無(wú)法處理。這迫使工程師們想出巧妙的技術(shù)來(lái)克服單機(jī)的限制。有許多不同的方法,各有其優(yōu)缺點(diǎn):主—副、集群、表聯(lián)合與分區(qū)(table federation and partitioning)、水平分區(qū)(sharding,可以認(rèn)為是分區(qū)的特例)。
導(dǎo)致數(shù)據(jù)存儲(chǔ)選項(xiàng)增加的另外一個(gè)因素是可用性。前互聯(lián)網(wǎng)時(shí)代的系統(tǒng),其用戶通常是來(lái)自組織的內(nèi)部,這就有可能在非工作時(shí)段設(shè)置有計(jì)劃的停機(jī)時(shí)間,甚至計(jì)劃外的宕機(jī)也只會(huì)造成有限的影響。商業(yè)化互聯(lián)網(wǎng)也改變了這一點(diǎn):現(xiàn)在每個(gè)能夠訪問(wèn)互聯(lián)網(wǎng)的人都是潛在用戶,所以計(jì)劃外的宕機(jī)會(huì)造成很可能更大的影響,而且互聯(lián)網(wǎng)的全球性導(dǎo)致很難確定非工作時(shí)段,并安排有計(jì)劃的停機(jī)。
我曾探討了冗余在實(shí)現(xiàn)高可用性中所起的作用。不過(guò),當(dāng)應(yīng)用到數(shù)據(jù)存儲(chǔ)層時(shí),冗余帶來(lái)了一系列新的有趣的挑戰(zhàn)。在數(shù)據(jù)庫(kù)層應(yīng)用冗余最常用的方式是主/副配置。
這個(gè)看似簡(jiǎn)單的設(shè)置,在與傳統(tǒng)的單機(jī)關(guān)系型數(shù)據(jù)庫(kù)比較時(shí),有一個(gè)巨大的差異:我們現(xiàn)在有網(wǎng)絡(luò)隔離的多臺(tái)機(jī)器。當(dāng)數(shù)據(jù)庫(kù)的寫(xiě)操作發(fā)生時(shí),我們現(xiàn)在要決定何時(shí)認(rèn)為它完成了:只要保存到主數(shù)據(jù)庫(kù),或者只要保存到副數(shù)據(jù)庫(kù)(或者甚至是n個(gè)副數(shù)據(jù)庫(kù),如果我們想要獲得更高的可用性--欲知增加另一臺(tái)機(jī)器對(duì)整個(gè)可用性的影響,請(qǐng)參看本博客系列的第一部分)。如果我們決定保存到主數(shù)據(jù)庫(kù)就足夠了,在復(fù)制數(shù)據(jù)之前如果主數(shù)據(jù)庫(kù)失效,我們要承擔(dān)丟失數(shù)據(jù)的風(fēng)險(xiǎn)。如果我們決定等到數(shù)據(jù)復(fù)制完成,我們就要接受延遲的代價(jià)。在副數(shù)據(jù)庫(kù)宕機(jī)的罕見(jiàn)情況下,我們需要決定是繼續(xù)接受寫(xiě)操作的請(qǐng)求,還是拒絕它。
因此,我們從一個(gè)默認(rèn)一致性的世界,進(jìn)入了一個(gè)一致性是一種選擇的世界。在這個(gè)世界里,我們可以選擇接受所謂的最終一致性,即,狀態(tài)在多個(gè)節(jié)點(diǎn)之間復(fù)制,但是并非每個(gè)節(jié)點(diǎn)都有整個(gè)狀態(tài)的完整視圖。在我們上面的示例配置中,如果我們選擇認(rèn)為達(dá)到主數(shù)據(jù)庫(kù)就是寫(xiě)操作完成(或者到達(dá)主數(shù)據(jù)庫(kù)和任一副數(shù)據(jù)庫(kù),但不一定是兩個(gè)副數(shù)據(jù)庫(kù)),那么我們就是選擇了最終一致性。最終,因?yàn)槊總€(gè)寫(xiě)操作會(huì)被復(fù)制到每個(gè)副數(shù)據(jù)庫(kù)。但是在任一時(shí)間點(diǎn),如果我們查詢某一個(gè)副數(shù)據(jù)庫(kù),我們無(wú)法保證它包含截止到那個(gè)時(shí)刻為止的所有寫(xiě)操作。
讓我們?cè)囋囆碌腃AP理論總而言之,當(dāng)數(shù)據(jù)存儲(chǔ)被復(fù)制(也稱為分隔(partitioned))時(shí),系統(tǒng)的狀態(tài)被分散。這意味著我們離開(kāi)了舒適的ACID領(lǐng)域,進(jìn)入CAP的美麗新世界。CAP理論是由加州伯克利分校的Eric Brewer博士在2000年提出的。它最簡(jiǎn)單的形式是這樣的:一個(gè)分布式系統(tǒng)必須在一致性、可用性和分隔容忍度(Partition Tolerance)之間取舍,并且只能做到三者中的兩者。
CAP理論把關(guān)于數(shù)據(jù)存儲(chǔ)的討論擴(kuò)展到超出ACID的范圍,激發(fā)了許多非關(guān)系型數(shù)據(jù)庫(kù)技術(shù)的誕生。在提出他的CAP理論的10年之后,Brewer博士發(fā)表了一份聲明,澄清他最初的“三選二”的觀點(diǎn)被極大地簡(jiǎn)化,是為了引起討論,并有助于超越ACID。不過(guò),這種極大的簡(jiǎn)化,引發(fā)了無(wú)數(shù)的曲解和誤會(huì)。在對(duì)CAP更精細(xì)的解釋中,所有三個(gè)維度應(yīng)當(dāng)理解為范圍,而不是布爾值。此外,應(yīng)當(dāng)理解,分布式系統(tǒng)大部分時(shí)間工作在非分隔模式,在這種情況下,需要做出一致性和性能/延遲之間的折中。在分隔真的發(fā)生的罕見(jiàn)情況下,系統(tǒng)必須在一致性和可用性之間做出選擇。
聯(lián)系到我們之前的主/副例子,如果選擇認(rèn)為只有當(dāng)數(shù)據(jù)在所有地方被復(fù)制(也稱作同步復(fù)制)之后寫(xiě)操作才算完成,我們就是以寫(xiě)操作延遲為代價(jià)選擇了一致性。另一方面,如果選擇認(rèn)為一旦數(shù)據(jù)保存到主數(shù)據(jù)庫(kù)中,就認(rèn)為寫(xiě)操作完成,并讓復(fù)制在后臺(tái)進(jìn)行(也稱作異步復(fù)制),我們就是以犧牲一致性為代價(jià)選擇了性能。
當(dāng)網(wǎng)絡(luò)分隔發(fā)生時(shí),分布式系統(tǒng)進(jìn)入特殊的分隔模式,在一致性和可用性之間取舍?;氐轿覀兊睦樱憾鄠€(gè)副數(shù)據(jù)庫(kù)在失去與主數(shù)據(jù)庫(kù)的連接之后,可能仍然繼續(xù)提供查詢服務(wù),就是以犧牲一致性為代價(jià)選擇了可用性。要么,我們可以選擇,主數(shù)據(jù)庫(kù)如果失去與副數(shù)據(jù)庫(kù)的連接,就應(yīng)當(dāng)停止接受寫(xiě)操作的請(qǐng)求,因此就是以犧牲可用性為代價(jià)選擇了一致性。在商業(yè)化互聯(lián)網(wǎng)時(shí)代,選擇一致性通常意味著收入的損失,所以很多系統(tǒng)選擇可用性。在這種情況下,當(dāng)系統(tǒng)恢復(fù)到正常狀態(tài)時(shí),它可以進(jìn)入恢復(fù)模式,所有積累的不一致性得到解決和復(fù)制。
趁我們還在談?wù)摶謴?fù)模式,值得說(shuō)一說(shuō)一種稱為主—主(或主動(dòng)—主動(dòng))的分布式數(shù)據(jù)存儲(chǔ)配置。在這種設(shè)置中,寫(xiě)操作可以發(fā)送到多個(gè)節(jié)點(diǎn),然后再互相復(fù)制。在這樣的系統(tǒng)中,即使是正常的模式也變得復(fù)雜了。因?yàn)?,如果?duì)同一條數(shù)據(jù)的兩個(gè)更新在大致相同的時(shí)間發(fā)生在兩個(gè)不同的主節(jié)點(diǎn)上,要如何協(xié)調(diào)呢?不僅如此,如果這樣的系統(tǒng)不得不從一個(gè)分隔的狀態(tài)恢復(fù),事情就變得更糟了。雖然有可能存在可行的主—主配置,而且也有一些產(chǎn)品使之更容易,我的建議是除非絕對(duì)必要,否則盡量避免。有很多方法可以實(shí)現(xiàn)性能和可用性的良好平衡,而不必需要負(fù)擔(dān)主—主配置的高復(fù)雜度性的成本。
許多現(xiàn)代數(shù)據(jù)存儲(chǔ)的常見(jiàn)模式提供的性能/規(guī)模和可用性良好搭配的一種常見(jiàn)方法,是結(jié)合分隔和復(fù)制形成一種配置(或者說(shuō)是模式)。這有時(shí)被稱為分隔的副本集合(partitioned replica set)。
不論是Hadoop、Cassandra或者M(jìn)ongoDB集群,所有這些基本上都符合這種模式,許多AWS數(shù)據(jù)服務(wù)也是如此。讓我們了解一下分隔的副本集合的一些共同特征:
數(shù)據(jù)是跨多個(gè)節(jié)點(diǎn)(或者多個(gè)節(jié)點(diǎn)集群)分隔的(即,分開(kāi)的)。沒(méi)有單一分區(qū)擁有所有的數(shù)據(jù)。單個(gè)寫(xiě)操作只發(fā)送到一個(gè)分區(qū)。多個(gè)寫(xiě)操作有可能發(fā)送到多個(gè)分區(qū),因此應(yīng)當(dāng)彼此獨(dú)立。復(fù)雜的、事務(wù)性、多條記錄(因此可能涉及多分區(qū))的寫(xiě)操作應(yīng)當(dāng)避免,因?yàn)檫@樣可能影響整個(gè)系統(tǒng)。
單個(gè)分區(qū)能夠處理的最大數(shù)據(jù)量可能成為潛在的瓶頸。如果一個(gè)分區(qū)達(dá)到它的帶寬上限,增加更多的分區(qū)以及拆分橫跨其間的流量,有助于解決該問(wèn)題。因此,可以通過(guò)增加更多的分區(qū)來(lái)擴(kuò)展這種類型的系統(tǒng)。
一個(gè)分區(qū)的索引(key)用來(lái)分配各個(gè)分區(qū)的數(shù)據(jù)。你需要小心選擇分區(qū)的索引,這樣讓讀操作和寫(xiě)操作盡可能平均“分布”在所有的分區(qū)。如果讀/寫(xiě)操作發(fā)生聚集,這些操作可能超出某個(gè)分區(qū)的帶寬,進(jìn)而影響整個(gè)系統(tǒng)的性能,而其它分區(qū)則并未充分利用。這被稱為“熱分區(qū)”問(wèn)題。
數(shù)據(jù)在多臺(tái)主機(jī)之間復(fù)制。這可以是,每個(gè)分區(qū)是完全分開(kāi)的副本集合,或者在同一組主機(jī)之上的多個(gè)副本集合。一條數(shù)據(jù)被復(fù)制的次數(shù)通常被稱為復(fù)制因子。
這樣的配置擁有內(nèi)置的高可用性:數(shù)據(jù)被復(fù)制到多個(gè)主機(jī)。理論上,若干小于復(fù)制因子數(shù)量的主機(jī)發(fā)生故障,不會(huì)影響整個(gè)系統(tǒng)的可用性。
所有這些好處,以及內(nèi)置的可擴(kuò)展性和高可用性,伴隨著相應(yīng)的代價(jià):這不再是你的瑞士軍刀,單機(jī)的關(guān)系型數(shù)據(jù)庫(kù)管理系統(tǒng)(RDBMS)了。這是復(fù)雜的系統(tǒng),有很多需要管理的可變動(dòng)的部分和需要微調(diào)的參數(shù)。需要專業(yè)知識(shí)來(lái)設(shè)置、配置和維護(hù)這些系統(tǒng)。此外,需要監(jiān)測(cè)和報(bào)警的基礎(chǔ)設(shè)施來(lái)確保它們的正常運(yùn)作。你當(dāng)然可以自己做,但不容易,你可能短時(shí)間無(wú)法搞定。
豐富的數(shù)據(jù)存儲(chǔ),雖然引起一些選擇困難,但其實(shí)是好事。我們只需超越傳統(tǒng)的整個(gè)系統(tǒng)只有單個(gè)數(shù)據(jù)存儲(chǔ)的想法,接受系統(tǒng)中使用多種數(shù)據(jù)存儲(chǔ)、每個(gè)為它最適合的工作負(fù)載提供服務(wù)這樣的思維方式。例如,我們可以使用下面的組合:
高性能攝入隊(duì)列,來(lái)獲取輸入點(diǎn)擊流量
基于Hadoop的點(diǎn)擊流量處理系統(tǒng)
基于云的對(duì)象存儲(chǔ),用來(lái)低成本、長(zhǎng)期地存儲(chǔ)經(jīng)過(guò)壓縮的日常點(diǎn)擊流量摘要
保存元數(shù)據(jù)的關(guān)系型數(shù)據(jù)庫(kù),可供我們用于充實(shí)點(diǎn)擊流量的數(shù)據(jù)
用于分析的數(shù)據(jù)倉(cāng)庫(kù)集群
用于自然語(yǔ)言查詢的搜索集群
上面所有這些都可以是某個(gè)單一子系統(tǒng)的組成部分,比如叫做網(wǎng)站分析平臺(tái)。
總結(jié)商業(yè)化互聯(lián)網(wǎng)帶來(lái)擴(kuò)展和可用性的需求,而RDBMS這樣的瑞士軍刀再也無(wú)法滿足這樣的需求。
對(duì)數(shù)據(jù)存儲(chǔ)增加水平擴(kuò)展和冗余加大了系統(tǒng)復(fù)雜度,使得ACID更加難以保證,迫使我們按照CAP理論考慮取舍,創(chuàng)造了許多優(yōu)化和專業(yè)化的有趣機(jī)會(huì)。
在系統(tǒng)中使用多個(gè)數(shù)據(jù)存儲(chǔ),每個(gè)為與其最適當(dāng)?shù)墓ぷ髫?fù)載提供服務(wù)。
現(xiàn)代數(shù)據(jù)存儲(chǔ)是復(fù)雜的系統(tǒng),要求特殊的知識(shí)和管理開(kāi)銷。