前言算法
分佈式數據庫的數據一致性管理是其最重要的內核技術之一,也是保證分佈式數據庫知足數據庫最基本的 ACID特性中的 「一致性」(Consistency)的保障。在分佈式技術發展下,數據一致性的解決方法和技術也在不斷的演進,本文就以做者實際研發的分佈式數據庫做爲案例,介紹分佈式數據庫數據一致性的原理以及實際實現。數據庫
大部份使用傳統關係型數據庫的DBA在看到「數據一致性」時,第一反應可能都是數據在跨表事務中的數據一致性場景。可是本文介紹的「數據一致性」,指的是「數據在多份副本中存儲時,如何保障數據的一致性」場景。安全
因爲在大數據領域,數據的安全再也不由硬件來保證,而是經過軟件手段,經過同時將數據寫入到多個副本中,來確保數據的安全。數據庫在同時向多個副本寫入記錄時,如何確保每一個副本數據一致,稱爲「數據一致性」。服務器
傳統的關係型數據庫對於運行環境--硬件要求都比較高,例如Oracle會建議用戶使用小型機+共享存儲做爲數據庫的運行環境,DB2 DPF也一樣建議用戶採用更好的服務器+高端存儲來搭建數據庫的運行環境。因此在數據存儲安全的技術要求下,傳統關係型數據庫更可能是依賴硬件的技術來保障數據的安全性。併發
由於關係型數據庫的數據安全是基於硬件來保障,而且數據也不會經過同時存儲多份來保障數據的安全,因此關係型數據庫的用戶默認認爲數據存儲是一致的。異步
本文在討論分佈式存儲時,主要指的是大數據產品中的分佈式文件系統和分佈式數據庫,例如:SequoiaDB和HDFS。分佈式
用戶在搞明白分佈式存儲的數據一致性原理時,必需要先明白爲何他們就須要數據一致性,和分佈式存儲的數據存儲與關係型數據庫的數據存儲又有什麼區別。性能
大數據技術的誕生,確確實實讓系統的性能有新的突破,而且支持硬件以水平擴展的方式來得到線性增加的性能和存儲。這些都是過去傳統關係型數據庫所沒法提供的。另外,大數據技術也拋棄了運行環境必須足夠好的硬性要求,而是容許用戶經過批量廉價X86服務器+本地磁盤的方式搭建規模集羣,從而得到比過去依賴硬件垂直擴展所提供的更強的計算能力和更多的存儲空間。大數據
大數據技術的核心思想就是分佈式,將一個大的工做任務分解成多個小任務,而後經過分佈式併發操做的方式將其完成,從而提升整個系統的計算效率或者是存儲能力。而在分佈式環境下,因爲硬件的要求下降,必然須要大數據產品提供另一個重要的功能--數據安全。spa
大數據產品在解決數據安全的方式上,都比較接近,簡單來講,就是讓一份數據經過異步或者同步的方式保存在多臺機器上,從而保障數據的安全。
分佈式存儲在解決數據安全的技術難點後,又引入了一個新的技術問題,就是如何保障多個副本中的數據一致性。目前SequoiaDB是使用Raft算法來保證數據在多個副本中一致性。
在分佈式環境下,最著名的一致性算法應該是Paxos算法,可是因爲它實在過於晦澀難懂,而且實現起來極度困難,因此在2013年,Diego Ongaro、John Ousterhout兩我的以易懂(Understandability)爲目標設計了一套一致性算法Raft。Raft算法最大的特色在於簡單易懂,而且實現起來簡單。
與Paxos不一樣,Raft強調的是易懂,Raft和Paxos同樣只要保證n/2+1節點正常就可以提供服務。
衆所周知當問題較爲複雜時能夠把問題分解爲幾個小問題來處理,Raft也使用了分而治之的思想。Raft算法重點解決三個子問題:選舉(Leader election)、日誌複製(Log replication)、安全性(Safety)。
Raft算法強化了Leader節點的功能,Follower節點的數據只可以從Leader中獲取,因此Follower節點的實現就變得簡單,只要負責和Leader保持通訊,而且接受Leader推送的數據便可。
Raft算法中,對節點的狀態分爲3種角色,分別是Leader(領導者)、Follower(追隨者)和Candidate(候選者)。
Leader,負責處理來自客戶端的請求,負責將日誌同步到Follower中,而且保證與Follower之間的heartBeat聯繫;
Follower,當集羣剛剛啓動時,全部節點均爲Follower狀態,它的工做主要爲響應Leader的日誌同步請求,響應Candidate的請求,以及把請求到Follower的事務請求轉發給Leader;
Candidate,選舉Leader時負責投票,選舉出來Leader後,節點將從Candidate狀態變爲Leader狀態。
在分佈式環境下,「時間同步」一直都是老大難的技術難題。Raft爲了解決這個問題,將時間劃分爲一個一個的Term(能夠理解爲「邏輯時間」)來處理在不一樣時間段裏的數據一致性。
Terms有如下原則
1 每一個Term中,至多存在一個Leader
2 某些Term中,有可能存在因爲選舉失敗,沒有Leader的狀況
3 每一個節點本身維護本地的currentTerm
4 每一個Term都是一個連續遞增的編號
5 若是Follower的Term編號比別的Follower Term編號小時,該Follower Term編號將更新Term編號,以保持與其餘Follower Term編號一致
Raft的選舉由定時器觸發,每一個節點的觸發時間都不相同。
全部的節點在開始時狀態都爲Follower,當定時器觸發選舉後Term編號遞增,該節點的狀態由Follower轉爲Candidate,而且向其餘節點發起RequestVote RPC請求,這時選舉有3種狀況可能發生:
1 發起RequestVote的節點收到n/2+1(過半數)個節點的投票,該節點將從Candidate狀態變爲Leader狀態,開始向其餘節點發送HeartBeat以保持Leader的正常狀態
2 若是收到投票請求後,該節點發現發起投票的節點Term大於本身,則該節點狀態從Candidate轉爲Follower,不然保持Candidate狀態,而且拒絕該投票請求
3 選舉期間發生了超時,則Term編號遞增,從新發起選舉
日誌複製主要的做用就是用來保證節點的數據一致性與高可用性。
當Leader被選舉出來後,全部的事務操做都必需要通過Leader處理。這些事務操做成功後,將會被按順序寫入到LOG中,每一個LOG都包含一個index編號。
Leader在LOG發生變化後,經過HeartBeat將新的LOG同步到Follower上,Follower在接收到LOG後,再向Leader發送ACK信息,當Leader接到大多數(2/n+1)Follower的ACK信息後,將該LOG設置爲已提交,而且Leader將LOG追加到本地磁盤中。
同時Leader將在下一個HeartBeat中,通知全部的Follower將該LOG存儲在各自的本地磁盤中。
安全性是用於確保每一個節點都是按照相同的日誌序列進行執行的安全機制。
若是當某個Follower在同步Leader的日誌時失敗,可是將來該Follower又可能被選舉爲Leader時,就有可能致使前一個Leader已經commit的日誌發生覆蓋,這樣就致使了節點執行不一樣序列的日誌。
Raft的安全性就是用於保證選舉出來的Leader必定包含先前已經commit LOG 的機制,主要遵循的原則以下
1 每一個Term 只能選舉一個Leader
2 Leader的日誌完整性,則當Candidate從新選舉Leader時,新的Leader必需要包含先前已經commit的LOG
3 Candidate在選舉新的Leader時,使用Term來保證LOG的完整性
以國產原廠的分佈式數據庫SequoiaDB爲例,SequoiaDB在多副本的部署中,採用Raft算法保證數據在多副本環境中保持一致。
SequoiaDB集羣中,總共包含3中角色節點,分別是協調節點、編目節點和數據節點。因爲協調節點自己不存任何數據,因此只有編目節點和數據節點存在事務操做,換言之,編目分區組和數據分區組的副本同步採用Raft算法保證數據一致性。
編目節點和數據節點因爲都是須要存儲數據的,而且在集羣部署中該,爲了確保數據的安全,都是建議採用分佈式的方式進行部署,因此在數據同步中,須要採用Raft算法的基本原理進行數據同步。
編目節點和數據節點在存儲數據時,共包含兩大部分,一個真實的數據文件,另外一個是事務日誌文件。
SequoiaDB的節點事務日誌,默認狀況下由20個64MB(總大小爲1.25GB)的文件構成。節點的事務日誌主要包含一個index編號和數據操做內容,index編號保持永遠遞增狀態。
另外,SequoiaDB節點的事務日誌不會永久保存,而是當全部的事務日誌寫滿後,再從新從第一個文件開始進行覆蓋寫入。
因爲編目分區組是保存SequoiaDB集羣的元信息,數據同步要求高,因此編目分區組的數據一致性要求爲強一致性,即每次向編目分區組執行事務操做時,必需要確保全部的編目節點操做成功,才計算該操做執行成功,不然該事務操做將在整個編目分區組中回退事務日誌,以保證分區組內的數據一致性。
另外,編目分區組還有一個比較重要的特性,即編目分區組必需要存在主節點纔可以正常工做,若是老的主節點宕機了,編目分區組暫時沒有主節點,則該編目分區組不可以對外提供任何事務操做和數據查詢操做。
數據分區組的數據一致性默認狀況下爲最終一致性性,即只要求主節點執行事務操做成功即視爲操做成功,主節點將在將來異步同步ReplicaLOG到從節點上。
SequoiaDB的主從節點是經過事務日誌同步來保證數據一致性的,而且主從節點的事務日誌同步是單線程完成。
若是當主節點和從節點的LSN差距爲一條記錄,則主節點會主動將最新的事務日誌推送給從節點。
若是主節點和從節點的LSN差距超過一條記錄,則從節點會主動向主節點請求同步事務日誌,主節點收到同步請求後,會將從節點的LSN號到主節點最新的LSN號對應的事務日誌打包一次性發送給從節點。
當從節點獲取到主節點推送過來的事務日誌後,就會自動解析事務日誌和重放。從節點在重放事務日誌時,默認狀況下會以10併發來重放事務日誌。
從節點在執行併發重放日誌時有條件限制,即在集合的惟一索引個數<=1的狀況下,INSERT、DELETE、UPDATE、LOB WRITE、LOB UPDATE、LOB REMOVE操做能夠支持併發重放事務日誌。從節點在作併發重放時,是經過記錄的OID進行打散併發執行,這樣就能夠保證對相同記錄的操做不會因爲併發重放致使數據不一致。
可是用戶須要注意,從節點在重放事務日誌時, DROP CL操做不可以支持併發重放。
目前SequoiaDB數據分區組的數據一致性是基於集合級別進行配置的。用戶在使用SequoiaDB過程當中,能夠隨時調整數據一致性的強度。
在一個多副本的SequoiaDB集羣中,集合默認的數據一致性行級別爲「最終一致性」。用戶能夠在建立集合時顯式指定該集合的「數據一致性強度」,例如能夠在SequoiaDB Shell中執行如下命令
db.CSNAME.createCL("CLNAME", {ReplSize:3})
ReplSize參數填寫範圍
數值 |
參數說明 |
-1 |
表明彈性強一致性; 例如副本數爲3,當全部的副本節點都正常運行時,數據庫將確保數據同時成功寫入3個副本中才提交該事務日誌; 若是其中一個節點宕機,可是該數據分區組中仍然存在主節點,則數據庫須要確保數據同時成功寫入2個副本中才提交事務日誌。 |
0 |
表明強一致性; 例如副本數爲3,當全部的副本節點都正常運行時,數據庫將確保數據同時成功寫入3個副本中才提交該事務日誌; 若是其中一個節點宕機,可是該數據分區組中仍然存在主節點,則數據庫仍然須要確保數據同時成功寫入3個副本中才提交事務日誌,因此當分區組中存在宕機節點,則該數據分區組沒法寫入新的記錄。 |
1-7 |
1-7數值表明分區組中寫入記錄時,應該確保寫入到多少個節點中,才能夠提交該事務日誌,不然認爲該事務操做失敗,另外,若是填寫的數值大於數據分區組全部的節點數目,則以數據分區組的最大節點數目爲生效RepliSize值,可是在數據庫SDB_SNAP_CATALOG快照中依然顯式用戶填寫的ReplSize數據。 |
若是集合在建立時沒有設置「數據一致性」ReplSize參數,用戶也能夠對已經存在的集合進行修改,在SequoiaDB Shell修改命令以下
db.CSNAME.CLNAME.alter ({ReplSize:3})
ReplSize的取值範圍和建立集合時一致。
若是用戶但願檢查當前集合的RepliSize參數值,能夠經過數據庫快照進行查看,在SequoiaDB Shell查看命令以下
db.snapshot(SDB_SNAP_CATALOG, {}, {"Name":null, "IsMainCL":null, "MainCLName":null, "ReplSize":null})
打印信息以下
{
"MainCLName": "test.main2",
"Name": "foo.bar2",
"IsMainCL": null,
"ReplSize": null
}
{
"IsMainCL": true,
"Name": "test.main2",
"MainCLName": null,
"ReplSize": null
}
{
"Name": "foo.tt",
"ReplSize": 3,
"IsMainCL": null,
"MainCLName": null
}
分佈式的數據庫,經過Raft算法來確保在分佈式狀況上數據的一致性,而且編目分區組和數據分區組對數據一致性要求又有所不一樣,編目分區組始終要求的是數據在多副本請狀況下數據強一致性,而數據分區組則能夠由用戶在建立集合時來執行數據一致性的強度,強度越高,數據安全性越好,可是執行的效率就會相對較差,反之依然。
目前SequoiaDB在數據一致性場景上,用戶的調整空間較大,能夠根據不一樣的業務要求來調整數據一致性的強度,以知足業務或追求性能最優,或者數據最安全的技術要求。
SequoiaDB巨杉數據庫簡介:
SequoiaDB是業界領先的新一代分佈式數據庫產品,功能上包括了分佈式OLTP,分佈式對象存儲以及分佈式NoSQL實現全類型數據的覆蓋。SequoiaDB爲用戶提供高性能、靈活存儲、實時與可擴展等企業級數據庫能力。