注:書本鏈接:GitHub - Vonng/ddia: 《Designing Data-Intensive Application》DDIA中文翻譯
注:譯者文本網(wǎng)站:簡介 · ddia-cn
注:如有侵權(quán)棒厘,請聯(lián)系刪除
第五章:復(fù)制
- 使得數(shù)據(jù)與用戶在地理上接近(從而減少延遲)
- 即使系統(tǒng)的一部分出現(xiàn)故障传藏,系統(tǒng)也能繼續(xù)工作(從而提高可用性)
- 伸縮可以接受讀請求的機(jī)器數(shù)量(從而提高讀取吞吐量)
如果復(fù)制中的數(shù)據(jù)不會(huì)隨時(shí)間而改變粮揉,那復(fù)制就很簡單:將數(shù)據(jù)復(fù)制到每個(gè)節(jié)點(diǎn)一次就萬事大吉。復(fù)制的困難之處在于處理復(fù)制數(shù)據(jù)的 變更(change),這就是本章所要講的廉丽。我們將討論三種流行的變更復(fù)制算法:單領(lǐng)導(dǎo)者(single leader较幌,單主),多領(lǐng)導(dǎo)者(multi leader少欺,多主) 和 無領(lǐng)導(dǎo)者(leaderless喳瓣,無主)。幾乎所有分布式數(shù)據(jù)庫都使用這三種方法之一赞别。
一畏陕、領(lǐng)導(dǎo)者與追隨者
存儲(chǔ)了數(shù)據(jù)庫拷貝的每個(gè)節(jié)點(diǎn)被稱為 副本(replica) 。
最常見的解決方案被稱為 基于領(lǐng)導(dǎo)者的復(fù)制(leader-based replication) (也稱 主動(dòng)/被動(dòng)(active/passive) 復(fù)制或 主/從(master/slave) 復(fù)制)仿滔。
1、同步復(fù)制與異步復(fù)制
復(fù)制系統(tǒng)的一個(gè)重要細(xì)節(jié)是:復(fù)制是 同步(synchronously) 發(fā)生的還是 異步(asynchronously) 發(fā)生的崎页。(在關(guān)系型數(shù)據(jù)庫中這通常是一個(gè)配置項(xiàng)鞠绰,其他系統(tǒng)則通常硬編碼為其中一個(gè))。
將所有從庫都設(shè)置為同步的是不切實(shí)際的:任何一個(gè)節(jié)點(diǎn)的中斷都會(huì)導(dǎo)致整個(gè)系統(tǒng)停滯不前飒焦。實(shí)際上蜈膨,如果在數(shù)據(jù)庫上啟用同步復(fù)制,通常意味著其中 一個(gè) 從庫是同步的,而其他的從庫則是異步的丈挟。如果該同步從庫變得不可用或緩慢刁卜,則將一個(gè)異步從庫改為同步運(yùn)行。這保證你至少在兩個(gè)節(jié)點(diǎn)上擁有最新的數(shù)據(jù)副本:主庫和同步從庫曙咽。這種配置有時(shí)也被稱為 半同步(semi-synchronous)【7】蛔趴。
2、設(shè)置新從庫
- 在某個(gè)時(shí)刻獲取主庫的一致性快照(如果可能例朱,不必鎖定整個(gè)數(shù)據(jù)庫)孝情。大多數(shù)數(shù)據(jù)庫都具有這個(gè)功能,因?yàn)樗莻浞荼匦璧娜鬣汀τ谀承﹫鼍绑锏矗赡苄枰谌焦ぞ撸缬糜?MySQL 的 innobackupex【12】渔隶。
- 將快照復(fù)制到新的從庫節(jié)點(diǎn)羔挡。
- 從庫連接到主庫,并拉取快照之后發(fā)生的所有數(shù)據(jù)變更间唉。這要求快照與主庫復(fù)制日志中的位置精確關(guān)聯(lián)绞灼。該位置有不同的名稱,例如 PostgreSQL 將其稱為 日志序列號(log sequence number呈野,LSN)低矮,MySQL 將其稱為 二進(jìn)制日志坐標(biāo)(binlog coordinates)。
- 當(dāng)從庫處理完快照之后積累的數(shù)據(jù)變更被冒,我們就說它 趕上(caught up) 了主庫军掂,現(xiàn)在它可以繼續(xù)及時(shí)處理主庫產(chǎn)生的數(shù)據(jù)變化了。
3昨悼、處理宕機(jī)節(jié)點(diǎn)
(1)從庫失效:追趕恢復(fù)
(2)主庫失效:故障切換
節(jié)點(diǎn)故障蝗锥、不可靠的網(wǎng)絡(luò)、對副本一致性幔戏、持久性玛追、可用性和延遲的權(quán)衡,這些問題實(shí)際上是分布式系統(tǒng)中的基本問題闲延。
4痊剖、復(fù)制日志的實(shí)現(xiàn)
(1)基于語句的復(fù)制
(2)傳輸預(yù)寫式日志(WAL)
(3)邏輯日志復(fù)制(基于行)
(4)基于觸發(fā)器的復(fù)制
5、復(fù)制延遲問題
如果停止寫入數(shù)據(jù)庫并等待一段時(shí)間垒玲,從庫最終會(huì)趕上并與主庫保持一致陆馁。出于這個(gè)原因,這種效應(yīng)被稱為 最終一致性(eventual consistency)
(1)讀自己寫入的數(shù)據(jù)
如果用戶在寫入后馬上就查看數(shù)據(jù)合愈,則新數(shù)據(jù)可能尚未到達(dá)副本叮贩。對用戶而言击狮,看起來好像是剛提交的數(shù)據(jù)丟失了。
在這種情況下益老,我們需要 寫后讀一致性(read-after-write consistency)彪蓬,也稱為 讀己之寫一致性(read-your-writes consistency)
(2)單調(diào)讀
用戶首先從新副本讀取,然后從舊副本讀取捺萌。時(shí)間看上去回退了档冬。(時(shí)光倒流(moving backward in time))
單調(diào)讀(monotonic reads)【23】可以保證這種異常不會(huì)發(fā)生。這是一個(gè)比 強(qiáng)一致性(strong consistency) 更弱桃纯,但比 最終一致性(eventual consistency) 更強(qiáng)的保證酷誓。
(3)一致前綴讀
一致前綴讀(consistent prefix reads)【23】。這個(gè)保證的意思是說:如果一系列寫入按某個(gè)順序發(fā)生态坦,那么任何人讀取這些寫入時(shí)盐数,也會(huì)看見它們以同樣的順序出現(xiàn)。
這是 分區(qū)(partitioned) 或 分片(sharded) 數(shù)據(jù)庫中的一個(gè)特殊問題伞梯,我們將在 第六章 中討論分區(qū)數(shù)據(jù)庫玫氢。如果數(shù)據(jù)庫總是以相同的順序應(yīng)用寫入,而讀取總是看到一致的前綴壮锻,那么這種異常不會(huì)發(fā)生琐旁。但是在許多分布式數(shù)據(jù)庫中,不同的分區(qū)獨(dú)立運(yùn)行猜绣,因此不存在 全局的寫入順序:當(dāng)用戶從數(shù)據(jù)庫中讀取數(shù)據(jù)時(shí),可能會(huì)看到數(shù)據(jù)庫的某些部分處于較舊的狀態(tài)敬特,而某些則處于較新的狀態(tài)掰邢。
注:此處與日常使用的kafka保障消息消費(fèi)順序性觀念相近
(4)復(fù)制延遲的解決方案
如果應(yīng)用程序開發(fā)人員不必?fù)?dān)心微妙的復(fù)制問題,并可以信賴他們的數(shù)據(jù)庫 “做了正確的事情”伟阔,那該多好呀辣之。這就是 事務(wù)(transaction) 存在的原因:數(shù)據(jù)庫通過事務(wù)提供強(qiáng)大的保證,所以應(yīng)用程序可以更加簡單皱炉。
單節(jié)點(diǎn)事務(wù)已經(jīng)存在了很長時(shí)間怀估。然而在走向分布式(復(fù)制和分區(qū))數(shù)據(jù)庫時(shí),許多系統(tǒng)放棄了事務(wù)合搅,聲稱事務(wù)在性能和可用性上的代價(jià)太高多搀,并斷言在可伸縮系統(tǒng)中最終一致性是不可避免的。這個(gè)敘述有一些道理灾部,但過于簡單了康铭,本書其余部分將提出更為細(xì)致的觀點(diǎn)。我們將在 第七章 和 第九章 回到事務(wù)的話題赌髓,并將在 第三部分 討論一些替代機(jī)制从藤。
4催跪、多主復(fù)制
(1)多主復(fù)制的應(yīng)用場景
運(yùn)維多個(gè)數(shù)據(jù)中心
需要離線操作的客戶端
協(xié)同編輯
(2)處理寫入沖突
同步與異步?jīng)_突檢測
避免沖突
-
收斂至一致的狀態(tài)
實(shí)現(xiàn)沖突合并解決有多種途徑:
- 給每個(gè)寫入一個(gè)唯一的 ID(例如時(shí)間戳、長隨機(jī)數(shù)夷野、UUID 或者鍵和值的哈希)懊蒸,挑選最高 ID 的寫入作為勝利者,并丟棄其他寫入悯搔。如果使用時(shí)間戳骑丸,這種技術(shù)被稱為 最后寫入勝利(LWW, last write wins)。雖然這種方法很流行鳖孤,但是很容易造成數(shù)據(jù)丟失【35】者娱。我們將在本章末尾的 檢測并發(fā)寫入 一節(jié)更詳細(xì)地討論 LWW。
- 為每個(gè)副本分配一個(gè)唯一的 ID苏揣,ID 編號更高的寫入具有更高的優(yōu)先級黄鳍。這種方法也意味著數(shù)據(jù)丟失。
- 以某種方式將這些值合并在一起 - 例如平匈,按字母順序排序框沟,然后連接它們(在 圖 5-7 中,合并的標(biāo)題可能類似于 “B/C”)增炭。
- 用一種可保留所有信息的顯式數(shù)據(jù)結(jié)構(gòu)來記錄沖突忍燥,并編寫解決沖突的應(yīng)用程序代碼(也許通過提示用戶的方式)。
自定義沖突解決邏輯
什么是沖突隙姿?
(3)多主復(fù)制拓?fù)?/h5>
復(fù)制拓?fù)?/strong>(replication topology)用來描述寫入操作從一個(gè)節(jié)點(diǎn)傳播到另一個(gè)節(jié)點(diǎn)的通信路徑梅垄。
5、無主復(fù)制
(1)當(dāng)節(jié)點(diǎn)故障時(shí)寫入數(shù)據(jù)庫
-
讀修復(fù)和反熵
在 Dynamo 風(fēng)格的數(shù)據(jù)存儲(chǔ)中經(jīng)常使用兩種機(jī)制:
-
讀修復(fù)(Read repair)
當(dāng)客戶端并行讀取多個(gè)節(jié)點(diǎn)時(shí)输玷,它可以檢測到任何陳舊的響應(yīng)队丝。例如,在 圖 5-10 中欲鹏,用戶 2345 獲得了來自副本 3 的版本 6 值和來自副本 1 和 2 的版本 7 值机久。客戶端發(fā)現(xiàn)副本 3 具有陳舊值赔嚎,并將新值寫回到該副本膘盖。這種方法適用于讀頻繁的值。
-
反熵過程(Anti-entropy process)
此外尤误,一些數(shù)據(jù)存儲(chǔ)具有后臺(tái)進(jìn)程侠畔,該進(jìn)程不斷查找副本之間的數(shù)據(jù)差異,并將任何缺少的數(shù)據(jù)從一個(gè)副本復(fù)制到另一個(gè)副本袄膏。與基于領(lǐng)導(dǎo)者的復(fù)制中的復(fù)制日志不同践图,此反熵過程不會(huì)以任何特定的順序復(fù)制寫入,并且在復(fù)制數(shù)據(jù)之前可能會(huì)有顯著的延遲沉馆。
-
讀寫的法定人數(shù)
(2)法定人數(shù)一致性的局限性
- 監(jiān)控陳舊度
(3)寬松的法定人數(shù)與提示移交
- 運(yùn)維多個(gè)數(shù)據(jù)中心
(4)檢測并發(fā)寫入
- 最后寫入勝利(丟棄并發(fā)寫入)
- “此前發(fā)生”的關(guān)系和并發(fā)(happen-before原則)
- 捕獲"此前發(fā)生"關(guān)系(happen-before)
- 合并并發(fā)寫入的值
- 版本向量
本章小結(jié)
在本章中码党,我們考察了復(fù)制的問題德崭。復(fù)制可以用于幾個(gè)目的:
-
高可用性
即使在一臺(tái)機(jī)器(或多臺(tái)機(jī)器,或整個(gè)數(shù)據(jù)中心)停機(jī)的情況下也能保持系統(tǒng)正常運(yùn)行
-
斷開連接的操作
允許應(yīng)用程序在網(wǎng)絡(luò)中斷時(shí)繼續(xù)工作
-
延遲
將數(shù)據(jù)放置在地理上距離用戶較近的地方揖盘,以便用戶能夠更快地與其交互
-
可伸縮性
通過在副本上讀眉厨,能夠處理比單機(jī)更大的讀取量
盡管是一個(gè)簡單的目標(biāo) - 在幾臺(tái)機(jī)器上保留相同數(shù)據(jù)的副本,但復(fù)制卻是一個(gè)非常棘手的問題兽狭。它需要仔細(xì)考慮并發(fā)和所有可能出錯(cuò)的事情憾股,并處理這些故障的后果。至少箕慧,我們需要處理不可用的節(jié)點(diǎn)和網(wǎng)絡(luò)中斷(這還不包括更隱蔽的故障服球,例如由于軟件錯(cuò)誤導(dǎo)致的靜默數(shù)據(jù)損壞)。
我們討論了復(fù)制的三種主要方法:
-
單主復(fù)制
客戶端將所有寫入操作發(fā)送到單個(gè)節(jié)點(diǎn)(主庫)颠焦,該節(jié)點(diǎn)將數(shù)據(jù)更改事件流發(fā)送到其他副本(從庫)斩熊。讀取可以在任何副本上執(zhí)行,但從庫的讀取結(jié)果可能是陳舊的伐庭。
-
多主復(fù)制
客戶端將每個(gè)寫入發(fā)送到幾個(gè)主庫節(jié)點(diǎn)之一粉渠,其中任何一個(gè)主庫都可以接受寫入。主庫將數(shù)據(jù)更改事件流發(fā)送給彼此以及任何從庫節(jié)點(diǎn)圾另。
-
無主復(fù)制
客戶端將每個(gè)寫入發(fā)送到幾個(gè)節(jié)點(diǎn)霸株,并從多個(gè)節(jié)點(diǎn)并行讀取,以檢測和糾正具有陳舊數(shù)據(jù)的節(jié)點(diǎn)集乔。
每種方法都有優(yōu)點(diǎn)和缺點(diǎn)去件。單主復(fù)制是非常流行的,因?yàn)樗苋菀桌斫馊怕罚恍枰獡?dān)心沖突解決箫攀。在出現(xiàn)故障節(jié)點(diǎn)、網(wǎng)絡(luò)中斷和延遲峰值的情況下幼衰,多主復(fù)制和無主復(fù)制可以更加健壯,其代價(jià)是難以推理并且僅提供非常弱的一致性保證缀雳。
復(fù)制可以是同步的渡嚣,也可以是異步的,這在發(fā)生故障時(shí)對系統(tǒng)行為有深遠(yuǎn)的影響肥印。盡管在系統(tǒng)運(yùn)行平穩(wěn)時(shí)異步復(fù)制速度很快识椰,但是要弄清楚在復(fù)制延遲增加和服務(wù)器故障時(shí)會(huì)發(fā)生什么,這一點(diǎn)很重要深碱。如果主庫失敗后你將一個(gè)異步更新的從庫提升為新的主庫腹鹉,那么最近提交的數(shù)據(jù)可能會(huì)丟失。
我們研究了一些可能由復(fù)制延遲引起的奇怪效應(yīng)敷硅,我們也討論了一些有助于決定應(yīng)用程序在復(fù)制延遲時(shí)的行為的一致性模型:
-
寫后讀一致性
用戶應(yīng)該總是能看到自己提交的數(shù)據(jù)功咒。
-
單調(diào)讀
用戶在看到某個(gè)時(shí)間點(diǎn)的數(shù)據(jù)后愉阎,他們不應(yīng)該再看到該數(shù)據(jù)在更早時(shí)間點(diǎn)的情況。
-
一致前綴讀
用戶應(yīng)該看到數(shù)據(jù)處于一種具有因果意義的狀態(tài):例如力奋,按正確的順序看到一個(gè)問題和對應(yīng)的回答榜旦。
最后,我們討論了多主復(fù)制和無主復(fù)制方法所固有的并發(fā)問題:因?yàn)樗麄冊试S多個(gè)寫入并發(fā)發(fā)生景殷,這可能會(huì)導(dǎo)致沖突溅呢。我們研究了一個(gè)數(shù)據(jù)庫可以使用的算法來確定一個(gè)操作是否發(fā)生在另一個(gè)操作之前,或者它們是否并發(fā)發(fā)生猿挚。我們還談到了通過合并并發(fā)更新來解決沖突的方法咐旧。
在下一章中,我們將繼續(xù)考察數(shù)據(jù)分布在多臺(tái)機(jī)器間的另一種不同于 復(fù)制 的形式:將大數(shù)據(jù)集分割成 分區(qū)绩蜻。