數(shù)據(jù)復(fù)制是指將同樣的數(shù)據(jù)存儲在不同的節(jié)點上氢橙,之間經(jīng)由網(wǎng)絡(luò)進行數(shù)據(jù)同步地来。數(shù)據(jù)復(fù)制的主要目的是:
- 使用距離用戶近的節(jié)點服務(wù)用戶娜扇,以此降低網(wǎng)絡(luò)傳輸延遲铛嘱;
- 提供更好的災(zāi)備能力,在某些節(jié)點失效的時候依舊能夠提供服務(wù)喊儡;
- 提高對外的服務(wù)能力,增加服務(wù)吞吐量;
數(shù)據(jù)復(fù)制所要面對的主要問題是如何應(yīng)對數(shù)據(jù)的寫入操作范删,并同步到所有數(shù)據(jù)節(jié)點當中。目前主要的方式是主從架構(gòu):
- 在所有數(shù)據(jù)節(jié)點中選出一個主節(jié)點拷肌,負責處理客戶端的所有寫入請求到旦;
- 其他數(shù)據(jù)節(jié)點是從節(jié)點,當主節(jié)點的數(shù)據(jù)落庫之后巨缘,會將所有的數(shù)據(jù)變更以復(fù)制日志的形式添忘,經(jīng)由網(wǎng)絡(luò)傳輸發(fā)送到所有的數(shù)據(jù)從節(jié)點,從節(jié)點重現(xiàn)復(fù)制日志以完成正確的數(shù)據(jù)復(fù)制操作若锁;
- 數(shù)據(jù)庫主從庫都可以處理客戶端的查詢操作搁骑;
主從復(fù)制的機制被很多主流關(guān)系型數(shù)據(jù)庫所采用,比如MySQL, PostgreSQL等等又固。還有很多非關(guān)系數(shù)據(jù)庫也采用了這種機制仲器,比如MongoDB, RethinkDB等等。甚至被高可靠消息隊列Kafka仰冠,RabbitMQ采用乏冀。
數(shù)據(jù)復(fù)制:同步與異步
一個非常常見的場景:用戶修改了自己的賬戶信息,主節(jié)點返回了修改成功的響應(yīng)洋只。那么煤辨,此時的從節(jié)點的數(shù)據(jù)是否已經(jīng)完成了修改呢?
上圖中的從節(jié)點1的復(fù)制是同步的:在完成數(shù)據(jù)復(fù)制之后才對客戶端返回修改成功的響應(yīng)木张;而從節(jié)點2的復(fù)制則是異步的:先返回客戶端修改成功的響應(yīng)众辨,之后才完成數(shù)據(jù)的真正復(fù)制操作。
需要注意的一點是舷礼,主節(jié)點的數(shù)據(jù)寫入成功并不能保證從數(shù)據(jù)節(jié)點的數(shù)據(jù)能夠完成數(shù)據(jù)復(fù)制鹃彻,很多因素可能會導(dǎo)致從數(shù)據(jù)節(jié)點的數(shù)據(jù)寫入失敗:從節(jié)點故障妻献,網(wǎng)絡(luò)傳輸問題等等蛛株。
同步復(fù)制機制能夠保證在客戶端獲得操作成功響應(yīng)的前提下,保證主從節(jié)點的數(shù)據(jù)一致性育拨,不存在主成功從失敗而導(dǎo)致臟數(shù)據(jù)出現(xiàn)的情況谨履;缺點在于客戶端需要等待從節(jié)點的響應(yīng),延長了整個請求響應(yīng)的過程熬丧,在從節(jié)點發(fā)生故障的時候會阻塞整個數(shù)據(jù)系統(tǒng)無法繼續(xù)響應(yīng)寫入請求笋粟。
鑒于系統(tǒng)容錯性的考慮,一般不會對于所有節(jié)點都采用同步復(fù)制的策略。在一些分布式系統(tǒng)中害捕,采用對于一個從節(jié)點采用同步復(fù)制策略其他采用異步策略绿淋,以此保證一個主節(jié)點的災(zāi)備節(jié)點,這種方式又叫做半同步尝盼。而在大多數(shù)系統(tǒng)中吞滞,異步復(fù)制策略是更常用的,在從節(jié)點發(fā)生故障的時候盾沫,依舊能夠?qū)ν馓峁┓?wù)裁赠,提升系統(tǒng)可用性。
設(shè)立新主節(jié)點
有時系統(tǒng)需要設(shè)立新主節(jié)點的操作來接替崩潰的主節(jié)點工作赴精,設(shè)立新主節(jié)點的主要問題是要保證新主節(jié)點已經(jīng)保有最新的數(shù)據(jù)佩捞。整個過程分以下幾步:
- 抽取主節(jié)點最近時間點的快照;
- 將上面的快照拷貝到新的數(shù)據(jù)節(jié)點中祖娘;
- 新數(shù)據(jù)節(jié)點向主節(jié)點請求快照之后的數(shù)據(jù)變更操作失尖;
- 新數(shù)據(jù)節(jié)點完成變更操作同步之后,就可以接替之前主節(jié)點的工作了渐苏;
應(yīng)對節(jié)點崩潰
在一個擁有大量節(jié)點的分布式系統(tǒng)中掀潮,任何節(jié)點崩潰都應(yīng)被當做常規(guī)事件來應(yīng)對。在主從架構(gòu)中琼富,一般分為主節(jié)點和從節(jié)點兩種情況仪吧。
從節(jié)點:主節(jié)點一般會儲存快照和操作日志兩種備份日志,在從節(jié)點重新啟動之后鞠眉,根據(jù)斷開時間長短采用快照+操作日志或者單純操作日志的數(shù)據(jù)恢復(fù)方式薯鼠。
主節(jié)點:主節(jié)點崩潰之后所做的工作就有一點多了:設(shè)立新的主節(jié)點來處理客戶端請求,從節(jié)點需要接受新主節(jié)點所發(fā)送的數(shù)據(jù)同步操作械蹋。一般分為以下幾步:
- 確定主節(jié)點確實崩潰宕機出皇。一般采用的是在一定時間(比如30秒)內(nèi)無法對外產(chǎn)生任何響應(yīng)。
- 產(chǎn)生一個新的主節(jié)點哗戈。這里涉及到不同的選主算法郊艘。
- 重新配置系統(tǒng)設(shè)置,包括系統(tǒng)接受客戶端請求到主節(jié)點的路由配置唯咬,從節(jié)點到主節(jié)點之間的路由配置纱注。在舊的主節(jié)點恢復(fù)之后要正確的進行一個從節(jié)點的工作。
變更操作日志
這里主要說一下WAL(write-ahead log)胆胰。
- 在日志型存儲引擎中(LSM-Tree)狞贱,日志就是數(shù)據(jù)存儲的主要形式,后臺按照一定策略進行日志壓縮和垃圾回收蜀涨;
- 在B樹型數(shù)據(jù)存儲中瞎嬉,數(shù)據(jù)變更會先寫入WAL中蝎毡,保證即使在寫入B樹索引過程中發(fā)生崩潰也不會丟失數(shù)據(jù);
需要注意的是WAL是物理級別的日志佑颇,與數(shù)據(jù)存儲引擎的類型和版本強依賴顶掉。