高可用的本質: 復制


服務和數據的高可用性本質上是靠“復制”來解決的,比如服務通過集群部署多台機器來完成,數據通過冗余的多副本機制來完成。對於服務來說,只需要部署多個實例即可,特別是無狀態服務,常見的微服務(dubbo/spring cloud)幾乎都是通過集群部署對外提供服務能力,更進一步的還可使用k8s+docker技術自動管理服務的副本容量;對於數據來說,需要通過數據復制來保證數據節點的一致性,由於數據是有狀態的,因此實現難度較服務復制成本要高。

復制除了提高可用性之外(多機房數據復制提高機房容錯性),還可以提高性能,比如讀寫分離、使數據副本離用戶更近等,用戶可優先就近讀取數據。對於數據來說,常見的復制策略有主從復制、多主復制和無主復制,除了這些之外,還有一種常見的廣義上“復制”策略-快照,比如Redis快照等。本文就針對上述幾種復制策略展開分析,話不多少,Let's go~

本文后續討論的復制無特殊說明都是針對數據復制來分析的,這里的復制討論都是基於一個節點能保存所有數據為前提,因為數據量過大需要使用分區機制,而分區機制不在本文討論范圍之內 :(

主從復制

如果數據不隨着時間而變化,那么只需復制一次即可,復制的難處在於數據始終在變化,因此復制時有很多權衡,比如是否同步,復制失敗的副本如何處理等。主從復制是常見的復制策略,寫操作發生在主節點,然后將更新的數據同步到從節點。基於主從的復制模型如下:

主從復制是許多數據庫的內置功能,比如PostgreSQL(從9.0版本開始),MySQL,Oracle Data Guard和SQL Server等,當然也有一些非關系型數據庫也支持此類功能,比如MongoDB等,不僅僅是數據庫,像kafka(分區的多副本)和rabbitmq的隊列為了實現高可用,也實現了主從復制功能,甚至一些存儲設備本身也具有復制機制。

同步復制和異步復制

復制中一個重要的細節是同步復制還是異步復制,同步復制擁有更強的數據一致性保證,如果主庫失效可以保證能在從庫中找到對應數據;但是缺點也很突出,那就是從庫會拖慢復制性能,如果從庫故障或者網絡原因,主庫無法處理請求直到從庫或者網絡正常為止。在多從庫場景中,針對網絡異常或者單個從庫故障的異常場景,可以使用quorum機制來保證大多數節點復制OK即可(比如zookeeper的主從同步機制),或者廣播復制只要有一個從庫復制OK即可(比如MySQL的半同步機制)。

異步復制擁有更好的性能保證,異步不影響請求的處理,主節點請求處理之后可以繼續處理下一個請求,但是異步復制由於是最終一致性的體現,所以存在一定的數據不一致時期。如果主庫失效,所有尚未同步給從庫的數據會丟失。大多數場景下使用異步復制策略就能滿足業務場景,如果業務對數據一致性有較高的要求,可以使用同步復制機制或者將請求發給主節點處理。

新從庫

有時候需要替換故障從庫或者新增從庫,如何確保新從庫和主庫數據一致呢?簡單的從主節點快照數據復制到新從庫是不行的,因為數據始終可能發生更新;鎖定主庫然后進行快照復制也不值得推薦,因此這違背了高可用原則。啟動新從庫,理論上可以做到不停機,過程如下:

  1. 某個時刻獲取主庫快照,大多數數據庫都具備該功能;

  2. 將快照復制到新從庫節點並應用;

  3. 從庫連接到主庫,開始拉取快照觸發之后發生變更的數據,這要求快照與主庫復制日志中的位置可以精確關聯,比如MySQL中的⼆進制⽇志坐標(binlog coordinates);

  4. 當從庫追上主庫之后,二者達到一致狀態,可以繼續處理后續數據變更了。

並不是所有場景都能不停機起新從庫,比如升級從庫時有的數據庫復制協議不能向后兼容,還有分區擴容場景下的復制等。

復制日志

主從復制底層由以下幾種實現方案,比如基於語句、基於WAL(預寫日志)、基於行日志和基於觸發器等,不同方案有不同的優缺點,下面簡要分析下:

  • 基於語句:最簡單的同步方式,主庫將每個更新語句(udpate/delete/create)都轉發給從庫,從庫解析之后應用到本地,這種方式看上去很合理,不過如果sql中包含非確定值函數的語句,則會造成主從庫不一致,比如NOW()獲取當前時間;

  • 基於WAL:數據庫的數據故障恢復能力,一般都是基於預寫日志實現,因為直接寫到數據頁或索引中相當於隨機寫,而預寫日志是追加方式的順序寫,性能較高;PostgreSQL和Oracle等使⽤這種復制⽅法,主要缺點是⽇志記錄的數據⾮常底層:WAL包含哪些磁盤塊中的哪些字節發⽣了更改(比如Mysql redo日志),這使復制與存儲引擎緊密耦合。如果數據庫將其存儲格式從⼀個版本更改為另⼀個版本,通常不可能在主庫和從庫上運⾏不同版本的數據庫軟件;

  • 基於行日志:也稱為邏輯日志,關系型數據庫通常是基於行粒度來描述數據的寫入序列,對於插入的行,行日志包含所有列的值;對於更新操作,行日志包含列更新前后的值,MySQL的binlog日志就是基於這種方式實現的(statement模式下);

  • 基於觸發器:上面幾種復制策略都是數據庫本身提供的機制,而基於觸發器機制涉及到應用程序代碼,當數據有更新操作時觸發對應的用戶程序進行對應的復制邏輯。

復制延時問題

異步復制模式下存在復制延時問題,當網絡異常或者服務異常時延時問題更嚴重,有的業務對數據延時容忍度較大,比如用戶信息更新對於其他用戶可見來說,延時一定時間無所謂。在讀寫分離場景中,如果讀都是走從庫並且存在延時較長時,會出現用戶剛更新完信息查看信息還是老的,好像剛才更新的數據丟失了,也就是說 ⽤戶寫⼊后從舊副本中讀取數據,這種情況需要讀寫一致性來保證。這是⼀個保證,如果⽤戶重新加載⻚⾯,他們總會看到他們⾃⼰提交的任何更新。它不會對其他⽤戶的寫⼊做出承諾:其他⽤戶的更新可能稍等才會看到。它保證⽤戶⾃⼰的輸⼊已被正確保存。

在主從復制場景中,應該如何實現讀寫一致性呢?首先可以明確的是,在可能存在復制延時場景中需要從主庫讀取數據,比如當前用戶查看更新自己的信息都走主庫,或者用戶更新完成之后讀取數據都走主庫等。如果是公共信息(多個用戶可以同時編輯)的更新操作,可以在客戶端增加更新時間戳,在時間戳最近一定時間內的所有讀取操作都走主庫。

多主復制

主從復制要求更新操作都走主庫,如果客戶端無法連接到主庫則不能進行更新,而基於多主復制的策略中,允許多個節點接收寫入操作。復制仍然以同樣的⽅式發⽣:處理寫⼊的每個節點都必須將該數據更改轉發給所有其他節點, 稱之為多領導者配置(也稱多主、多活復制,比如多機房的異地多活)。在這種情況下,每個領導者同時扮演其他領導者的追隨者。

多主復制場景

比較常見的多主復制場景是多數據中心,要求每個數據中心都有一個主庫,每個數據中心內部使用主從同步,數據中心之間是多主復制,也就是一個數據中心的主庫會復制其他數據中心主庫的數據,多數據中心的多主復制如下圖:

多數據中心對於公司服務運維能力要求較高,一般只有較大公司才玩的轉,畢竟是有一定成本的。多數據中心對於服務來說,需要進行挺大的改造的,比如主鍵ID就需要接入分布式ID方案,不能采用單機數據庫的ID自增方案;多數據中心的多主復制方案可以容忍數據中心停機而不中斷服務,大大提高公司對外服務高可用性。

寫入沖突

討論多數據中心的寫入沖突之前,先看下協同編輯場景中存在的寫入沖突問題,協同編輯比如google docs允許多人同時對一個文件進行編輯操作,為了解決沖突,可以采取用戶在編輯前鎖定文檔,然后編輯之后另一個用戶才能編輯,但是這種方案鎖粒度太大,因此可以使用更小粒度的方案,比如針對文檔中的一個單元格進行鎖定操作。

多領導者復制的最⼤問題是可能發⽣寫沖突,這意味着需要解決沖突,常見的沖突解決可以采用版本思想,比如按照最新時間戳,最大版本號等,但是這種方案可能導致數據覆蓋丟失問題;除了版本思路之外,還可以保留沖突數據,當用戶再次查看數據時,讓用戶選擇使用哪一個沖突版本的數據,比如git的merge沖突等。

無主復制

⼀些數據存儲系統采⽤不同的⽅法,放棄主庫的概念,並允許任何副本直接接受來⾃客戶端的寫⼊。由於無主復制沒有主庫概念,但是也要保證多副本機制,因此需要在客戶端向多個從節點進行寫操作,比如bookkeeper的寫入策略,就是客戶端並發些,只要收到大多數數據節點的ack就認為此次數據寫入成功,這樣就能保證數據的“一致性”。

快照技術

快照技術就是將當前數據狀態存儲到文件,便於存檔,當故障發生時可以使用最近一次的快照恢復數據,由於快照執行一次的成本相對較大,但是為了保證快照數據具有實時性,因此會折中在多少次更新操作或者多長時間后觸發一次快照操作,比如Redis會默認當900s內有一次更新操作,或者300s內有10次更新操作,或者60s內有10000次更新操作,就會觸發RDB持久化(Redis數據快照)。常說的快照技術也就是全量數據保存,還有一種是增量數據保存,比如Redis中的AOF持久化策略。

小結

俗話說,要想提高可用性就進行一次復制操作;如果再想提高可用性,那就再復制一次。復制的本質是冗余數據,提高可用性,注意,復制也不是冗余越多越好,畢竟越多網絡開銷更大,從而影響整體服務性能,需要根據特定場景特定考慮,一般針對數據來說,冗余3份即可。

復制可分為同步復制和異步復制兩種模式,一般來說前者有較高的數據一致性保證,后者有更好的性能保證。復制策略常見的有主從同步、多主同步和無主復制等,主從同步模式容易理解,無主復制需要應用程序多做一些額外的操作保證數據一致性。快照技術也是一種復制模式,常見於本地數據的歸檔保存,比如於故障恢復場景。復制是為了解決高可用問題,如果數據量更大,往往會使用分區+復制的策略來保證高性能和高可用性。

 

 推薦閱讀 


歡迎小伙伴關注【TopCoder】閱讀更多精彩好文。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM