備份意味著把你的數(shù)據(jù)的多個(gè)副本放置在不同的機(jī)器上,這些機(jī)器通過(guò)網(wǎng)絡(luò)連接。如第二章綜述所講,備份的好處有以下幾點(diǎn)
- 允許你的數(shù)據(jù)離你的用戶在地理位置上更近,從而減小延遲
- 允許你的系統(tǒng)在單個(gè)節(jié)點(diǎn)掛掉之后依舊能夠工作
- 通過(guò)提高機(jī)器的數(shù)量從而提高讀的吞吐量。
這章我們先假設(shè)一臺(tái)機(jī)器能夠放下所有的數(shù)據(jù),在第6章,我們?cè)诎堰@個(gè)假設(shè)放寬,通過(guò)分區(qū)技術(shù)解決當(dāng)單機(jī)沒(méi)辦法放下所有數(shù)據(jù)時(shí)候的問(wèn)題。這章后面討論備份系統(tǒng)可能出現(xiàn)的問(wèn)題以及如何解決他們。
如果你的數(shù)據(jù)從不變化,那你只需要把數(shù)據(jù)的復(fù)制到每個(gè)節(jié)點(diǎn)就搞定了。所有的問(wèn)題都是在你備份的數(shù)據(jù)發(fā)生變化時(shí)出現(xiàn)的。當(dāng)備份系統(tǒng)的數(shù)據(jù)發(fā)生變化時(shí),有3種流行算法使得多個(gè)節(jié)點(diǎn)也能備份這些變化。single leader, multi-leader,leaderless. 近乎所有的分布式系統(tǒng)都是用這3種的其中一種。三種算法都有自己的優(yōu)點(diǎn)和缺點(diǎn)。
在備份的過(guò)程中有很多的權(quán)衡需要考慮,舉個(gè)例子,使用同步備份還是異步備份,如何處理失敗的備份流程。這些一般都在數(shù)據(jù)庫(kù)當(dāng)中有配置,雖說(shuō)不同數(shù)據(jù)庫(kù)在實(shí)現(xiàn)上有眾多差異,但是思想上還是一致的。
Leaders 和 Followers
我們管每臺(tái)存儲(chǔ)著數(shù)據(jù)庫(kù)備份的節(jié)點(diǎn)叫做備份節(jié)點(diǎn)(replica), 如果你是多備份系統(tǒng),就有一個(gè)問(wèn)題需要處理,你怎么能知道所有的數(shù)據(jù)在所有的備份上都是正常的呢?
數(shù)據(jù)庫(kù)要求每次寫(xiě)操作都要把數(shù)據(jù)發(fā)送給每個(gè)備份節(jié)點(diǎn),否則備份節(jié)點(diǎn)就沒(méi)辦法都有相同的數(shù)據(jù)了。最常用的解決方案是leader-based replication, 也叫active/passive 或者 master–slave replication,工作原理如Figure 5-1所示
- 某一個(gè)備份節(jié)點(diǎn)被選作Leader, 當(dāng)客戶端要寫(xiě)數(shù)據(jù)庫(kù)的時(shí)候,他們必須把他的請(qǐng)求發(fā)給Leader, Leader先把請(qǐng)求內(nèi)容寫(xiě)入到本地的存儲(chǔ)中。
- 其他的備份節(jié)點(diǎn)稱作Follower, 當(dāng)Leader把寫(xiě)請(qǐng)求寫(xiě)到本地存儲(chǔ)的同時(shí),也把更新以備份日志或更新流的形式發(fā)送給其他的Follower。 每個(gè)Follower接收從Leader傳來(lái)的更新日志,按照日志更新的順序,更新自己的本地存儲(chǔ)。
- 當(dāng)客戶端需要讀數(shù)據(jù)的時(shí)候,他們可以從Leader或者Follower讀取數(shù)據(jù)。但是寫(xiě)請(qǐng)求就只能通過(guò)Leader了,F(xiàn)ollower對(duì)于客戶端而言是只讀的。

