高可用的本質: 複製

服務和數據的高可用性本質上是靠“複製”來解決的,比如服務通過集羣部署多臺機器來完成,數據通過冗餘的多副本機制來完成。對於服務來說,只需要部署多個實例即可,特別是無狀態服務,常見的微服務(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】閱讀更多精彩好文。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章