小編給大家分享一下CockroachDB指的是什么,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
永福網(wǎng)站制作公司哪家好,找創(chuàng)新互聯(lián)!從網(wǎng)頁(yè)設(shè)計(jì)、網(wǎng)站建設(shè)、微信開(kāi)發(fā)、APP開(kāi)發(fā)、響應(yīng)式網(wǎng)站建設(shè)等網(wǎng)站項(xiàng)目制作,到程序開(kāi)發(fā),運(yùn)營(yíng)維護(hù)。創(chuàng)新互聯(lián)成立與2013年到現(xiàn)在10年的時(shí)間,我們擁有了豐富的建站經(jīng)驗(yàn)和運(yùn)維經(jīng)驗(yàn),來(lái)保證我們的工作的順利進(jìn)行。專注于網(wǎng)站建設(shè)就選創(chuàng)新互聯(lián)。
介紹
CockroachDB是一個(gè)支持SQL,支持分布式事務(wù)的ACID的分布式數(shù)據(jù),支持ANSI SQL的最高隔離級(jí)別Serializability。
在一個(gè)分布式系統(tǒng)中,要支持Linearizability比較難,因?yàn)椴煌臋C(jī)器之間時(shí)鐘有誤差,需要一個(gè)全局時(shí)鐘。TiDB選擇了和Percolator一樣的方案,單點(diǎn)timestamp oracle提供時(shí)鐘源。Google Spanner直接搞了一個(gè)基于硬件的TrueTime API提供相對(duì)來(lái)說(shuō)比較精準(zhǔn)的時(shí)鐘。CockroachDB沒(méi)有原子鐘,也沒(méi)有使用單點(diǎn)timestamp oracle,而是基于NTP來(lái)盡量同步機(jī)器之間的時(shí)鐘偏移,NTP誤差能達(dá)到250ms甚至更多,并且不能嚴(yán)格保證,這導(dǎo)致CockroachDB要保證Linearizability一致性很難,并且性能差。最終雖然CockroachDB支持Linearizability,但是官方不推薦。默認(rèn),CockroachDB支持Serializable隔離級(jí)別,但是不保證Linearizability。
Serializable
一個(gè)真實(shí)的數(shù)據(jù)庫(kù)系統(tǒng)同一時(shí)刻會(huì)有很多并發(fā)的事務(wù)在執(zhí)行,如何讓這些事務(wù)覺(jué)得只有自己運(yùn)行在數(shù)據(jù)庫(kù)中不受其他事務(wù)的任何干擾是一個(gè)隔離級(jí)別的問(wèn)題。Serializable就是不受任何干擾,弱一點(diǎn)的隔離級(jí)別有Repeatable Read, Read Committed, Read Uncommitted,Snapshot Isolation這些隔離級(jí)別多多少少會(huì)覺(jué)得受到了其他事務(wù)的干擾,如Repeatable Read有幻讀問(wèn)題,Snapshot Isolation有write skew問(wèn)題,具體不贅述??梢詤⒖糰-critique-of-ansi-sql-isolation-levels
要實(shí)現(xiàn)一個(gè)支持Serializable隔離級(jí)別的數(shù)據(jù)庫(kù)挺難的,很多數(shù)據(jù)庫(kù)都不支持Serializable隔離級(jí)別,原因有幾個(gè),我覺(jué)得最重要的原因是性能不行。Oracle 11g默認(rèn)隔離級(jí)別RC,最高隔離級(jí)別Snapshot Isolation,業(yè)界一些知名數(shù)據(jù)庫(kù)對(duì)隔離級(jí)別的支持看When is "ACID" ACID? Rarely. 然而CockroachDB為了實(shí)現(xiàn)Serializable,花了大量的功夫。
一個(gè)事務(wù)通常包含多個(gè)讀寫(xiě)操作,操作不同的行/列。數(shù)據(jù)庫(kù)系統(tǒng)會(huì)對(duì)系統(tǒng)中的事務(wù)進(jìn)行調(diào)度,事務(wù)會(huì)交叉執(zhí)行,而不是一個(gè)接著一個(gè)。
一共三個(gè)事務(wù),上圖是數(shù)據(jù)庫(kù)系統(tǒng)對(duì)這三個(gè)事務(wù)的一種調(diào)度。那么這個(gè)調(diào)度是不是Serializable的?這個(gè)有理論支持: serializability graph。這個(gè)理論引入了三種沖突,三種沖突都是對(duì)于不同的事務(wù)操作同一個(gè)數(shù)據(jù)而言:
RW: W覆蓋了R讀到的值
WR: R讀到了W更新的值
WW: W覆蓋了第一個(gè)W更新的值
對(duì)于任何一個(gè)事務(wù)調(diào)度結(jié)果,如果兩個(gè)事務(wù)存在某種沖突,就在事務(wù)之間連上有向邊(后面的事務(wù)指向前面的事務(wù))。下圖是上面事務(wù)調(diào)度的serializability graph。
已經(jīng)證明如果一個(gè)事務(wù)調(diào)度的serializability graph中不存在環(huán),那么這個(gè)事務(wù)調(diào)度就是Serializable的。那么CockroachDB是怎么做的?
CockroachDB事務(wù)處理系統(tǒng)
多版本
CockroachDB的事務(wù)是Lock-Free的,不需要加任何讀寫(xiě)鎖,自然就需要維護(hù)數(shù)據(jù)的多個(gè)版本,版本通過(guò)timestamp來(lái)標(biāo)識(shí)。
ACID中的A和I密切相關(guān),都是通過(guò)并發(fā)控制協(xié)議保證的,下面先說(shuō)明A是如何保證的,然后說(shuō)明在并發(fā)的情況下,I是如何保證的。并發(fā)控制協(xié)議保證了A和I。
原子性
一個(gè)分布式事務(wù)可能會(huì)對(duì)多個(gè)節(jié)點(diǎn)上的數(shù)據(jù)進(jìn)行讀寫(xiě),如何保證原子性? 大家都知道分布式事務(wù)都是2PC,第一階段做Prepare,把需要的讀的數(shù)據(jù)讀進(jìn)來(lái)(怎么保證讀到最新的數(shù)據(jù),后面會(huì)說(shuō),這里先假設(shè)能讀到),計(jì)算,最后把計(jì)算后的數(shù)據(jù)寫(xiě)入各個(gè)節(jié)點(diǎn),但是不對(duì)外生效,即系統(tǒng)中其他事務(wù)暫且讀不到這個(gè)數(shù)據(jù)。這種已經(jīng)寫(xiě)入各個(gè)節(jié)點(diǎn),但是沒(méi)有生效的數(shù)據(jù)CockroachDB把它叫做write intent,這種write intent和實(shí)際的數(shù)據(jù)存儲(chǔ)在一起,只是外部讀不到而已。
那么這個(gè)事務(wù)的狀態(tài)存在哪?事實(shí)上,在一個(gè)事務(wù)開(kāi)始的時(shí)候,會(huì)往底層存儲(chǔ)系統(tǒng)中寫(xiě)入一條記錄,這個(gè)記錄叫做Transaction Record,record會(huì)記錄事務(wù)ID,事務(wù)狀態(tài),Pending(正在運(yùn)行)還是Committed,還是Aborted,而write intent里存在key指向這個(gè)Transaction Record。提交事務(wù),只需要把Transaction Record中的事務(wù)狀態(tài)改成Committed即可,回滾事務(wù)改成Aborted即可。一旦事務(wù)狀態(tài)修改成功,就可以返回給客戶端,遺留的write intent會(huì)異步處理:commit時(shí),將write intent的值覆蓋原始值,刪掉write intent,rollback時(shí)直接刪掉write intent即可。
隨后客戶端過(guò)來(lái)讀的時(shí)候,如果碰到了write intent(之前說(shuō)了,write intent是異步刪除),就會(huì)沿著write intent找到Transaction Record,看看事務(wù)的狀態(tài),如果狀態(tài)是committed,返回write intent中的值,如果Abort就會(huì)返回原始的值。如果是Pending,說(shuō)明這個(gè)事務(wù)還在正常跑,遇到了寫(xiě)寫(xiě)沖突,如何解決寫(xiě)寫(xiě)沖突? 這個(gè)牽扯到隔離級(jí)別和并發(fā)控制協(xié)議,看下面。
隔離性
之前提到,數(shù)據(jù)是多版本的,版本通過(guò)timestamp來(lái)標(biāo)識(shí)。timestamp是讀寫(xiě)事務(wù)/寫(xiě)事務(wù)在事務(wù)開(kāi)始的時(shí)候從本機(jī)拿到的wall time(實(shí)際上是HLC,一種基于物理時(shí)鐘的可以捕獲因果關(guān)系的邏輯時(shí)鐘),這個(gè)timestamp只是這個(gè)事務(wù)最后commit的候選timestamp而已,不一定是最終的commit的timestamp(根本原因是機(jī)器之間存在時(shí)鐘offset,后面會(huì)講到),這里先假定,拿到了一個(gè)最終的timestamp。timestamp越大,說(shuō)明版本越新。這個(gè)事務(wù)的所有寫(xiě)入的數(shù)據(jù)都會(huì)打上這個(gè)timestamp作為版本標(biāo)識(shí)。在這樣一個(gè)系統(tǒng)中,serializability graph大概是下面的樣子:
上面這個(gè)圖是無(wú)環(huán)的。下面這個(gè)圖是有環(huán)的:
回到Serializability,為了實(shí)現(xiàn)Serializability,需要保證事務(wù)的調(diào)度是無(wú)環(huán)的。CockroachDB通過(guò)在timestamp的反方向避免之前提到的三種沖突,從而在圖中就不會(huì)有和timestamp走向一致的邊,進(jìn)而保證無(wú)環(huán)。最后,CockroachDB的serializability graph長(zhǎng)如下樣子:
CockroachDB保證如下約束:
RW: W的時(shí)間戳只能比R的大,這只會(huì)產(chǎn)生回頭邊(通過(guò)在每個(gè)節(jié)點(diǎn)維護(hù)一個(gè)Read Timestamp Cache)。
WR: R只會(huì)讀比自己timestamp小的最大的版本,這也只會(huì)產(chǎn)生回頭邊。
WW:第二W的timestamp比第一個(gè)W的timestamp大,這也只會(huì)產(chǎn)生回頭邊。
也就是說(shuō),只要保證一個(gè)事務(wù)只與timestamp更小的事務(wù)沖突,就能保證無(wú)環(huán)。
Recoverable
殘酷的是,僅僅保證無(wú)環(huán)能實(shí)現(xiàn)Serializability,同時(shí)還需要保持?jǐn)?shù)據(jù)庫(kù)的一致性,即ACID中的C??紤]如下場(chǎng)景:
T1,T2兩個(gè)事務(wù),timestamp(T1) < timestamp(T2),T1更新A,還沒(méi)有提交,T2讀A。這是一個(gè)WR沖突,但是由于這個(gè)沖突是回頭邊,所以是允許的。為了維護(hù)上面提到的RW約束,T2必須讀T1的更新(W的timestamp必須比R大,然而T1比T2小)。然而,T2讀T1對(duì)A的更新有什么問(wèn)題?
T2讀T1的更新。如果最后T2 commit,隨后T1回滾,這個(gè)會(huì)違反T1的原子性:T1沒(méi)有寫(xiě)成功的值被T2讀到了。
CockroachDB使用一種比較苛刻的調(diào)度來(lái)處理這種場(chǎng)景:所有的操作只能在已經(jīng)committed的數(shù)據(jù)上進(jìn)行!下面講講CockroachDB的這種苛刻的調(diào)度是如何保證的,這里就需要用到前面原子性的知識(shí)。
Strict Scheduling
從上一節(jié)以及原子性章節(jié)可以得知,一個(gè)事務(wù)碰到了一個(gè)write intent,那么說(shuō)明有可能寫(xiě)write intent的事務(wù)還沒(méi)有結(jié)束(因?yàn)閣rite intent是異步清除的),這就說(shuō)明有可能碰到了uncommitted的數(shù)據(jù)。這時(shí),當(dāng)前事務(wù)會(huì)去檢查write intent所在的事務(wù)的狀態(tài),如果已經(jīng)提交了,將write intent覆蓋舊值然后清除write intent即可。如果已經(jīng)回滾了,那么直接清除write intent就行。如果是Pending,正在運(yùn)行呢?這個(gè)時(shí)候,就要看事務(wù)的優(yōu)先級(jí)了,優(yōu)先級(jí)低的事務(wù)需要abort,事務(wù)開(kāi)始時(shí)賦予的優(yōu)先級(jí)是random的。CockroachDB會(huì)保證被abort的事務(wù)在restart之后優(yōu)先級(jí)會(huì)提高。
到這里,CockroachDB如何提供Serializability隔離級(jí)別就講完了,注意,這里的前提是每個(gè)事務(wù)都被賦予了一個(gè)合適的timestamp,什么叫做合適的 timestamp? 一個(gè)分布式讀/讀寫(xiě)事務(wù)需要能讀到最新的已經(jīng)committed的數(shù)據(jù)。
CockroachDB如何為事務(wù)賦予時(shí)間戳
CockroachDB使用NTP進(jìn)行時(shí)鐘同步,NTP基本能保證機(jī)器之間的時(shí)鐘offset小于250ms,但是這也不絕對(duì),這受到網(wǎng)絡(luò)延時(shí),系統(tǒng)load等因素的影響。從前面可以看出,CockroachDB的Serializability依賴于集群內(nèi)機(jī)器之間的時(shí)鐘clock在一個(gè)范圍ε內(nèi)。這個(gè)范圍可以配置,默認(rèn)250ms。任何一個(gè)時(shí)刻,在一臺(tái)機(jī)器上拿到wall time為t,那么集群中可能存在的最大wall time是t+ε。
一個(gè)事務(wù)T開(kāi)始時(shí),先拿一個(gè)本地Wall time(實(shí)際上是HLC),記作t,根據(jù)NTP定義,集群內(nèi)機(jī)器此刻最大的Wall time為t+ε,如果事務(wù)執(zhí)行過(guò)程中讀到的數(shù)據(jù)對(duì)象處于[t,t+ε]之間,我們是不知道這個(gè)值到底是在T開(kāi)始之后才commit的,還是T開(kāi)始之前就commit的。所以T需要restart,重新設(shè)置t為碰到的這個(gè)timestamp。
以上是“CockroachDB指的是什么”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!