DDIA笔记——数据复制
Table of Contents generated with DocToc
此篇為《數(shù)據(jù)密集型應(yīng)用系統(tǒng)設(shè)計(jì)》(DDIA)讀書筆記,筆記可能存在遺漏,建議直接閱讀原書。
第五章 數(shù)據(jù)復(fù)制
- 主從復(fù)制
- 復(fù)制滯后
- 復(fù)制滯后帶來(lái)的問(wèn)題
- 多主節(jié)點(diǎn)復(fù)制
- 適用場(chǎng)景
- 處理寫沖突
- 拓?fù)浣Y(jié)構(gòu)
- 無(wú)主節(jié)點(diǎn)復(fù)制
- 讀修復(fù)和反熵
- 讀寫quorum
- 寬松的quorum和數(shù)據(jù)回傳
- 多數(shù)據(jù)中心操作
- 檢測(cè)并發(fā)寫
- 合并同時(shí)寫入的值
- 版本矢量
第五章 數(shù)據(jù)復(fù)制
主從復(fù)制
復(fù)制滯后
如果一個(gè)應(yīng)用正好從一個(gè)異步的從節(jié)點(diǎn)讀取數(shù)據(jù),而該副本落后于主節(jié)點(diǎn),則應(yīng)用可能會(huì)讀到過(guò)期的信息。由于并非所有的寫入都反應(yīng)到從副本上,如果同時(shí)對(duì)主節(jié)點(diǎn)和從節(jié)點(diǎn)發(fā)起相同的查詢,可能會(huì)得到不同的結(jié)果。但如果停止寫數(shù)據(jù)庫(kù),經(jīng)過(guò)一段時(shí)間后,從節(jié)點(diǎn)最終會(huì)追上主節(jié)點(diǎn)并與主節(jié)點(diǎn)保持一致,這種效應(yīng)也被稱為最終一致性。
復(fù)制滯后帶來(lái)的問(wèn)題
三種復(fù)制滯后帶來(lái)的問(wèn)題場(chǎng)景:
1.讀自己的寫
許多應(yīng)用會(huì)讓用戶提交一些數(shù)據(jù),然后查看自己所提交的內(nèi)容,對(duì)于異步復(fù)制會(huì)出現(xiàn)這樣的問(wèn)題:提交數(shù)據(jù)須發(fā)送到主節(jié)點(diǎn),但是當(dāng)用戶讀取數(shù)據(jù)時(shí),數(shù)據(jù)可能來(lái)自從節(jié)點(diǎn),然而這時(shí)新數(shù)據(jù)可能尚未到達(dá)從節(jié)點(diǎn),導(dǎo)致用戶以為提交的數(shù)據(jù)丟失。
針對(duì)這種情況,我們需要“讀寫一致性”,該機(jī)制保證如果用戶重新加載頁(yè)面,他們總能看到自己最近提交的更新,但對(duì)其他用戶則沒(méi)有任何保證(其他用戶的更新可能無(wú)法及時(shí)看到)。
基于主從復(fù)制的系統(tǒng)實(shí)現(xiàn)讀寫一致性的可行方案:
- 如果用戶訪問(wèn)可能會(huì)被修改的內(nèi)容,從主節(jié)點(diǎn)讀取;否則,在從節(jié)點(diǎn)讀取;所以在查詢執(zhí)行之前需要判斷內(nèi)容是否可能被修改;
- 如果應(yīng)用的大部分內(nèi)容都必須經(jīng)由主節(jié)點(diǎn),這就喪失了讀操作的擴(kuò)展性。這就需要其他的方案,例如:跟蹤最近的更新時(shí)間,如果更新后一分鐘之內(nèi),則從主節(jié)點(diǎn)讀取;同時(shí)監(jiān)控從節(jié)點(diǎn)的復(fù)制滯后程度,避免從那些滯后時(shí)間過(guò)長(zhǎng)的從節(jié)點(diǎn)讀取;
- 讀請(qǐng)求+客戶端記住最近更新時(shí)的時(shí)間戳,系統(tǒng)確保對(duì)該用戶提供讀服務(wù)時(shí)都應(yīng)該至少包含了該時(shí)間戳的更新,否則可以交給另一個(gè)副本來(lái)處理或等待至副本接收到最近的更新;
- 如果副本分布在多數(shù)據(jù)中心,必須先把請(qǐng)求路由到主節(jié)點(diǎn)所在的數(shù)據(jù)中心(?);
如果同一用戶從多個(gè)設(shè)備訪問(wèn)數(shù)據(jù)時(shí),還有一些需要考慮的問(wèn)題:
- 記住用戶上次更新時(shí)間戳的方法實(shí)現(xiàn)起來(lái)會(huì)比較困難;
- 如果副本分布在多數(shù)據(jù)中心,無(wú)法保證來(lái)自不同設(shè)備的連接經(jīng)過(guò)路由之后都到達(dá)同一數(shù)據(jù)中心;
2.單調(diào)讀
如圖,用戶1234發(fā)出一條寫請(qǐng)求,主節(jié)點(diǎn)執(zhí)行完畢之后,將請(qǐng)求轉(zhuǎn)發(fā)給其他從節(jié)點(diǎn),其中從節(jié)點(diǎn)1復(fù)制滯后較短,從節(jié)點(diǎn)2復(fù)制滯后較長(zhǎng)。此時(shí),用戶2345發(fā)起了兩次對(duì)reply_to=5555的讀請(qǐng)求,第一次查詢成功得到了用戶數(shù)據(jù),而第二次請(qǐng)求,由于滯后過(guò)長(zhǎng),導(dǎo)致返回為空。
單調(diào)讀一致性保證:當(dāng)讀取數(shù)據(jù)時(shí),如果某個(gè)用戶依次進(jìn)行多次讀取,則他不會(huì)看到回滾現(xiàn)象,即在讀取較新值之后又發(fā)生讀舊值的情況。
實(shí)現(xiàn)單調(diào)讀的一種方式是:確保每個(gè)用戶總是從固定的同一副本執(zhí)行讀取(例如:基于用戶ID的哈希算法來(lái)選擇從節(jié)點(diǎn));
3.前綴一致讀
復(fù)制滯后帶來(lái)的因果反常:
Mr. Pooms: How far into the future can you see, Mrs. Cake?
Mrs. Cake: About ten seconds usually, Mr. Pooms.
但是由于滯后程度不同其他人聽(tīng)到的可能是:
Mrs. Cake: About ten seconds usually, Mr. Pooms.Mr. Pooms: How far into the future can you see, Mrs. Cake?
為了防止這種異常,引入了另一種保證:前綴一致讀(對(duì)于一系列按照某個(gè)順序發(fā)生的寫請(qǐng)求,那么讀取這些內(nèi)容是也會(huì)按照當(dāng)時(shí)寫入的順序)。
一種解決方案是確保任何具有因果順序關(guān)系的寫入都交給一個(gè)分區(qū)來(lái)完成,但該方案的真實(shí)效率會(huì)大打折扣。
多主節(jié)點(diǎn)復(fù)制
由主從復(fù)制模型中“一主多從”變?yōu)椤岸嘀鞫鄰摹?#xff0c;復(fù)制流程類似:處理寫的每個(gè)主節(jié)點(diǎn)都必須將該數(shù)據(jù)更改轉(zhuǎn)發(fā)到所有其他節(jié)點(diǎn) 。此時(shí),每個(gè)主節(jié)點(diǎn)還是其他主節(jié)點(diǎn)的從節(jié)點(diǎn)。
適用場(chǎng)景
1.多數(shù)據(jù)中心
數(shù)據(jù)中心內(nèi)部采用主從復(fù)制方案,而在數(shù)據(jù)中心之間,由各個(gè)數(shù)據(jù)中心的主節(jié)點(diǎn)來(lái)負(fù)責(zé)同其他數(shù)據(jù)中心的主節(jié)點(diǎn)進(jìn)行數(shù)據(jù)的交換和更新。
每個(gè)數(shù)據(jù)中心之間通過(guò)廣域網(wǎng)連接。
缺點(diǎn):不同的數(shù)據(jù)中心可能會(huì)同時(shí)修改相同的數(shù)據(jù),因而必須解決潛在的寫沖突。
2.離線客戶端操作——網(wǎng)絡(luò)斷開(kāi)后還要繼續(xù)工作
3.協(xié)作編輯(通常不會(huì)將協(xié)作編輯等價(jià)于數(shù)據(jù)庫(kù)復(fù)制問(wèn)題,但二者有很多相似之處)
處理寫沖突
1.避免沖突
確保特定用戶的更新請(qǐng)求總是路由到特定的數(shù)據(jù)中心,并在該數(shù)據(jù)中心的主節(jié)點(diǎn)上進(jìn)行讀/寫。從用戶角度來(lái)看,這基本就等價(jià)于主從復(fù)制模型來(lái)。。。
2.收斂于一致?tīng)顟B(tài)
至少要保證數(shù)據(jù)在所有副本中最終狀態(tài)是一致的。
- 為每個(gè)寫入分配一個(gè)特定的ID,并制定規(guī)則,挑選勝利者;
- 將所有寫入合并為一條,在應(yīng)用層進(jìn)行處理;
3.解決沖突最合適的方式可能還是依靠應(yīng)用層
例如:保存導(dǎo)致沖突的所有可能,在讀取數(shù)據(jù)時(shí),由應(yīng)用層處理。
拓?fù)浣Y(jié)構(gòu)
環(huán)形和星形拓?fù)浯嬖诘膯?wèn)題:如果某一節(jié)點(diǎn)發(fā)生故障,在修復(fù)之前,會(huì)影響其他節(jié)點(diǎn)之間復(fù)制日志的轉(zhuǎn)發(fā);
全鏈接拓?fù)浯嬖诘膯?wèn)題:存在某些網(wǎng)絡(luò)鏈路比其他鏈路更快的情況,從而導(dǎo)致復(fù)制日志之間的覆蓋;
沖突檢測(cè)技術(shù)在許多多主節(jié)點(diǎn)復(fù)制系統(tǒng)中的實(shí)現(xiàn)還不夠完善
無(wú)主節(jié)點(diǎn)復(fù)制
同時(shí)向所有副本發(fā)出寫請(qǐng)求/讀請(qǐng)求。
讀修復(fù)和反熵
當(dāng)一個(gè)失效節(jié)點(diǎn)重新上線后,如何趕上中間錯(cuò)過(guò)的那些寫請(qǐng)求?兩種機(jī)制:
- 讀修復(fù)
當(dāng)客戶端并行讀取多個(gè)副本時(shí),可以檢測(cè)到過(guò)期值(根據(jù)版本號(hào)),然后將新值寫入到該副本;這種方法主要適合那些被頻繁讀取到場(chǎng)景。
- 反熵過(guò)程
一些數(shù)據(jù)存儲(chǔ)有后臺(tái)進(jìn)程不斷查找副本之間數(shù)據(jù)的差異,將任何缺少的數(shù)據(jù)從一個(gè)副本復(fù)制到另一個(gè)副本。與基于主節(jié)點(diǎn)復(fù)制分復(fù)制日志不同的是,反熵過(guò)程并不保證以特定的順序復(fù)制寫入,并且會(huì)引入明顯的同步滯后。
讀寫quorum
n個(gè)副本,寫入需要w個(gè)節(jié)點(diǎn)確認(rèn),讀取必須至少查詢r(jià)個(gè)節(jié)點(diǎn),則只要w + r > n,讀取節(jié)點(diǎn)就一定包含最新值,然后根據(jù)版本號(hào)就可以確定過(guò)期值。不要把w和r當(dāng)作絕對(duì)的保證,而是一種靈活可調(diào)的讀取新值的概率,因?yàn)楝F(xiàn)實(shí)情況往往更加復(fù)雜
寬松的quorum和數(shù)據(jù)回傳
配置適當(dāng)?shù)膓uorum的數(shù)據(jù)庫(kù)系統(tǒng)可以容忍某些節(jié)點(diǎn)故障,也不需要進(jìn)行故障切換,同時(shí)還可以容忍某些節(jié)點(diǎn)變慢(不需要等待所有副本響應(yīng))。
在一個(gè)大規(guī)模集群中(節(jié)點(diǎn)數(shù)遠(yuǎn)大于n),客戶可能在網(wǎng)絡(luò)中斷期間還能連接到某些數(shù)據(jù)庫(kù)節(jié)點(diǎn),但這些節(jié)點(diǎn)又不能夠滿足數(shù)據(jù)仲裁的那些節(jié)點(diǎn),此時(shí)你可能面臨一個(gè)選擇:
- 如果無(wú)法達(dá)到w或r,將錯(cuò)誤明確返回給客戶端;
- 只是將它們暫時(shí)寫入到一些可以訪問(wèn)到的節(jié)點(diǎn)(這些節(jié)點(diǎn)并不在n個(gè)節(jié)點(diǎn)集合中);
第二種方案稱為“寬松的仲裁”(sloppy quorum):寫入和讀取仍然需要w和r個(gè)成功的響應(yīng),但包含了那些并不在先前指定的n個(gè)節(jié)點(diǎn)。一旦網(wǎng)絡(luò)問(wèn)題解決,臨時(shí)節(jié)點(diǎn)需要把接收到的寫入全部發(fā)送到原始節(jié)點(diǎn)上,這就是所謂的“數(shù)據(jù)回傳”。
可以看出,sloppy quorum對(duì)于提高寫入可用性特別有用,只要有任何w個(gè)節(jié)點(diǎn)可用,數(shù)據(jù)庫(kù)就可以接收新的寫入。同時(shí),這也意味著,即使?jié)M足w + r > n,也不能保證著讀取r個(gè)副本時(shí)一定能讀取到新值,因?yàn)樾轮悼赡鼙慌R時(shí)寫入n之外的某些節(jié)點(diǎn)且尚未回傳。所以,sloppy quorum更像是為了數(shù)據(jù)持久性而設(shè)計(jì)的一個(gè)保證措施。
多數(shù)據(jù)中心操作
在一些數(shù)據(jù)庫(kù)系統(tǒng)中(Cassandra和Voldemort):副本的數(shù)量n是所有數(shù)據(jù)中心的節(jié)點(diǎn)總數(shù),每個(gè)客戶端的寫入都會(huì)發(fā)送到所有副本,但客戶端通常只會(huì)等待來(lái)自本地?cái)?shù)據(jù)中心內(nèi)的quorum節(jié)點(diǎn)數(shù)的確認(rèn)。
而有些數(shù)據(jù)庫(kù)系統(tǒng)(如:Riak)則將客戶端與數(shù)據(jù)庫(kù)節(jié)點(diǎn)之間的通信限制在一個(gè)數(shù)據(jù)中心內(nèi),因此n描述的是一個(gè)數(shù)據(jù)中心內(nèi)的副本數(shù)量。集群之間跨數(shù)據(jù)中心的復(fù)制則在后臺(tái)異步運(yùn)行,類似于多主節(jié)點(diǎn)復(fù)制風(fēng)格。
檢測(cè)并發(fā)寫
處理寫沖突
- 最后寫入者獲勝:
強(qiáng)制對(duì)寫請(qǐng)求排序,最后只有一個(gè)寫入值存活下來(lái)。
如何判斷兩個(gè)操作是否并發(fā)?
- Happens-before關(guān)系和并發(fā)
如果B知道A,或者依賴于A,或者以某種方式在A基礎(chǔ)上構(gòu)建,則稱操作A中操作B之前發(fā)生。所以,如果兩個(gè)操作都不在另一個(gè)之前發(fā)生,那么操作是并發(fā)的。(呃。。。)
如果一個(gè)操作發(fā)生在另一個(gè)操作之前,則后面的操作可以覆蓋較早的操作;如果屬于并發(fā),就需要解決潛在的沖突問(wèn)題。
如何讓確定操作并發(fā)性,即兩個(gè)操作究竟屬于并發(fā)還是一個(gè)發(fā)生在另一個(gè)之前(依賴)?
- 服務(wù)器為每個(gè)主鍵維護(hù)一個(gè)版本號(hào),每當(dāng)主鍵新值寫入時(shí)遞增版本號(hào),并將新版本號(hào)于寫入的值一起保存;
- 當(dāng)客戶端讀取主鍵時(shí),服務(wù)器將返回所有當(dāng)前值以及最新的版本號(hào)。且要求寫之前,必須先發(fā)生讀請(qǐng)求;
- 客戶端寫請(qǐng)求必須包含:之前讀帶的版本號(hào)、讀到的值和新值三者合并后的集合。寫請(qǐng)求的響應(yīng)和讀操作一樣;
- 當(dāng)服務(wù)器收到帶有特定版本號(hào)的寫入時(shí),覆蓋該版本號(hào)或更低版本的所有值;如果一個(gè)寫請(qǐng)求沒(méi)有包含版本號(hào),它將與所有其他寫入同時(shí)進(jìn)行,不會(huì)覆蓋任何已有值,其傳入的值將包含在后續(xù)讀請(qǐng)求的返回值列表中;
合并同時(shí)寫入的值
不舍棄并發(fā)寫入的值和舊值,而是將舊值和新值進(jìn)行合并。但是對(duì)于刪除操作,項(xiàng)目在刪除時(shí)不能簡(jiǎn)單地從數(shù)據(jù)庫(kù)中刪除,系統(tǒng)必須保留一個(gè)對(duì)應(yīng)的版本號(hào)以恰當(dāng)?shù)臉?biāo)記該項(xiàng)目需要在合并時(shí)刪除(結(jié)合購(gòu)物車案例)。
版本矢量
對(duì)每個(gè)副本的每個(gè)主鍵均定義一個(gè)版本號(hào),每個(gè)副本在處理寫入時(shí)增加自己的版本號(hào),并且跟蹤從其他副本看到的版本號(hào),通過(guò)這些信息來(lái)指示要覆蓋哪些值、該保留哪些值。所有副本的版本號(hào)集合稱為版本矢量。
總結(jié)
以上是生活随笔為你收集整理的DDIA笔记——数据复制的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 第二讲 命令源码文件
- 下一篇: 金山wps的云文档删除文档