當前位置:
首頁 > 知識 > 資料庫數據複製技術入門

資料庫數據複製技術入門

複製資料庫數據可以使我們的應用程序更快,並增加我們對故障的容忍度,但是有很多不同的選項可供選擇,每個選項都帶有成本付出。如果我們不了解我們使用的工具是如何工作的,以及它們提供的保證是什麼(或者更重要的是,不提供),那麼很難做出正確的選擇,這就是我想在這裡探討的內容。本文研究所有可用的選項以及資料庫複製設置中涉及的所有內容都可能是壓倒性的,涉及幾十年關於該主題的文獻。

光在真空中以299,792 km / s的速度行進。即使我們假設我們的要求以這樣的速度行駛,並且它們以直線行駛,但是對於世界旅行來說仍然需要133ms。

無論我們如何快速執行查詢,如果資料庫位於北美,數據仍然需要一直送往亞洲,然後亞洲辦公室的人員才能使用這些數據。很明顯,我們必須將這些數據提供給離它們更近的地方,所以複製任務就開始了。

複製什麼和為什麼複製

當我們說要複製某些內容時,就意味著我們希望在多個位置保留相同數據的副本。在資料庫的情況下,這可能意味著整個資料庫的副本,這是最常見的情況,或者只是它的某些部分(例如一組表)。我們通常通過網路連接將在多個位置保留數據,這是我們大多數頭痛的根源,您將會看到一些問題。

這樣做的原因:

  • 您希望將數據與用戶保持近距離,以便節省數據旅行時間。請記住,無論您的資料庫有多快,數據仍然需要從啟動請求的計算機傳輸到資料庫所在的伺服器,然後再返回。您可以優化資料庫,但無法優化物理定律。
  • 您希望擴展服務請求的計算機數量。在某些時候,單個伺服器將無法處理它需要服務的客戶端數量。在這種情況下,擁有多個具有相同數據的資料庫可幫助您為更多客戶提供服務 這就是我們所說的水平縮放(而不是 垂直縮放,這意味著擁有更強大的機器)。
  • 如果發生故障(即將發生),您希望安全。想像一下,您將數據存儲在單個資料庫伺服器中並且該伺服器著火,然後會發生什麼?我確定你有某種備份(對嗎?!),但你的備份將a)需要一些時間來恢復,b)可能至少要幾個小時。不酷。擁有副本意味著您可以在解決火災情況時開始將請求發送到此伺服器,也許沒有人會注意到發生了一些不好的事情。

強制性的CAP介紹

CAP定理是由Eric Brewer在2000年引入的,所以這不是一個新想法。首字母縮略詞代表Consistency,Availability和Partition Tolerance,它基本上說,鑒於分散式系統中的這三個屬性,你需要選擇其中的2個(即你不能擁有全部3個)。實際上,這意味著您需要在不可避免的分區發生時在一致性和可用性之間進行選擇。

一致性:在CAP定義中,一致性意味著集群中的所有節點(例如,所有資料庫伺服器,領導者和副本)在任何給定時間點都會看到相同的數據。實際上,這意味著如果您在同一時間查詢任何資料庫伺服器,您將得到相同的結果。

可用性:這意味著即使我們無法保證它具有最新數據,讀取和寫入也將始終成功。在實踐中,這意味著我們仍然可以使用我們的一個資料庫,即使這個資料庫無法與其他資料庫交互,因此可能沒有收到最新的更新。

分區容差:這意味著即使存在網路分區,您的系統也將繼續工作。網路分區意味著群集中的節點無法相互通信。

為什麼我要談論這個?好吧,因為根據您所採用的路線,您將有不同的權衡,有時有利於一致性和有時可用性。

CAP定理在分散式系統討論中的價值有多大值得商榷,但我認為記住在處理網路分區時幾乎總是交換可用性的一致性(反之亦然)是有用的。

關於延遲

延遲是請求等待處理的時間(它是 潛在的)。我們的目標是儘可能降低延遲。當然,即使延遲很低,我們仍然可以有很長的響應時間(例如,如果查詢需要很長時間才能運行),但這是一個不同的問題。

