spanner 的前世今生
spanner的前身是big table,讓我們先來看看big table這個(gè)老子的方方面面,然后再來看看兒子spanner為啥一出世就吸引了全球技術(shù)人員的眼球。
2006年,google 發(fā)表了big table [1]的文章,為什么要做big table,下面有一個(gè)簡短的總結(jié)[2]:
就是一個(gè)問題:數(shù)據(jù)太多,訪問量太大,規(guī)模問題出現(xiàn)。規(guī)模是問題的源泉,是后續(xù)故事的核心,在此基礎(chǔ)上才碰到了動(dòng)態(tài)schema(semi-structure帶來的問題,比如big table支持的schema change),全局可用,數(shù)據(jù)一致讀寫等問題。
big table的數(shù)據(jù)模型是?<row, column, timestamp> -> cell content ,每個(gè)cell都是一個(gè)三維空間中的一個(gè)點(diǎn),每個(gè)維度都是動(dòng)態(tài)可配置的(行可以隨意增加,列可以隨意增加,時(shí)間序列可以隨意增加),非常靈活自由。
big table 的系統(tǒng)架構(gòu),解決數(shù)據(jù)和訪問在一個(gè)cluster內(nèi)部如何分配:將數(shù)據(jù)分片,每臺(tái)tablet server load 若干分片,有一個(gè)核心節(jié)點(diǎn)master來做全局信息同步。
在big table 論文發(fā)布之后,big table一直在改進(jìn),主要是致力于提供更好的scalability;加入了跨cluster(一般是跨機(jī)房的cluster)的數(shù)據(jù)異步復(fù)制以及Coprocessor(HBase的coprocess應(yīng)該也是從這里引入)。
?
google 大哥在成長,工程師需要更好用的結(jié)構(gòu)化存儲(chǔ),big table 看來在以下幾個(gè)方面做的不夠好:
1. 分布式transaction:比如A給B發(fā)送了一個(gè)消息,那么A的發(fā)件箱和B的收件箱應(yīng)該同時(shí)有一封信件,這是一個(gè)完整的事務(wù),應(yīng)該遵循事務(wù)的ACID原則,但是big table無法支持,其只支持single-row-transactions。這也也好理解,在啥都沒有的情況下,big table的出世就足以讓人興奮,誰會(huì)為分布式transaction傷腦筋呢?不過日子越過越好,人們的要求也越來越高,這件事情就逃避不掉了。
2. 強(qiáng)一致性數(shù)據(jù)同步:即使某些用戶不要求分布式transaction,那么強(qiáng)一致性也是希望提供的,也就是說在數(shù)據(jù)沒有同時(shí)主、備集群寫入之前,不要返回client成功的消息。應(yīng)用有此需求也容易理解,如果你主集群寫完就返回,然后主集群掛了,我最新的數(shù)據(jù)不是丟了嗎?
3. SQL語言支持:大家都很懶
4. 全球負(fù)載均衡:負(fù)載均衡是個(gè)很大的話題,包括存儲(chǔ)負(fù)載(存儲(chǔ)空間全球數(shù)據(jù)中心共享)、調(diào)度負(fù)載(在全球數(shù)據(jù)中心內(nèi)平衡CPU/MEM利用)、網(wǎng)絡(luò)負(fù)載(在全球數(shù)據(jù)中心內(nèi)平衡網(wǎng)絡(luò)流量)、距離負(fù)載(讓數(shù)據(jù)緊貼應(yīng)用進(jìn)行全球移動(dòng))
?
不得不說,系統(tǒng)真的是一步步進(jìn)步的,人們的需求真的是一步步提高的,如果不是big table做出來,這些問題估計(jì)沒人敢想。也正是因?yàn)檫@些問題的存在,Spanner[3]橫空出世。
看看spanner解決了哪些問題:
Spanner is Google’s scalable, multi-version, globally distributed,?and synchronously-replicated database
Spanner’s main focus is managing cross-datacenter?replicated data, providing?externally consistent [16] reads and writes, and
globally-consistent reads across the database.
最核心的是兩點(diǎn):
1. 分布式transaction
2. 全球自動(dòng)化負(fù)載均衡(細(xì)粒度切分和全球數(shù)據(jù)復(fù)制都是為這個(gè)目的服務(wù)的)
Spanner 體系架構(gòu):
A Spanner deployment is called a universe. 全球只有三個(gè)spanner,分別用于測試、開發(fā)/生產(chǎn)(VS dark launching from Facebook ?)和生產(chǎn)。
Spanner is organized as a set of zones, where each?zone is the rough analog of a deployment of Bigtable. 全球big table 集群(類比)被統(tǒng)一管理,統(tǒng)一調(diào)度起來就是spanner。
The universe master is primarily a console that?displays status information about all the zones for interactive?debugging. universe master并不是用來服務(wù)系統(tǒng)的,更像是個(gè)管理工具。
?
?
?tablet和paxos state machine共存,多個(gè)互為replica的tablet和paxos state machine形成了paxos group,其中有一個(gè)是leader,也就是用于寫的tablet,保管lock table等。該leader同時(shí)也是一個(gè)transaction manager,用于實(shí)現(xiàn)分布式transaction。當(dāng)實(shí)現(xiàn)分布式transaction時(shí)候,有不止一個(gè)paxos group參與進(jìn)來,這時(shí)候有一個(gè)group會(huì)被選作coordinator group,則該group的leader就是coordinator leader,該group的slave就是coordinator slave。(這部分跟Spanner沒多少關(guān)系,是distributed transaction的經(jīng)典內(nèi)容)
在big table中,tablet只是行數(shù)據(jù)的容器,tablet內(nèi)部的行都是一視同仁的;而spanner對(duì)tablet進(jìn)行了進(jìn)一步的結(jié)構(gòu)劃分,多了一層dictionary結(jié)構(gòu),用以區(qū)分那些PK前綴相同的行(比如,所有以Alice開頭的行都在一個(gè)dictionary里面)。dictionary是數(shù)據(jù)復(fù)制和placement配置的基本單位,比如某個(gè)dictionary要分布在亞洲和美洲,共4份拷貝。
spanner中負(fù)載均衡的最小單位也是dictionary,同時(shí)提供方法MoveDir可以手動(dòng)將一個(gè)dictionary移動(dòng)到指定的zone。文中提到dictionary只是一層抽象目錄,下面還有fragment才是真正的物理目錄,有點(diǎn)詫異。細(xì)粒度當(dāng)然可以更加優(yōu)化負(fù)載均衡以及數(shù)據(jù)恢復(fù),但是太細(xì)的粒度也意味著復(fù)雜度成倍增加,這是不是值得呢?可能的原因是某些用戶的dictionary目錄里面數(shù)據(jù)還是太多,而同時(shí)反正分布式transaction已經(jīng)實(shí)現(xiàn),不同fragment之間交互也順便可以借點(diǎn)光,沒有增加太多的實(shí)現(xiàn)負(fù)擔(dān),不過我仍然感覺到這點(diǎn)做的太復(fù)雜了。
另外,文中雖然沒寫,根據(jù)之前的一些資料,dictionary應(yīng)該也是權(quán)限控制的最小單元。
?
關(guān)于數(shù)據(jù)模型:
關(guān)于big table 不實(shí)現(xiàn)傳統(tǒng)transaction的理由是:我們認(rèn)為這些transaction太復(fù)雜,程序員會(huì)過度使用transaction從而導(dǎo)致性能太差,所以不實(shí)現(xiàn)。
而這里spanner實(shí)現(xiàn)傳統(tǒng)的transaction的理由是:系統(tǒng)的職責(zé)是實(shí)現(xiàn)應(yīng)該有的功能,如果程序員用錯(cuò)了,那么改正就行了;但是如果系統(tǒng)不實(shí)現(xiàn),誰也沒辦法用。
上面應(yīng)該是經(jīng)典的需求實(shí)現(xiàn)問題,不同的人會(huì)有不同的理解。
spanner的行模型是?(key:string, timestamp:int64) -> row content,可以看到跟big table的模型最大的不同是這里強(qiáng)化了row的概念,不再突出column;這樣spanner的timestamp是賦給整行數(shù)據(jù)的,是有物理意義的,這使得spanner更像一個(gè)實(shí)現(xiàn)多版本并發(fā)的數(shù)據(jù)庫,而在big table中,timestamp僅僅用于保存多個(gè)版本的key-value,跟并發(fā)完全無關(guān);我覺得這也是為什么spanner稱自己為semi-relational 數(shù)據(jù)庫,而big table只稱自己是semi-structure 數(shù)據(jù)庫的原因。
下面是spanner的數(shù)據(jù)表模式,其中user是一張父親表,album一張子表(不存在沒有user的album),這非常像一個(gè)樹形結(jié)構(gòu),user樹枝,blbum是樹葉,多么清晰,好的東西都是易于理解的,大部分時(shí)候也是難于實(shí)現(xiàn)的。
?
關(guān)于TrueTime:只要知道兩點(diǎn)就可以了:
1. 一堆機(jī)器投票來決定當(dāng)前時(shí)間應(yīng)該是多少,然后按人頭計(jì)數(shù),人多者勝。
2. 跟傳統(tǒng)投票不同的是,每個(gè)人不是報(bào)來一個(gè)數(shù)字,而是根據(jù)一般誤差報(bào)上一個(gè)范圍來,比如A報(bào)[3-4], B 報(bào)[4-5], C報(bào)[3-5],結(jié)果就會(huì)變成4,因?yàn)槊咳硕纪猬F(xiàn)在是4點(diǎn)。再詳細(xì)的話請(qǐng)看原論文吧。
?
并發(fā)控制:
1. 對(duì)于什么是external consistency, 我理解不深,覺得就當(dāng)成serializable transaction的一種實(shí)現(xiàn)協(xié)議,和基于lock的、基于MVCC啥的并列,就可以了。解釋:provides the illusion that each operation applied by concurrent processes takes effect instantaneously at some point between its invocation and its response, implying that the meaning of a concurrent object's operations can be given by pre- and post-conditions.?
2. 一個(gè)paxos group內(nèi)的leader通過投票選出來,通過不停的延長lease繼續(xù)擔(dān)當(dāng)leader的角色,文中提到paxos group內(nèi)任何兩個(gè)paxos leader必須保證disjointness invariant,這是為什么呢?因?yàn)槊總€(gè)leader都要給自己這個(gè)group內(nèi)執(zhí)行的transaction分配一個(gè)timestamp, 如果兩個(gè)leader的interval有重疊,那么就不能保證所有l(wèi)eader在分配timestamp時(shí)候全局單調(diào)遞增。其實(shí)就是說,咱們倆一人一個(gè)時(shí)間段,這個(gè)時(shí)間段內(nèi)的時(shí)間點(diǎn)隨便我們分配,只要我們各自保證分配的時(shí)間單調(diào)遞增,則咱倆都是單調(diào)遞增的。
3. 文中一堆時(shí)間,簡單抽象一下就是:spanner不依靠事件通信來保證transaction一致性,而是依靠嚴(yán)格的時(shí)間序列。
一個(gè)極端簡單的例子:某個(gè)partition內(nèi)部最新commit的一個(gè)transaction的完成時(shí)間是3點(diǎn),當(dāng)前還有兩個(gè)transaction繼續(xù)在執(zhí)行,不知道什么時(shí)候結(jié)束,那么如果這時(shí)候有一個(gè)讀請(qǐng)求過來,那么我們只能認(rèn)讓這個(gè)讀的請(qǐng)求看到(visible)3點(diǎn)之前的數(shù)據(jù),因?yàn)?點(diǎn)之后的數(shù)據(jù)可能只寫了一半,是不允許讀的。那么文中那么多的時(shí)間序列和假設(shè)就是為了保證讀請(qǐng)求過來的時(shí)候,我們能準(zhǔn)確的找到3點(diǎn)這個(gè)數(shù)字。很容易?如果是單機(jī)當(dāng)然容易,如果有一堆機(jī)器參與了分布式transaction,找到3這個(gè)數(shù)字并不是輕而易舉。
4. 幾種操作
讀寫操作:最典型的操作,基于鎖的并發(fā)控制,只不過使用樂觀鎖,如果出現(xiàn)沖突,某些低優(yōu)先級(jí)的transaction先終止(系統(tǒng)會(huì)自動(dòng)再重試),高優(yōu)先級(jí)的先完成。在準(zhǔn)備寫之前,依然是決定timestamp,如果不是分布式transaction,則自己選一個(gè)時(shí)間就可以了;如果是分布式transaction,則同時(shí)收取所有participant的建議,選一個(gè)最大的,再跟cooperator自己的now比較選個(gè)大的,繼續(xù)向下進(jìn)行。
只讀操作:跟上面舉的例子類似,就是找個(gè)最近剛commit的transaction的時(shí)間點(diǎn),然后返回該時(shí)間點(diǎn)之前寫入的數(shù)據(jù)。值得注意的是,這時(shí)候,因?yàn)樗械膔eplica都已經(jīng)完成了寫入,所以該時(shí)間點(diǎn)只要找到了之后,可以隨便挑一個(gè)replica進(jìn)行讀。
SnapshotRead:這就不用說了,時(shí)間點(diǎn)都省的找了,client會(huì)提供;不過如果client提供的時(shí)間點(diǎn)還未到來呢?根據(jù)系統(tǒng)實(shí)現(xiàn)可以選擇報(bào)錯(cuò)或者block,不過我想報(bào)錯(cuò)更合理吧,讀取未來數(shù)據(jù)的業(yè)務(wù)沒見過。
?
這部分transaction看起來復(fù)雜,因?yàn)橹饕羌?xì)節(jié)問題,宏觀問題都是清楚明白的。
?
不得不說,Google的創(chuàng)新力很可怕,Spanner恐怕兩年內(nèi)不會(huì)有開源的實(shí)現(xiàn),因?yàn)槠洳粌H依靠軟件、而且依靠硬件,更主要的是,開源界可能沒有那么緊迫的需求推動(dòng)。
逐步搬之前的文章過來:http://www.cnblogs.com/raymondshiquan/articles/2697956.html
[1]?Bigtable: A Distributed Storage System for Structured Data
[2]?jeff notes 2009
[3]?Spanner
總結(jié)
以上是生活随笔為你收集整理的spanner 的前世今生的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: hue-3.7.0安装+ hadoop2
- 下一篇: 【123】