這種備份模式在關(guān)系數(shù)據(jù)庫(kù)中有很多應(yīng)用,例如PostgreSQL, MySQL, 在某些非關(guān)系數(shù)據(jù)庫(kù)中也有應(yīng)用,例如MongoDB, RethinkDB, Espresso。不僅如此,leader-based replication不光用于數(shù)據(jù)當(dāng)中,分布式的消息隊(duì)列,比如Kafka和RabbitMQ同樣運(yùn)用了這套方案。某些網(wǎng)絡(luò)文件系統(tǒng),例如DRBD, 在備份文件的時(shí)候也是一樣的。
同步備份 vs 異步備份
備份有一個(gè)很重要的細(xì)節(jié),是備份和寫(xiě)請(qǐng)求時(shí)同步的還是異步的。在關(guān)系數(shù)據(jù)庫(kù)中,這是通過(guò)配置實(shí)現(xiàn)的,其他系統(tǒng)一般在兩者中選取其一,不可修改。
想想Figure 5-1的情況,用戶通過(guò)網(wǎng)頁(yè)更新自己的檔案照片,客戶端把這個(gè)更新發(fā)送給Leader, Leader收到請(qǐng)求之后,在之后的某個(gè)時(shí)間把更新發(fā)送給Follower, 最后Leader通知客戶端更新完成。如Figure 5-2所示