當我們複製我們的資料庫時,我們可以通過縮短此請求需要傳輸的距離和/或增加我們的容量來減少延遲,因此請求無需等待,因為繁忙的伺服器可以處理它。

非同步複製

當我們談論的複製,我們基本上是說,當我寫一些數據到一個指定節點A,這個相同的數據也需要在節點B(也許C和D和E和...)寫入,但我們需要決定此複製是如何發生的,以及我們需要什麼保證。與往常一樣,這都是權衡利弊。讓我們探討一下我們的選擇。

第一個選項是在收到消息的節點成功寫入數據後立即向客戶端發送確認, 然後將此消息發送到副本(可能存在也可能不存在)。

這看起來很棒,我們沒有注意到任何性能影響,因為複製發生在後台,在我們已經得到響應之後,如果副本已經死或慢,我們甚至都不會注意到它,因為數據已經發回給客戶。一切很好。

非同步複製存在(至少)兩個主要問題。首先是我們正在削弱我們的持久性保證,另一個是我們暴露於複製滯後中。我們將在稍後討論複製滯後,讓我們首先關注持久性問題。

我們的問題是,如果收到此寫入請求的節點在將這種更改複製到副本之前發生了失敗,則即使我們向客戶端發送了確認,數據也會丟失。

你可能會問自己

「但是在那一刻發生失敗的可能性是多少?!」

如果是這樣的話,我建議你改為問

「 如果當時發生失敗會有什麼後果?」

是的,承擔風險可能完全沒問題,但在處理金融交易的典型例子中,或許最好是付出代價以獲得更強的擔保。但是代價是多少?

同步複製

正如您所料,同步複製基本上意味著我們將 首先複製數據,然後向客戶端發送確認。因此,當客戶得到確認時,我們可以確保數據被複制並且安全(好吧,它絕不是100%安全的,理論上我們所有的數據中心都可以同時爆炸,但它足夠安全)。

我們需要支付的代價是:性能和可用性。

性能損失是由於我們需要等待這些可能很慢的複製節點做完他們的事情並向我們發送確認。由於這些副本通常在地理上分布,並且可能彼此相距很遠,因此這比我們想要等待的時間更長。

第二個問題是可用性。如果其中一個副本(記住,我們可以有很多!)已關閉或由於某種原因我們無法訪問它,我們根本無法寫入任何數據。你應該總是計劃失敗,並且網路分區比我們想像的更常見,因此根據可以訪問的所有副本執行任何寫入對我來說似乎不是一個好主意

不是8,不是80

有一些中間方式:一些資料庫和複製工具允許我們定義一些要同步複製的關注者,而其他人只使用非同步方法。這有時稱為半同步複製。

例如,Postgres您可以定義一個調用的配置,synchronous_standby_names 以指定哪些副本將同步接收更新,而其他副本將只是非同步接收它們。

單領導複製

最常見的複製拓撲是擁有一個領導者,然後將更改變動複製到所有關注者。

在此設置中,客戶端始終將寫入(在資料庫INSERT,UPDATE和DELETE查詢的情況下 )發送給領導者,而不是發送給它的跟隨者。但是,這些跟隨關注者可以響應來自客戶端的讀取查詢。

擁有單一領導者的主要好處是我們避免了由並發寫入引起的衝突。所有客戶端都在寫入同一台伺服器,因此協調更容易。如果我們允許客戶端同時寫入2個不同的伺服器,我們需要以某種方式解決如果它們都嘗試使用不同的值更改相同的對象時會發生的衝突(稍後會詳細介紹)。

那麼,如果我們決定採用單一領導方法,我們需要記住哪些問題?第一個是我們需要確保只有一個節點能夠處理所有寫入。雖然我們可以在整個集群中拆分讀取工作,但所有寫入都將轉移到單個伺服器,如果您的應用程序非常密集,則可能會出現問題。但請記住,大多數應用程序讀取的數據比寫入的數據多得多,因此您需要分析這是否真的是一個問題。

另一個問題是您需要支付寫入的延遲成本。還記得文章開頭亞洲的同事案例嗎?好吧,當他們想要更新某些數據時,該查詢仍然需要在獲得響應之前到達全球。