Figure 5-2中, Follower1的備份是同步的,Leader在Follower1返回ok之前一直等待。在收到Follower更新成功之后,才向客戶端返回更新成功。而在這段等待的時(shí)間中,數(shù)據(jù)庫(kù)是不接受其他客戶端的寫(xiě)請(qǐng)求的。Follower 2的備份是異步的,Leader將消息發(fā)送出去,并沒(méi)有等待Follower返回成功。
圖中顯示Follower 2在處理消息之前有很大的延遲,正常情況下,備份是很快的,大多數(shù)數(shù)據(jù)庫(kù)更新到備份節(jié)點(diǎn)需要少于一秒的時(shí)間。但是對(duì)于這個(gè)時(shí)間其實(shí)并不是100%承諾的。有時(shí)候會(huì)出現(xiàn)Follower的數(shù)據(jù)比Leader晚幾分鐘甚至更多的情況出現(xiàn),比如當(dāng)Follower剛剛從異常中恢復(fù),或者系統(tǒng)負(fù)載接近滿負(fù)荷,或者節(jié)點(diǎn)間的網(wǎng)絡(luò)出現(xiàn)異常。
同步備份的好處是,F(xiàn)ollower的數(shù)據(jù)100%跟Leader的內(nèi)容一致,一旦Leader在某個(gè)時(shí)間掛了,我們可以直接拿Follower來(lái)替代它并且保證數(shù)據(jù)沒(méi)有問(wèn)題。缺點(diǎn)在于如果Follower因?yàn)槟承┰驔](méi)有響應(yīng),那這次寫(xiě)操作就無(wú)法處理了。Leader必須在Follower恢復(fù)之前禁止任何的寫(xiě)更新操作。
基于這個(gè)原因,讓所有的Follower都是同步更新顯然是不現(xiàn)實(shí)的,任何一個(gè)節(jié)點(diǎn)異常都會(huì)導(dǎo)致整個(gè)系統(tǒng)掛起。在實(shí)際情況下,如果你在數(shù)據(jù)庫(kù)中開(kāi)啟了同步備份,這往往代表其中的一個(gè)備份節(jié)點(diǎn)是同步的,其他是異步的。如果那個(gè)同步節(jié)點(diǎn)出現(xiàn)異常,或者延遲很大,那另外一個(gè)異步節(jié)點(diǎn)會(huì)替代他成為同步節(jié)點(diǎn)。這樣就保證你至少有2個(gè)節(jié)點(diǎn)有最新的數(shù)據(jù),Leader和一個(gè)同步節(jié)點(diǎn),這種配置被稱作半同步(semi-synchronous)
很多時(shí)候,leader-based replication通常被配置成全異步的。這種情況下,一旦Leader掛了,那所有沒(méi)有同步給Follower的更新就全都丟掉了。這就意味著寫(xiě)操作是不能100%保證持久化的,即使客戶端已經(jīng)收到了成功的返回。但是這樣的好處是即使所有的Follower都掛掉了,Leader依然可以正常的處理寫(xiě)請(qǐng)求??赡軙?huì)丟數(shù)據(jù)聽(tīng)上去是一個(gè)很差的代價(jià),但是異步備份仍然是用的十分廣泛,尤其是當(dāng)你有很多個(gè)Follower或者他們分布在世界不同地方的時(shí)候。
異步備份丟數(shù)據(jù)聽(tīng)上去依舊是一個(gè)很可怕的事情,所以人們開(kāi)始研究那種不會(huì)丟數(shù)據(jù)但依舊有高性能和高可用性的備份方式。chain replication 是一種同步備份的變種,他已經(jīng)用到了Azure存儲(chǔ)中。
添加新的Follower
隨著時(shí)間的推移,你可能需要添加新的Follower,可能是要增加備份數(shù),可能是要替換掉老的Follower,但是問(wèn)題是你怎么能夠知道新的Follower已經(jīng)擁有最新的數(shù)據(jù)了呢?
簡(jiǎn)單從一個(gè)節(jié)點(diǎn)把數(shù)據(jù)庫(kù)文件復(fù)制過(guò)來(lái)是不可行的,因?yàn)閏lient一直還在更新刪除數(shù)據(jù)。一個(gè)簡(jiǎn)單的復(fù)制只能得到數(shù)據(jù)庫(kù)某個(gè)時(shí)間點(diǎn)的鏡像,但是不是最新的。你也可以簡(jiǎn)單的在復(fù)制的過(guò)程中禁止寫(xiě)請(qǐng)求,就能避免這個(gè)問(wèn)題,但是這就和我們的高性能,高可用性違背了。所以實(shí)際過(guò)程如下
- 從Leader的數(shù)據(jù)庫(kù)中取出一個(gè)時(shí)間點(diǎn)的鏡像,這個(gè)在大多數(shù)數(shù)據(jù)庫(kù)中都是很輕松的事情,因?yàn)閿?shù)據(jù)庫(kù)本身也需要定期備份。某些時(shí)候,我們需要些第三方庫(kù),比如在處理MYSQL時(shí)需要innobackupex
- 把這個(gè)鏡像內(nèi)容復(fù)制到新的Follower中
- Follower向Leader請(qǐng)求這個(gè)鏡像時(shí)間點(diǎn)之后的所有更新。這就需要鏡像文件能夠和Leader的備份日志中某一個(gè)具體的位置關(guān)聯(lián)起來(lái)。這個(gè)位置有著不同的名字,PostgreSQL叫他log sequence number, MYSQL叫他binlog coordinates
- 當(dāng)Follower把更新都完成后,我們認(rèn)為他已經(jīng)追上了最新的數(shù)據(jù)(caught up),這個(gè)時(shí)候他就可以像其他Follower一樣正常跟Leader通信做備份了。
理論是上面這樣,但是實(shí)際操作中每個(gè)數(shù)據(jù)庫(kù)具體的方法差距很大,有的能做到全自動(dòng),有的就需要管理員手動(dòng)執(zhí)行一些東西。
處理節(jié)點(diǎn)失效
系統(tǒng)中任何節(jié)點(diǎn)都可能會(huì)失效,有些是意外,比如錯(cuò)誤,掉電,有些就是計(jì)劃中的,比如停機(jī)檢修,重啟。重啟單個(gè)機(jī)器但不影響服務(wù)對(duì)于操作和維護(hù)而言很重要。所以我們的目標(biāo)是即使單機(jī)掛掉,整個(gè)系統(tǒng)依舊能夠正常運(yùn)轉(zhuǎn),并且要把單機(jī)掛掉帶來(lái)的影響降到盡可能的小。
那在leader-based replication的架構(gòu)下如何實(shí)現(xiàn)高可用性呢?
Follower失效: 追趕恢復(fù)(Catch-up recovery)
在每個(gè)Follower本地磁盤中,有一份他從Leader收到的更新數(shù)據(jù)的日志。如果某個(gè)Follower突然掛掉或者他與Leader的網(wǎng)絡(luò)中斷,他能夠基于他的日志很容易的恢復(fù)。首先他能根據(jù)知道發(fā)生異常之前他更新到的位置,F(xiàn)ollower可以向Leader請(qǐng)求這個(gè)位置之后的所有更新數(shù)據(jù)。當(dāng)他處理完這些數(shù)據(jù)后,可以認(rèn)為已經(jīng)跟上了Leader的進(jìn)度,這時(shí)就可以正常的持續(xù)接收Leader發(fā)送的更新數(shù)據(jù)了。
Leader失效:故障切換(failover)
處理Leader失效就要麻煩很多了,要從眾多Follower中選取一個(gè)作為新Leader,客戶端需要重新將請(qǐng)求發(fā)送給新Leader。剩下的Follower要切換到新Leader接收更新數(shù)據(jù)。我們管這個(gè)叫故障切換(failover)
故障切換可能需要手動(dòng)操作,管理員收到Leader掛的通知,然后人工操作選個(gè)新Leader,當(dāng)然也可以自動(dòng)來(lái)。自動(dòng)操作就是以下幾步
- 確定Leader掛掉了, 因?yàn)槭У脑蚝芏?,掉電,異常崩潰,斷網(wǎng)。其實(shí)沒(méi)有一個(gè)100%確定的方法能夠判斷Leader真的掛掉了,所以一般來(lái)說(shuō)都是用一個(gè)很簡(jiǎn)單的方法。超時(shí)判斷,節(jié)點(diǎn)定時(shí)向?qū)Ψ桨l(fā)送心跳消息,如果一個(gè)節(jié)點(diǎn)超過(guò)一段時(shí)間,比如30s沒(méi)有響應(yīng)心跳消息,就認(rèn)為這個(gè)節(jié)點(diǎn)已經(jīng)死了。(如果Leader是計(jì)劃中的維護(hù)導(dǎo)致不可用,則不適用于這個(gè)判斷方法)
- 選新Leader, 這個(gè)一般是由一個(gè)選舉過(guò)程實(shí)現(xiàn)的,剩余的Follower中選Leader,也可以預(yù)先選好一個(gè)控制節(jié)點(diǎn)(controller node), Leader失效后將控制節(jié)點(diǎn)指定為L(zhǎng)eader。候選的Leader最好是更新的數(shù)據(jù)最新的節(jié)點(diǎn),這樣可以減少數(shù)據(jù)丟失。讓所有節(jié)點(diǎn)一致同意某一個(gè)新的Leader是一個(gè)一致性問(wèn)題,這個(gè)第九章講。
- 重新配置系統(tǒng)使用新Leader, 客戶端需要將寫(xiě)請(qǐng)求發(fā)送給新Leader。另外當(dāng)新的Leader活過(guò)來(lái)的時(shí)候,他可能依舊認(rèn)為自己是Leader,系統(tǒng)必須保證他能夠意識(shí)到自己已經(jīng)變成了Follower并且能夠正確的后新的Leader進(jìn)行通信。
故障切換看似簡(jiǎn)單,有很多地方都可能會(huì)出錯(cuò)。
- 如果使用了異步備份,那新的Leader可能沒(méi)有收到老Leader的所有的更新數(shù)據(jù)。當(dāng)老的Leader恢復(fù)重新加入系統(tǒng)中后,那些沒(méi)有同步的寫(xiě)請(qǐng)求應(yīng)該如何處理就很尷尬。因?yàn)樾碌腖eader可能會(huì)接收到互相沖突的寫(xiě)請(qǐng)求,比如老的說(shuō)這個(gè)字段是1,但是新Leader后面又收到了他是2,他就不知道到底是幾了。絕大多數(shù)的處理方法是把這部分?jǐn)?shù)據(jù)丟掉,但是這就讓客戶端不好處理了,因?yàn)樗膶?xiě)請(qǐng)求可能返回成功,但是卻丟了。
- 丟掉這些寫(xiě)請(qǐng)求時(shí)危險(xiǎn)的,尤其是當(dāng)還有其他外部系統(tǒng)使用了你的數(shù)據(jù)的時(shí)候。在一次GitHub的故障中,一個(gè)沒(méi)有收到所有的更新的Follower被選成了Leader,對(duì)于每條新數(shù)據(jù),數(shù)據(jù)庫(kù)用了一個(gè)自增的數(shù)字來(lái)做主鍵。但是因?yàn)樾碌腖eader的更新是落后于老Leader的,所以他把之前老Leader已經(jīng)使用過(guò)的一些主鍵又給了當(dāng)時(shí)的新數(shù)據(jù),導(dǎo)致主鍵復(fù)用的情況。問(wèn)題在于這些主鍵在另一個(gè)redis當(dāng)中有存儲(chǔ)用到,這一下導(dǎo)致redis的數(shù)據(jù)和MYSQL不一致,導(dǎo)致一些私人數(shù)據(jù)暴露給了錯(cuò)誤的用戶。
- 在特定的異常情況下,可能出現(xiàn)有兩個(gè)節(jié)點(diǎn)都認(rèn)為自己是Leader,這種情況稱作split brain, 這種情況很危險(xiǎn),因?yàn)閮蓚€(gè)節(jié)點(diǎn)都會(huì)接受寫(xiě)請(qǐng)求,寫(xiě)請(qǐng)求之間的沖突就沒(méi)辦法處理了,數(shù)據(jù)很有可能會(huì)發(fā)生丟失或損壞。出于安全考慮,有些系統(tǒng)會(huì)有對(duì)應(yīng)的安全機(jī)制,如果選出來(lái)兩個(gè)Leader,直接干掉一個(gè),但是你又沒(méi)辦法保證你的安全機(jī)制是正常的,有可能出問(wèn)題把兩個(gè)都干掉了。
- 判斷Leader超時(shí)應(yīng)該設(shè)多長(zhǎng)?如果設(shè)的很長(zhǎng),那一旦Leader掛掉就需要很多時(shí)間才能恢復(fù),但是如果設(shè)的很短,那可能會(huì)增添沒(méi)必要的故障切換。舉個(gè)例子,某個(gè)時(shí)刻的負(fù)載高峰或者某個(gè)時(shí)段網(wǎng)絡(luò)抖動(dòng)都會(huì)造成返回延遲。這個(gè)時(shí)候說(shuō)明整個(gè)系統(tǒng)負(fù)載已經(jīng)很大了,如果還啟用了故障切換,帶來(lái)更多額外的流量和操作,那就會(huì)把事情搞得更糟。
由于沒(méi)有簡(jiǎn)單的解決這些問(wèn)題的辦法,所有有些運(yùn)維團(tuán)隊(duì)寧愿選擇手動(dòng)的故障切換。
備份日志的實(shí)現(xiàn)
之前講的都是虛的,leader-based replication具體是如何工作的呢?實(shí)際情況中,有幾種不同的備份方式。
基于指令的備份(Statement-based replication)
這是一種最簡(jiǎn)單的方式,Leader記錄每次寫(xiě)請(qǐng)求指令,將這個(gè)指令日志發(fā)送給Follower。在關(guān)系數(shù)據(jù)庫(kù)中,這就意味著每個(gè)INSERT, UPDATE, DELETE請(qǐng)求的具體SQL被發(fā)送個(gè)Follower。每個(gè)Follower解析收到的日志,執(zhí)行對(duì)應(yīng)的SQL命令,就好像是從客戶端收到的一樣。
這種方法雖然聽(tīng)上去挺靠譜的,但是有幾個(gè)問(wèn)題會(huì)導(dǎo)致備份出錯(cuò)。
- 一旦指令中包含非確定性的函數(shù),比如NOW(), RAND(), 備份中生成的數(shù)據(jù)就不一樣了。
- 如果指令中涉及自增的數(shù)據(jù),或者這個(gè)指令依賴于數(shù)據(jù)庫(kù)中的其他數(shù)據(jù),例如 update ... where <some condition>, 那每個(gè)副本的執(zhí)行順序必須一致,否則效果就不一樣了。一旦有多個(gè)事務(wù)同時(shí)執(zhí)行,這個(gè)可能就有問(wèn)題了。
- 每個(gè)指令可能會(huì)有額外效果(觸發(fā)器,存儲(chǔ)過(guò)程, 用戶自定義函數(shù)), 這些內(nèi)容除非影響面是確定的,否則在不同副本間可能會(huì)有不同的結(jié)果。
雖然這個(gè)方案有些問(wèn)題,但是改一改還是可以用的,比如Leader在記日志的時(shí)候把所有非確定函數(shù)轉(zhuǎn)成一個(gè)指定值,這樣所有Follower結(jié)果就一致了。但是圖啥呢,明明還有其他的方法嘛。
基于指令的備份在 MYSQL 5.1以前都在使用?,F(xiàn)在有時(shí)候也會(huì)使,因?yàn)樗趾?jiǎn)單。如果有非確定函數(shù)的時(shí)候,會(huì)切換到基于行的備份,這個(gè)馬上講。VoltDB也是用這種方法,他要求每個(gè)事務(wù)結(jié)果都是確定的,所以沒(méi)有之前的問(wèn)題。
借用Write-ahead log (WAL) 的方法
第3章我們討論了,存儲(chǔ)引擎是如何把數(shù)據(jù)寫(xiě)入磁盤的,通常就是把所有寫(xiě)請(qǐng)求追加到一個(gè)日志中。
- 在SSTables中,這個(gè)日志其實(shí)就是整個(gè)存儲(chǔ)引擎的核心,讀寫(xiě)都是基于這個(gè)日志。日志段在后臺(tái)進(jìn)行合并。
- 在B樹(shù)中,數(shù)據(jù)本身是存在另外的地方,日志不負(fù)責(zé)讀數(shù)據(jù),每次寫(xiě)請(qǐng)求都是先寫(xiě)入write-ahead log, 保證程序崩潰后,可以根據(jù)日志恢復(fù)。
無(wú)論哪種情況,其實(shí)日志都是一個(gè)只可以追加的字節(jié)流,這個(gè)字節(jié)流中包含了所有的寫(xiě)請(qǐng)求。我們可以用這個(gè)日志在其他節(jié)點(diǎn)上構(gòu)建一個(gè)完整的備份出來(lái)。Leader不僅要把寫(xiě)請(qǐng)求記到本地WAL日志中,還要把它發(fā)給Follower,F(xiàn)ollower基于這些日志構(gòu)建一個(gè)完整的備份。
這種方法用于PostgreSQL和Oracle等等。但是這種方法有一個(gè)缺點(diǎn),就是他是在一個(gè)很低的層級(jí)上去描述數(shù)據(jù)。因?yàn)閃AL繪描述磁盤上某個(gè)字節(jié)發(fā)生了變化。這就使得副本和Leader緊緊耦合在一起。那Leader和Follower就必須運(yùn)行相同的版本。如果數(shù)據(jù)庫(kù)更新版本導(dǎo)致數(shù)據(jù)格式發(fā)生變化,那兼容性就沒(méi)辦法處理了,因?yàn)槟悴豢赡芤凰查g把Leader和Follower同時(shí)更新。這就意味著一旦更新版本,必須暫停服務(wù)。
邏輯日志備份/基于行備份
由于WAL有這些問(wèn)題,所以有一個(gè)解決方法是用另一套日志格式來(lái)做備份。這樣備份日志就可以和存儲(chǔ)引擎內(nèi)部解耦了。這種類型的備份日志稱作邏輯日志(logical log), 用以和存儲(chǔ)引擎物理層面的數(shù)據(jù)表達(dá)格式區(qū)分。
關(guān)系數(shù)據(jù)庫(kù)的備份日志通常是一系列記錄,用以準(zhǔn)確描述數(shù)據(jù)庫(kù)寫(xiě)入的數(shù)據(jù)。
- 針對(duì)插入數(shù)據(jù),日志包含了這條數(shù)據(jù)所有列的值
- 針對(duì)刪除數(shù)據(jù),日志包含足夠的信息以準(zhǔn)確找到需要?jiǎng)h除的數(shù)據(jù)。典型的信息就是他的主鍵,如果沒(méi)有主鍵,那就需要被刪除列的所有字段。
- 針對(duì)更新數(shù)據(jù),日志包含信息能夠準(zhǔn)確找到需要更新的行,以及需要更新的列和更新的值。
如果一個(gè)事務(wù)同時(shí)更新了多條數(shù)據(jù),則系統(tǒng)會(huì)產(chǎn)生了多條這樣的日志,日志后面有一條記錄標(biāo)識(shí)這個(gè)事務(wù)被成功提交了。MYSQL的binlog就是用這種方法。
因?yàn)檫壿嬋罩竞痛鎯?chǔ)引擎內(nèi)部解耦,所以他可以很容易的具備向后兼容性,允許Leader和Follower運(yùn)行不同的版本的數(shù)據(jù)庫(kù),甚至是不同的數(shù)據(jù)庫(kù)。同時(shí)邏輯日志還能夠容易的被外部應(yīng)用解析,這個(gè)特性在你需要把數(shù)據(jù)庫(kù)內(nèi)容發(fā)送給外部應(yīng)用的時(shí)候十分有用。比如從數(shù)據(jù)庫(kù)把數(shù)據(jù)導(dǎo)給數(shù)據(jù)倉(cāng)庫(kù)用以離線分析,或者構(gòu)建緩存和索引。這個(gè)技術(shù)叫做change data capture, 第11章講
基于觸發(fā)器的備份
前面講過(guò)的所有備份都是數(shù)據(jù)庫(kù)系統(tǒng)實(shí)現(xiàn)的,不需要任何應(yīng)用方寫(xiě)代碼。絕大多數(shù)時(shí)候你希望的就是這樣,但是有時(shí)候你需要更為靈活的配置。比如你只希望備份一部分?jǐn)?shù)據(jù),或者將一個(gè)數(shù)據(jù)庫(kù)內(nèi)容備份到另一個(gè)不同的數(shù)據(jù)庫(kù)中。這種時(shí)候你就需要將備份功能上移到應(yīng)用層來(lái)實(shí)現(xiàn)。
一些工具可以讓?xiě)?yīng)用觸及數(shù)據(jù)庫(kù)的數(shù)據(jù)變化,比如Oracle GoldenGate, 他是通過(guò)讀取數(shù)據(jù)庫(kù)的日志實(shí)現(xiàn)的。另外一種實(shí)現(xiàn)的方法是用觸發(fā)器(triggers) 和存儲(chǔ)過(guò)程(stored procedures)
觸發(fā)器可以允許你注冊(cè)一些自定義函數(shù),在數(shù)據(jù)變化時(shí) ,這些函數(shù)會(huì)自動(dòng)執(zhí)行。這樣觸發(fā)器可以把數(shù)據(jù)變化記錄到另外一個(gè)單獨(dú)的表中,這個(gè)表可以被外部程序訪問(wèn)。這樣外部程序就可以用任意自定義的邏輯來(lái)處理或者備份數(shù)據(jù)。Oracle的數(shù)據(jù)總線(data bus)和Postgres的Bucardo就是這樣工作的。
很顯然,基于觸發(fā)器的備份要比其他數(shù)據(jù)庫(kù)自帶的備份方案代價(jià)更大,而且也更容易帶來(lái)bug和一些限制因素。但是由于他的靈活性,他還是很有用的。