最後,雖然下面這個問題對於單一領導者複製來說並不是一個真正的問題,但您需要考慮領導節點死亡時會發生什麼。整個系統是否會停止工作?它是否僅適用於讀取(來自副本),但不適用於寫入?是否有選舉新領導者的流程(即將其中一個副本推廣到領導者身份)?這個選舉過程是自動化還是需要有人告訴系統誰是城裡的新的領導者?

乍一看,似乎最好的方法是只有自動故障轉移策略,它將選出一個新的領導者,一切都會繼續工作。不幸的是,這說起來容易做起來難。

自動故障轉移的挑戰

我們需要問的第一個問題是:我們怎樣才能確定領導者已經死了?答案是:我們可能無法確定。

在任何分散式系統中一樣,不可能將慢速響應與死亡節點區分開來。資料庫通常使用超時來決定(例如,如果我在20秒內沒有收到您的回復,那麼您已經死了!)。

這通常足夠好,但肯定不完美。如果您等待更多,則不太可能將節點識別為錯誤,但是也需要更多時間來啟動故障轉移過程,同時您的系統可能無法使用。另一方面,如果您沒有給它足夠的時間,您可能會啟動一個不必要的故障轉移過程。所以這是第一個挑戰。

挑戰二:你需要決定誰是新的領導者。你有所有這些追隨者,生活在一個無政府狀態,他們需要以某種方式就誰應該成為新的領導者達成一致。例如,一個相對簡單(至少在概念上)接近它以具有預定義的後繼節點,其將在原始領導者死亡時假設領導者位置。或者,您可以選擇具有最新更新的節點(例如,更靠近領導者的節點),以最大限度地減少數據丟失。無論你決定選擇新的領導者,所有節點仍然需要就該決定達成一致,這是困難的部分。這被稱為共識問題,並且可能非常棘手。

好吧,你發現領導者真的已經死了並且選擇了一個新的領導者,現在你需要以某種方式告訴客戶開始向這個新的領導者發送寫入,而不是死者。這是一個請求路由問題,我們也可以從幾個不同的角度來處理它。例如,您可以允許客戶端向任何節點發送寫入,並讓這些節點將此請求重定向到領導者。或者,您可以擁有一個接收此消息的路由層,並將它們重定向到相應的節點。

如果您使用非同步複製,則新的領導者可能沒有來自前一個領導者的所有數據。在這種情況下,如果舊的領導者復活(可能只是網路故障或伺服器重啟)並且新領導者在此期間收到了相互衝突的更新,我們如何處理這些衝突?一種常見的方法是放棄這些衝突(使用最後寫入 - 獲勝方法),但這也可能是危險的(以此Github問題(從2012年開始)為例)。

我們也可以有一個有趣的(好吧,也許它不是那麼有趣,當它在生產中發生)的情況,前一個領導者回來並認為它仍然是領導者。這被稱為裂腦,可能導致奇怪的情況。

如果兩個領導者都開始接受寫入而我們還沒有準備好處理衝突,則可能會丟失數據。

某些系統具有防護機制,如果檢測到有多個領導者,則會強制關閉一個節點。這種方法被稱為STONITH「頭部中的另一個節點」。

這也是當有一個網路分區時我們最終會看到兩個孤立的集群,每個集群都有自己的領導者,因為這個集群的每個部分都看不到另一個集群,因此認為它們都已經死了。

如您所見,自動故障轉移並不簡單。有很多事情需要考慮,因此有時人手動執行此過程會更好。當然,如果您的領導者資料庫在晚上7點死亡並且沒有人隨叫隨到,那麼可能不是等到明天早上的最佳解決方案,因此,一如既往地權衡利弊。

作者:JDON

原文:https://www.jdon.com/51361

資料庫數據複製技術入門

打開今日頭條,查看更多圖片
喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 程序員小新人學習 的精彩文章:

Tensorflow_08A_Keras 助攻下的 Sequential 模型
DDD悖論:DDD是不是銀彈?

TAG:程序員小新人學習 |