全球分布式數(shù)據(jù)庫(kù):Google Spanner(論文翻譯)

本文由廈門大學(xué)計(jì)算機(jī)系教師林子雨翻譯,翻譯質(zhì)量很高,本人只對(duì)極少數(shù)翻譯得不太恰當(dāng)?shù)牡胤竭M(jìn)行了修改。

【摘要】:Spanner 是谷歌公司研發(fā)的、可擴(kuò)展的、多版本、全球分布式、同步復(fù)制數(shù)據(jù)庫(kù)。它是第一個(gè)把數(shù)據(jù)分布在全球范圍內(nèi)的系統(tǒng),并且支持外部一致性的分布式事務(wù)。本文描述了 Spanner 的架構(gòu)、特性、不同設(shè)計(jì)決策的背后機(jī)理和一個(gè)新的時(shí)間 API,這個(gè) API 可以暴露時(shí)鐘的不確定性。這個(gè) API 及其實(shí)現(xiàn),對(duì)于支持外部一致性和許多強(qiáng)大特性而言,是非常重要的,這些強(qiáng)大特性包括:非阻塞的讀、不采用鎖機(jī)制的只讀事務(wù)、原子模式變更。

【關(guān)鍵詞】Google Spanner, Bigtable, distributed database

1 介紹

Spanner 是一個(gè)可擴(kuò)展的、全球分布式的數(shù)據(jù)庫(kù),是在谷歌公司設(shè)計(jì)、開發(fā)和部署的。

在最高抽象層面,Spanner 就是一個(gè)數(shù)據(jù)庫(kù),把數(shù)據(jù)分片存儲(chǔ)在許多 Paxos[21]狀態(tài)機(jī)上,這些機(jī)器位于遍布全球的數(shù)據(jù)中心內(nèi)。復(fù)制技術(shù)可以用來(lái)服務(wù)于全球可用性和地理局部性。客戶端會(huì)自動(dòng)在副本之間進(jìn)行失敗恢復(fù)。隨著數(shù)據(jù)的變化和服務(wù)器的變化,Spanner 會(huì)自動(dòng)把數(shù)據(jù)進(jìn)行重新分片,從而有效應(yīng)對(duì)負(fù)載變化和處理失敗。Spanner 被設(shè)計(jì)成可以擴(kuò)展到幾百萬(wàn)個(gè)機(jī)器節(jié)點(diǎn),跨越成百上千個(gè)數(shù)據(jù)中心,具備幾萬(wàn)億數(shù)據(jù)庫(kù)行的規(guī)模。

應(yīng)用可以借助于 Spanner 來(lái)實(shí)現(xiàn)高可用性,通過在一個(gè)洲的內(nèi)部和跨越不同的洲之間復(fù)制數(shù)據(jù),保證即使面對(duì)大范圍的自然災(zāi)害時(shí)數(shù)據(jù)依然可用。我們最初的客戶是 F1[35],一個(gè)谷歌廣告后臺(tái)的重新編程實(shí)現(xiàn)。F1 使用了跨越美國(guó)的 5 個(gè)副本。絕大多數(shù)其他應(yīng)用很可能會(huì)在屬于同一個(gè)地理范圍內(nèi)的 3-5 個(gè)數(shù)據(jù)中心內(nèi)放置數(shù)據(jù)副本,采用相對(duì)獨(dú)立的失敗模式。也就是說(shuō),許多應(yīng)用都會(huì)首先選擇低延遲,而不是高可用性,只要系統(tǒng)能夠從 1-2 個(gè)數(shù)據(jù)中心失敗中恢復(fù)過來(lái)。

Spanner 的主要工作,就是管理跨越多個(gè)數(shù)據(jù)中心的數(shù)據(jù)副本,但是,在我們的分布式系統(tǒng)體系架構(gòu)之上設(shè)計(jì)和實(shí)現(xiàn)重要的數(shù)據(jù)庫(kù)特性方面,我們也花費(fèi)了大量的時(shí)間。盡管有許多項(xiàng)目可以很好地使用 BigTable[9],我們也不斷收到來(lái)自客戶的抱怨,客戶反映 BigTable 無(wú)法應(yīng)用到一些特定類型的應(yīng)用上面,比如具備復(fù)雜可變的模式,或者對(duì)于在大范圍內(nèi)分布的多個(gè)副本數(shù)據(jù)具有較高的一致性要求。其他研究人員也提出了類似的抱怨[37]。谷歌的許多應(yīng)用已經(jīng)選擇使用 Megastore[5],主要是因?yàn)樗陌腙P(guān)系數(shù)據(jù)模型和對(duì)同步復(fù)制的支持,盡管 Megastore 具備較差的寫操作吞吐量。由于上述多個(gè)方面的因素,Spanner 已經(jīng)從一個(gè)類似 BigTable 的單一版本的鍵值存儲(chǔ),演化成為一個(gè)具有時(shí)間屬性的多版本的數(shù)據(jù)庫(kù)。數(shù)據(jù)被存儲(chǔ)到模式化的、半關(guān)系的表中,數(shù)據(jù)被版本化,每個(gè)版本都會(huì)自動(dòng)以提交時(shí)間作為時(shí)間戳,舊版本的數(shù)據(jù)會(huì)更容易被垃圾回收。應(yīng)用可以讀取舊版本的數(shù)據(jù)。Spanner 支持通用的事務(wù),提供了基于 SQL 的查詢語(yǔ)言。

作為一個(gè)全球分布式數(shù)據(jù)庫(kù),Spanner 提供了幾個(gè)有趣的特性:第一,在數(shù)據(jù)的副本配置方面,應(yīng)用可以在一個(gè)很細(xì)的粒度上進(jìn)行動(dòng)態(tài)控制。應(yīng)用可以詳細(xì)規(guī)定,哪些數(shù)據(jù)中心包含哪些數(shù)據(jù),數(shù)據(jù)距離用戶有多遠(yuǎn)(控制用戶讀取數(shù)據(jù)的延遲),不同數(shù)據(jù)副本之間距離有多遠(yuǎn)(控制寫操作的延遲),以及需要維護(hù)多少個(gè)副本(控制可用性和讀操作性能)。數(shù)據(jù)也可以被動(dòng)態(tài)和透明地在數(shù)據(jù)中心之間進(jìn)行移動(dòng),從而平衡不同數(shù)據(jù)中心內(nèi)資源的使用。第二, Spanner 有兩個(gè)重要的特性,很難在一個(gè)分布式數(shù)據(jù)庫(kù)上實(shí)現(xiàn),即 Spanner 提供了讀和寫操作的外部一致性,以及在一個(gè)時(shí)間戳下面的跨越數(shù)據(jù)庫(kù)的全球一致性的讀操作。這些特性使得 Spanner 可以支持一致的備份、一致的 MapReduce 執(zhí)行[12]和原子模式變更,所有都是在全球范圍內(nèi)實(shí)現(xiàn),即使存在正在處理中的事務(wù)也可以。

之所以可以支持這些特性,是因?yàn)?Spanner 可以為事務(wù)分配全球范圍內(nèi)有意義的提交時(shí)間戳,即使事務(wù)可能是分布式的。這些時(shí)間戳反映了事務(wù)序列化的順序。除此以外,這些序列化的順序滿足了外部一致性的要求:如果一個(gè)事務(wù) T1 在另一個(gè)事務(wù) T2 開始之前就已經(jīng)提交了,那么,T1 的時(shí)間戳就要比 T2 的時(shí)間戳小。Spanner 是第一個(gè)可以在全球范圍內(nèi)提供這種保證的系統(tǒng)。

實(shí)現(xiàn)這種特性的關(guān)鍵技術(shù)就是一個(gè)新的 TrueTime API 及其實(shí)現(xiàn)。這個(gè) API 可以直接暴露時(shí)鐘不確定性,Spanner 時(shí)間戳的保證就是取決于這個(gè) API 實(shí)現(xiàn)的界限。如果這個(gè)不確定性很大,Spanner 就降低速度來(lái)等待這個(gè)大的不確定性結(jié)束。谷歌的簇管理器軟件提供了一個(gè) TrueTime API 的實(shí)現(xiàn)。這種實(shí)現(xiàn)可以保持較小的不確定性(通常小于 10ms),主要是借助于現(xiàn)代時(shí)鐘參考值(比如 GPS 和原子鐘)。

第 2 部分描述了 Spanner 實(shí)現(xiàn)的結(jié)構(gòu)、特性集和工程方面的決策;第 3 部分介紹我們的新的 TrueTime API,并且描述了它的實(shí)現(xiàn);第 4 部分描述了 Spanner 如何使用 TrueTime 來(lái)實(shí)現(xiàn)外部一致性的分布式事務(wù)、不用鎖機(jī)制的只讀事務(wù)和原子模式更新。第 5 部分提供了測(cè)試 Spanner 性能和 TrueTime 行為的測(cè)試基準(zhǔn),并討論了 F1 的經(jīng)驗(yàn)。第 6、7 和 8 部分討論了相關(guān)工作,并給出總結(jié)。

2 實(shí)現(xiàn)

本部分內(nèi)容描述了 Spanner 的結(jié)構(gòu)和背后的實(shí)現(xiàn)機(jī)理,然后描述了目錄抽象,它被用來(lái)管理副本和局部性,并介紹了數(shù)據(jù)的轉(zhuǎn)移單位。最后,將討論我們的數(shù)據(jù)模型,從而說(shuō)明為什么 Spanner 看起來(lái)更加像一個(gè)關(guān)系數(shù)據(jù)庫(kù),而不是一個(gè)鍵值數(shù)據(jù)庫(kù);還會(huì)討論應(yīng)用如何可以控制數(shù)據(jù)的局部性。

一個(gè) Spanner 部署稱為一個(gè) universe。假設(shè) Spanner 在全球范圍內(nèi)管理數(shù)據(jù),那么,將會(huì)只有可數(shù)的、運(yùn)行中的 universe。我們當(dāng)前正在運(yùn)行一個(gè)測(cè)試用的 universe,一個(gè)部署/線上用的 universe 和一個(gè)只用于線上應(yīng)用的 universe。

Spanner 被組織成許多個(gè) zone 的集合,每個(gè) zone 都大概像一個(gè) BigTable 服務(wù)器的部署。 zone 是管理部署的基本單元。zone 的集合也是數(shù)據(jù)可以被復(fù)制到的位置的集合。當(dāng)新的數(shù)據(jù)中心加入服務(wù),或者老的數(shù)據(jù)中心被關(guān)閉時(shí),zone 可以被加入到一個(gè)運(yùn)行的系統(tǒng)中,或者從中移除。zone 也是物理隔離的單元,在一個(gè)數(shù)據(jù)中心中,可能有一個(gè)或者多個(gè) zone, 例如,當(dāng)屬于不同應(yīng)用的數(shù)據(jù)必須被分區(qū)存儲(chǔ)到同一個(gè)數(shù)據(jù)中心的不同服務(wù)器集合中時(shí),一個(gè)數(shù)據(jù)中心就會(huì)有多個(gè) zone 。

圖1

圖 1 顯示了在一個(gè) Spanner 的 universe 中的服務(wù)器。一個(gè) zone 包括一個(gè) zonemaster, 和一百至幾千個(gè) spanserver。Zonemaster 把數(shù)據(jù)分配給 spanserver,spanserver 把數(shù)據(jù)提供給客戶端。客戶端使用每個(gè) zone 上面的 location proxy 來(lái)定位可以為自己提供數(shù)據(jù)的 spanserver。Universe master 和 placement driver,當(dāng)前都只有一個(gè)。Universe master 主要是一個(gè)控制臺(tái),它顯示了關(guān)于 zone 的各種狀態(tài)信息,可以用于相互之間的調(diào)試。Placement driver 會(huì)周期性地與 spanserver 進(jìn)行交互,來(lái)發(fā)現(xiàn)那些需要被轉(zhuǎn)移的數(shù)據(jù),或者是為了滿足新的副本約束條件,或者是為了進(jìn)行負(fù)載均衡。

2.1 Spanserver 軟件棧

本部分內(nèi)容主要關(guān)注 spanserver 實(shí)現(xiàn),來(lái)解釋復(fù)制和分布式事務(wù)是如何被架構(gòu)到我們的基于 BigTable 的實(shí)現(xiàn)之上的。圖 2 顯示了軟件棧。在底部,每個(gè) spanserver 負(fù)載管理 100-1000 個(gè)稱為 tablet 的數(shù)據(jù)結(jié)構(gòu)的實(shí)例。一個(gè) tablet 就類似于 BigTable 中的 tablet,也實(shí)現(xiàn)了下面的映射: (key:string, timestamp:int64)->string

圖2

與 BigTable 不同的是,Spanner 會(huì)把時(shí)間戳分配給數(shù)據(jù),這種非常重要的方式,使得 Spanner 更像一個(gè)多版本數(shù)據(jù)庫(kù),而不是一個(gè)鍵值存儲(chǔ)。一個(gè) tablet 的狀態(tài)是存儲(chǔ)在類似于 B-樹的文件集合和寫前(write-ahead)的日志中,所有這些都會(huì)被保存到一個(gè)分布式的文件系統(tǒng)中,這個(gè)分布式文件系統(tǒng)被稱為 Colossus,它繼承自 Google File System。

為了支持復(fù)制,每個(gè) spanserver 會(huì)在每個(gè) tablet 上面實(shí)現(xiàn)一個(gè)單個(gè)的 Paxos 狀態(tài)機(jī)。一個(gè)之前實(shí)現(xiàn)的Spanner 可以支持在每個(gè) tablet 上面實(shí)現(xiàn)多個(gè) Paxos 狀態(tài)機(jī)器,它可以允許更加靈活的復(fù)制配置,但是,這種設(shè)計(jì)過于復(fù)雜,被我們舍棄了。每個(gè)狀態(tài)機(jī)器都會(huì)在相應(yīng)的 tablet 中保存自己的元數(shù)據(jù)和日志。我們的 Paxos 實(shí)現(xiàn)支持長(zhǎng)壽命的領(lǐng)導(dǎo)者(采用基于時(shí)間的領(lǐng)導(dǎo)者租約),時(shí)間通常在 0 到 10 秒之間。當(dāng)前的 Spanner 實(shí)現(xiàn)中,會(huì)對(duì)每個(gè) Paxos 寫操作進(jìn)行兩次記錄:一次是寫入到 tablet 日志中,一次是寫入到 Paxos 日志中。這種做法只是權(quán)宜之計(jì),我們以后會(huì)進(jìn)行完善。我們?cè)?Paxos 實(shí)現(xiàn)上采用了管道化的方式,從而可以在存在廣域網(wǎng)延遲時(shí)改進(jìn) Spanner 的吞吐量,但是,Paxos 會(huì)把寫操作按照順序的方式執(zhí)行。

Paxos 狀態(tài)機(jī)是用來(lái)實(shí)現(xiàn)一系列被一致性復(fù)制的映射。每個(gè)副本的鍵值映射狀態(tài),都會(huì)被保存到相應(yīng)的 tablet 中。寫操作必須在領(lǐng)導(dǎo)者上初始化 Paxos 協(xié)議,讀操作可以直接從底層的任何副本的 tablet 中訪問狀態(tài)信息,只要這個(gè)副本足夠新。副本的集合被稱為一個(gè) Paxos group。

對(duì)于每個(gè)是領(lǐng)導(dǎo)者的副本而言,每個(gè) spanserver 會(huì)實(shí)現(xiàn)一個(gè)鎖表來(lái)實(shí)現(xiàn)并發(fā)控制。這個(gè)鎖表包含了兩階段鎖機(jī)制的狀態(tài):它把鍵的值域映射到鎖狀態(tài)上面。注意,采用一個(gè)長(zhǎng)壽命的 Paxos 領(lǐng)導(dǎo)者,對(duì)于有效管理鎖表而言是非常關(guān)鍵的。在 BigTable 和 Spanner 中,我們都專門為長(zhǎng)事務(wù)做了設(shè)計(jì),比如,對(duì)于報(bào)表操作,可能要持續(xù)幾分鐘,當(dāng)存在沖突時(shí),采用樂觀并發(fā)控制機(jī)制會(huì)表現(xiàn)出很差的性能。對(duì)于那些需要同步的操作,比如事務(wù)型的讀操作,需要獲得鎖表中的鎖,而其他類型的操作則可以不理會(huì)鎖表。

對(duì)于每個(gè)扮演領(lǐng)導(dǎo)者角色的副本,每個(gè) spanserver 也會(huì)實(shí)施一個(gè)事務(wù)管理器來(lái)支持分布式事務(wù)。這個(gè)事務(wù)管理器被用來(lái)實(shí)現(xiàn)一個(gè) participant leader,該組內(nèi)的其他副本則是作為 participant slaves。如果一個(gè)事務(wù)只包含一個(gè) Paxos 組(對(duì)于許多事務(wù)而言都是如此),它就可以繞過事務(wù)管理器,因?yàn)殒i表和 Paxos 二者一起可以保證事務(wù)性。如果一個(gè)事務(wù)包含了多 于一個(gè) Paxos 組,那些組的領(lǐng)導(dǎo)者之間會(huì)彼此協(xié)調(diào)合作完成兩階段提交。其中一個(gè)參與者組,會(huì)被選為協(xié)調(diào)者,該組的 participant leader 被稱為 coordinator leader,該組的 participant slaves 被稱為 coordinator slaves。每個(gè)事務(wù)管理器的狀態(tài),會(huì)被保存到底層的 Paxos 組。

2.2 目錄和放置

在一系列鍵值映射的上層,Spanner 實(shí)現(xiàn)支持一個(gè)被稱為“目錄”的桶抽象,也就是包含公共前綴的連續(xù)鍵的集合。(選擇“目錄”作為名稱,主要是由于歷史沿襲的考慮,實(shí)際 上更好的名稱應(yīng)該是“桶”)。我們會(huì)在第 2.3 節(jié)解釋前綴的源頭。對(duì)目錄的支持,可以讓應(yīng)用通過選擇合適的鍵來(lái)控制數(shù)據(jù)的局部性。

一個(gè)目錄是數(shù)據(jù)放置的基本單元。屬于一個(gè)目錄的所有數(shù)據(jù),都具有相同的副本配置。 當(dāng)數(shù)據(jù)在不同的 Paxos 組之間進(jìn)行移動(dòng)時(shí),會(huì)一個(gè)目錄一個(gè)目錄地轉(zhuǎn)移,如圖 3 所示。Spanner 可能會(huì)移動(dòng)一個(gè)目錄從而減輕一個(gè) Paxos 組的負(fù)擔(dān),也可能會(huì)把那些被頻繁地一起訪問的目錄都放置到同一個(gè)組中,或者會(huì)把一個(gè)目錄轉(zhuǎn)移到距離訪問者更近的地方。當(dāng)客戶端操作正在進(jìn)行時(shí),也可以進(jìn)行目錄的轉(zhuǎn)移。我們可以預(yù)期在幾秒內(nèi)轉(zhuǎn)移 50MB 的目錄。

圖3

一個(gè) Paxos 組可以包含多個(gè)目錄,這意味著一個(gè) Spanner tablet 是不同于一個(gè) BigTable tablet 的。一個(gè) Spanner tablet 沒有必要是一個(gè)行空間內(nèi)按照詞典順序連續(xù)的分區(qū),相反,它可以是行空間內(nèi)的多個(gè)分區(qū)。我們做出這個(gè)決定,是因?yàn)檫@樣做可以讓多個(gè)被頻繁一起訪問的目錄被整合到一起。

Movedir 是一個(gè)后臺(tái)任務(wù),用來(lái)在不同的 Paxos 組之間轉(zhuǎn)移目錄[14]。Movedir 也用來(lái)為 Paxos 組增加和刪除副本[25],因?yàn)?Spanner 目前還不支持在一個(gè) Paxos 內(nèi)部進(jìn)行配置的變更。 Movedir 并不是作為一個(gè)事務(wù)來(lái)實(shí)現(xiàn),這樣可以避免在一個(gè)塊數(shù)據(jù)轉(zhuǎn)移過程中阻塞正在進(jìn)行的讀操作和寫操作。相反,Movedir 會(huì)注冊(cè)一個(gè)事實(shí)(fact),表明它要轉(zhuǎn)移數(shù)據(jù),然后在后臺(tái)運(yùn)行轉(zhuǎn)移數(shù)據(jù)。當(dāng)它幾乎快要轉(zhuǎn)移完指定數(shù)量的數(shù)據(jù)時(shí),就會(huì)啟動(dòng)一個(gè)事務(wù)來(lái)自動(dòng)轉(zhuǎn)移那部分?jǐn)?shù)據(jù),并且為兩個(gè) Paxos 組更新元數(shù)據(jù)。

一個(gè)目錄也是一個(gè)應(yīng)用可以指定的地理復(fù)制屬性(即放置策略)的最小單元。我們的放置規(guī)范語(yǔ)言的設(shè)計(jì),把管理復(fù)制的配置這個(gè)任務(wù)單獨(dú)分離出來(lái)。管理員需要控制兩個(gè)維度: 副本的數(shù)量和類型,以及這些副本的地理放置屬性。他們?cè)谶@兩個(gè)維度里面創(chuàng)建了一個(gè)命名 選項(xiàng)的菜單。通過為每個(gè)數(shù)據(jù)庫(kù)或單獨(dú)的目錄增加這些命名選項(xiàng)的組合,一個(gè)應(yīng)用就可以控制數(shù)據(jù)的復(fù)制。例如,一個(gè)應(yīng)用可能會(huì)在自己的目錄里存儲(chǔ)每個(gè)終端用戶的數(shù)據(jù),這就有可能使得用戶 A 的數(shù)據(jù)在歐洲有三個(gè)副本,用戶 B 的數(shù)據(jù)在北美有 5 個(gè)副本。

為了表達(dá)的清晰性,我們已經(jīng)做了盡量簡(jiǎn)化。事實(shí)上,當(dāng)一個(gè)目錄變得太大時(shí),Spanner 會(huì)把它分片存儲(chǔ)。每個(gè)分片可能會(huì)被保存到不同的 Paxos 組上(因此就意味著來(lái)自不同的服 務(wù)器)。Movedir 在不同組之間轉(zhuǎn)移的是分片,而不是轉(zhuǎn)移整個(gè)目錄。

2.3 數(shù)據(jù)模型

Spanner 會(huì)把下面的數(shù)據(jù)特性集合暴露給應(yīng)用:基于模式化的半關(guān)系表的數(shù)據(jù)模型,查詢語(yǔ)言和通用事務(wù)。支持這些特性的動(dòng)機(jī),是受到許多因素驅(qū)動(dòng)的。需要支持模式化的半關(guān)系表是由 Megastore[5]的普及來(lái)支持的。在谷歌內(nèi)部至少有 300 個(gè)應(yīng)用使用 Megastore(盡 管它具有相對(duì)低的性能),因?yàn)樗臄?shù)據(jù)模型要比 BigTable 簡(jiǎn)單,更易于管理,并且支持在跨數(shù)據(jù)中心層面進(jìn)行同步復(fù)制。BigTable 只可以支持跨數(shù)據(jù)中心的最終事務(wù)一致性。使用 Megastore 的著名的谷歌應(yīng)用是 Gmail,Picasa,Calendar,Android Market, AppEngine。在 Spanner 中需要支持 SQL 類型的查詢語(yǔ)言,也很顯然是非常必要的,因?yàn)?Dremel[28]作為交互式分析工具已經(jīng)非常普及。最后,在 BigTable 中跨行事務(wù)的缺乏來(lái)導(dǎo)致了用戶頻繁的抱怨; Percolator[32]的開發(fā)就是用來(lái)部分解決這個(gè)問題的。一些作者都在抱怨,通用的兩階段提交的代價(jià)過于昂貴,因?yàn)樗鼤?huì)帶來(lái)可用性問題和性能問題[9][10][19]。我們認(rèn)為,最好讓應(yīng)用 程序開發(fā)人員來(lái)處理由于過度使用事務(wù)引起的性能問題,而不是總是圍繞著“缺少事務(wù)”進(jìn) 行編程。在 Paxos 上運(yùn)行兩階段提交弱化了可用性問題。

應(yīng)用的數(shù)據(jù)模型是架構(gòu)在被目錄桶裝的鍵值映射層之上。一個(gè)應(yīng)用會(huì)在一個(gè) universe 中創(chuàng)建一個(gè)或者多個(gè)數(shù)據(jù)庫(kù)。每個(gè)數(shù)據(jù)庫(kù)可以包含無(wú)限數(shù)量的模式化的表。每個(gè)表都和關(guān)系數(shù)據(jù)庫(kù)表類似,具備行、列和版本值。我們不會(huì)詳細(xì)介紹 Spanner 的查詢語(yǔ)言,它看起來(lái)很像 SQL,只是做了一些擴(kuò)展。

Spanner 的數(shù)據(jù)模型不是純粹關(guān)系型的,它的行必須有名稱。更準(zhǔn)確地說(shuō),每個(gè)表都需 要有包含一個(gè)或多個(gè)主鍵列的排序集合。這種需求,讓 Spanner 看起來(lái)仍然有點(diǎn)像鍵值存儲(chǔ): 主鍵形成了一個(gè)行的名稱,每個(gè)表都定義了從主鍵列到非主鍵列的映射。當(dāng)一個(gè)行存在時(shí),必須要求已經(jīng)給行的一些鍵定義了一些值(即使是 NULL)。采用這種結(jié)構(gòu)是很有用的,因?yàn)檫@可以讓應(yīng)用通過選擇鍵來(lái)控制數(shù)據(jù)的局部性。

圖4

圖 4 包含了一個(gè) Spanner 模式的實(shí)例,它是以每個(gè)用戶和每個(gè)相冊(cè)為基礎(chǔ)存儲(chǔ)圖片元數(shù)據(jù)。這個(gè)模式語(yǔ)言和 Megastore 的類似,同時(shí)增加了額外的要求,即每個(gè) Spanner 數(shù)據(jù)庫(kù)必 須被客戶端分割成一個(gè)或多個(gè)表的層次結(jié)構(gòu)(hierarchy)。客戶端應(yīng)用會(huì)使用 INTERLEAVE IN 語(yǔ)句在數(shù)據(jù)庫(kù)模式中聲明這個(gè)層次結(jié)構(gòu)。這個(gè)層次結(jié)構(gòu)上面的表,是一個(gè)目錄表。目錄表中的每行都具有鍵 K,和子孫表中的所有以 K 開始(以字典順序排序)的行一起,構(gòu)成了一個(gè)目錄。ON DELETE CASCADE 意味著,如果刪除目錄中的一個(gè)行,也會(huì)級(jí)聯(lián)刪除所有相關(guān)的子孫行。這個(gè)圖也解釋了這個(gè)實(shí)例數(shù)據(jù)庫(kù)的交織層次(interleaved layout),例如 Albums(2,1) 代表了來(lái)自 Albums 表的、對(duì)應(yīng)于 user_id=2 和 album_id=1 的行。這種表的交織層次形成目錄,是非常重要的,因?yàn)樗试S客戶端來(lái)描述存在于多個(gè)表之間的位置關(guān)系,這對(duì)于一個(gè)分片的分布式數(shù)據(jù)庫(kù)的性能而言是很重要的。沒有它的話,Spanner 就無(wú)法知道最重要的位置關(guān)系。

表1

本部分內(nèi)容描述 TrueTime API,并大概給出它的實(shí)現(xiàn)方法。我們把大量細(xì)節(jié)內(nèi)容放在另一篇論文中,我們的目標(biāo)是展示這種 API 的力量。表 1 列出了 API 的方法。TrueTime 會(huì)顯式地把時(shí)間表達(dá)成 TTinterval,這是一個(gè)時(shí)間區(qū)間,具有有界限的時(shí)間不確定性(不像其他 的標(biāo)準(zhǔn)時(shí)間接口,沒有為客戶端提供―不確定性‖這種概念)。TTinterval 區(qū)間的端點(diǎn)是 TTstamp 類型。TT.now()方法會(huì)返回一個(gè) TTinterval,它可以保證包含 TT.now()方法在調(diào)用時(shí)的絕對(duì) 時(shí)間。這個(gè)時(shí)間和具備閏秒涂抹(leap-second smearing)的 UNIX 時(shí)間一樣。把即時(shí)誤差邊 界定義為 ε,平均誤差邊界為ε。TT.after()和 TT.before()方法是針對(duì) TT.now()的便捷的包裝器。

表示一個(gè)事件 e 的絕對(duì)時(shí)間,可以利用函數(shù) tabs(e)。如果用更加形式化的術(shù)語(yǔ),TrueTime 可以保證,對(duì)于一個(gè)調(diào)用 tt=TT.now(),有 tt.earliest≤tabs(enow)≤tt.latest,其中, enow 是調(diào)用的事件。

在底層,TrueTime 使用的時(shí)間是 GPS 和原子鐘。TrueTime 使用兩種類型的時(shí)間,是因?yàn)樗鼈冇胁煌氖∧J健PS 參考時(shí)間的弱點(diǎn)是天線和接收器失效、局部電磁干擾和相關(guān)失敗(比如設(shè)計(jì)上的缺陷導(dǎo)致無(wú)法正確處理閏秒和電子欺騙),以及 GPS 系統(tǒng)運(yùn)行中斷。原子鐘也會(huì)失效,不過失效的方式和 GPS 無(wú)關(guān),不同原子鐘之間的失效也沒有彼此關(guān)聯(lián)。 由于存在頻率誤差,在經(jīng)過很長(zhǎng)的時(shí)間以后,原子鐘都會(huì)產(chǎn)生明顯誤差。

TrueTime 是由每個(gè)數(shù)據(jù)中心上面的許多 time master 機(jī)器和每臺(tái)機(jī)器上的一個(gè) timeslave daemon 來(lái)共同實(shí)現(xiàn)的。大多數(shù) master 都有具備專用天線的 GPS 接收器,這些 master 在物理上是相互隔離的,這樣可以減少天線失效、電磁干擾和電子欺騙的影響。剩余的 master (我們稱為 Armageddon master)則配備了原子鐘。一個(gè)原子鐘并不是很昂貴:一個(gè) Armageddon master 的花費(fèi)和一個(gè) GPS master 的花費(fèi)是同一個(gè)數(shù)量級(jí)的。所有 master 的時(shí)間 參考值都會(huì)進(jìn)行彼此校對(duì)。每個(gè) master 也會(huì)交叉檢查時(shí)間參考值和本地時(shí)間的比值,如果二者差別太大,就會(huì)把自己驅(qū)逐出去。在同步期間,Armageddon master 會(huì)表現(xiàn)出一個(gè)逐漸增加的時(shí)間不確定性,這是由保守應(yīng)用的最差時(shí)鐘漂移引起的。GPS master 表現(xiàn)出的時(shí)間不確定性幾乎接近于 0。

每個(gè) daemon 會(huì)從許多 master[29]中收集投票,獲得時(shí)間參考值,從而減少誤差。被選中的 master 中,有些 master 是 GPS master,是從附近的數(shù)據(jù)中心獲得的,剩余的 GPS master 是從遠(yuǎn)處的數(shù)據(jù)中心獲得的;還有一些是 Armageddon master。Daemon 會(huì)使用一個(gè) Marzullo 算法[27]的變種,來(lái)探測(cè)和拒絕欺騙,并且把本地時(shí)鐘同步到非撒謊 master 的時(shí)間參考值。 為了免受較差的本地時(shí)鐘的影響,我們會(huì)根據(jù)組件規(guī)范和運(yùn)行環(huán)境確定一個(gè)界限,如果機(jī)器的本地時(shí)鐘誤差頻繁超出這個(gè)界限,這個(gè)機(jī)器就會(huì)被驅(qū)逐出去。

在同步期間,一個(gè) daemon 會(huì)表現(xiàn)出逐漸增加的時(shí)間不確定性。ε 是從保守應(yīng)用的最差 時(shí)鐘漂移中得到的。ε 也取決于 time master 的不確定性,以及與 time master 之間的通訊延遲。在我們的線上應(yīng)用環(huán)境中,ε 通常是一個(gè)關(guān)于時(shí)間的鋸齒形函數(shù)。在每個(gè)投票間隔中, ε 會(huì)在 1 到 7ms 之間變化。因此,在大多數(shù)情況下,ε的值是 4ms。Daemon 的投票間隔,在當(dāng)前是 30 秒,當(dāng)前使用的時(shí)鐘漂移比率是 200 微秒/秒,二者一起意味著 0 到 6ms 的鋸齒形邊界。剩余的 1ms 主要來(lái)自到 time master 的通訊延遲。在失敗的時(shí)候,超過這個(gè)鋸齒形邊界也是有可能的。例如,偶爾的 time master 不確定性,可能會(huì)引起整個(gè)數(shù)據(jù)中心范圍內(nèi)的 ε 值的增加。類似的,過載的機(jī)器或者網(wǎng)絡(luò)連接,都會(huì)導(dǎo)致 ε 值偶爾地局部增大。

4 并發(fā)控制

本部分內(nèi)容描述 TrueTime 如何可以用來(lái)保證并發(fā)控制的正確性,以及這些屬性如何用來(lái)實(shí)現(xiàn)一些關(guān)鍵特性,比如外部一致性的事務(wù)、無(wú)鎖機(jī)制的只讀事務(wù)、針對(duì)歷史數(shù)據(jù)的非阻塞讀。這些特性可以保證,在時(shí)間戳為 t 的時(shí)刻的數(shù)據(jù)庫(kù)讀操作,一定只能看到在 t 時(shí)刻之 前已經(jīng)提交的事務(wù)。

進(jìn)一步說(shuō),把 Spanner 客戶端的寫操作和 Paxos 看到的寫操作這二者進(jìn)行區(qū)分,是非常重要的,我們把 Paxos 看到的寫操作稱為 Paxos 寫操作。例如,兩階段提交會(huì)為準(zhǔn)備提交階段生成一個(gè) Paxos 寫操作,這時(shí)不會(huì)有相應(yīng)的客戶端寫操作。

4.1 時(shí)間戳管理

表 2 列出了 Spanner 支持的操作的類型。Spanner 可以支持讀寫事務(wù)、只讀事務(wù)(預(yù)先聲明的快照隔離事務(wù))和快照讀。獨(dú)立寫操作,會(huì)被當(dāng)成讀寫事務(wù)來(lái)執(zhí)行。非快照獨(dú)立讀操作,會(huì)被當(dāng)成只讀事務(wù)來(lái)執(zhí)行。二者都是在內(nèi)部進(jìn)行 retry,客戶端不用進(jìn)行這種 retry loop。

表2

一個(gè)只讀事務(wù)具備快照隔離的性能優(yōu)勢(shì)[6]。一個(gè)只讀事務(wù)必須事先被聲明不會(huì)包含任何寫操作,它并不是一個(gè)簡(jiǎn)單的不包含寫操作的讀寫事務(wù)。在一個(gè)只讀事務(wù)中的讀操作,在執(zhí)行時(shí)會(huì)采用一個(gè)系統(tǒng)選擇的時(shí)間戳,不包含鎖機(jī)制,因此,后面到達(dá)的寫操作不會(huì)被阻塞。 在一個(gè)只讀事務(wù)中的讀操作,可以到任何足夠新的副本上去執(zhí)行(見第 4.1.3 節(jié))。

一個(gè)快照讀操作,是針對(duì)歷史數(shù)據(jù)的讀取,執(zhí)行過程中,不需要鎖機(jī)制。一個(gè)客戶端可以為快照讀確定一個(gè)時(shí)間戳,或者提供一個(gè)時(shí)間范圍讓 Spanner 來(lái)自動(dòng)選擇時(shí)間戳。不管是 哪種情況,快照讀操作都可以在任何具有足夠新的副本上執(zhí)行。

對(duì)于只讀事務(wù)和快照讀而言,一旦已經(jīng)選定一個(gè)時(shí)間戳,那么,提交就是不可避免的,除非在那個(gè)時(shí)間點(diǎn)的數(shù)據(jù)已經(jīng)被垃圾回收了。因此,客戶端不必在 retry loop 中緩存結(jié)果。 當(dāng)一個(gè)服務(wù)器失效的時(shí)候,客戶端就可以使用同樣的時(shí)間戳和當(dāng)前的讀位置,在另外一個(gè)服務(wù)器上繼續(xù)執(zhí)行讀操作。

4.1.1 Paxos 領(lǐng)導(dǎo)者租約

Spanner 的 Paxos 實(shí)現(xiàn)中使用了時(shí)間化的租約,來(lái)實(shí)現(xiàn)長(zhǎng)時(shí)間的領(lǐng)導(dǎo)者地位(默認(rèn)是 10秒)。一個(gè)潛在的領(lǐng)導(dǎo)者會(huì)發(fā)起請(qǐng)求,請(qǐng)求時(shí)間化的租約投票,在收到指定數(shù)量的投票后,這個(gè)領(lǐng)導(dǎo)者就可以確定自己擁有了一個(gè)租約。一個(gè)副本在成功完成一個(gè)寫操作后,會(huì)隱式地延期自己的租約。對(duì)于一個(gè)領(lǐng)導(dǎo)者而言,如果它的租約快要到期了,就要顯示地請(qǐng)求租約延期。另一個(gè)領(lǐng)導(dǎo)者的租約有個(gè)時(shí)間區(qū)間,這個(gè)時(shí)間區(qū)間的起點(diǎn)就是這個(gè)領(lǐng)導(dǎo)者獲得指定數(shù)量的投票那一刻,時(shí)間區(qū)間的終點(diǎn)就是這個(gè)領(lǐng)導(dǎo)者失去指定數(shù)量的投票的那一刻(因?yàn)橛行┩?票已經(jīng)過期了)。Spanner 依賴于下面這些“不連貫性”:對(duì)于每個(gè) Paxos 組,每個(gè) Paxos 領(lǐng) 導(dǎo)者的租約時(shí)間區(qū)間,是和其他領(lǐng)導(dǎo)者的時(shí)間區(qū)間完全隔離的。附錄 A 顯示了如何強(qiáng)制實(shí)現(xiàn)這些不連貫性。

Spanner 實(shí)現(xiàn)允許一個(gè) Paxos 領(lǐng)導(dǎo)者通過把 slave 從租約投票中釋放出來(lái)這種方式,實(shí)現(xiàn)領(lǐng)導(dǎo)者的退位。為了保持這種彼此隔離的不連貫性,Spanner 會(huì)對(duì)什么時(shí)候退位做出限制。把 smax 定義為一個(gè)領(lǐng)導(dǎo)者可以使用的最大的時(shí)間戳。在退位之前,一個(gè)領(lǐng)導(dǎo)者必須等到 TT.after(smax)是真。

4.1.2 為讀寫事務(wù)分配時(shí)間戳

事務(wù)讀和寫采用兩段鎖協(xié)議。當(dāng)所有的鎖都已經(jīng)獲得以后,在任何鎖被釋放之前,就可以給事務(wù)分配時(shí)間戳。對(duì)于一個(gè)給定的事務(wù),Spanner 會(huì)為事務(wù)分配時(shí)間戳,這個(gè)時(shí)間戳是 Paxos 分配給 Paxos 寫操作的,它代表了事務(wù)提交的時(shí)間。

Spanner 依賴下面這些單調(diào)性:在每個(gè) Paxos 組內(nèi),Spanner 會(huì)以單調(diào)增加的順序給每個(gè) Paxos 寫操作分配時(shí)間戳,即使在跨越多個(gè)領(lǐng)導(dǎo)者時(shí)也是如此。一個(gè)單個(gè)的領(lǐng)導(dǎo)者副本,可以很容易地以單調(diào)增加的方式分配時(shí)間戳。在多個(gè)領(lǐng)導(dǎo)者之間就會(huì)強(qiáng)制實(shí)現(xiàn)彼此隔離的不連 貫:一個(gè)領(lǐng)導(dǎo)者必須只能分配屬于它自己租約時(shí)間區(qū)間內(nèi)的時(shí)間戳。要注意到,一旦一個(gè)時(shí)間戳 s 被分配,smax 就會(huì)被增加到 s,從而保證彼此隔離性(不連貫性)。

Spanner 也會(huì)實(shí)現(xiàn)下面的外部一致性:如果一個(gè)事務(wù) T2 在事務(wù) T1 提交以后開始執(zhí)行, 那么,事務(wù) T2 的時(shí)間戳一定比事務(wù) T1 的時(shí)間戳大。對(duì)于一個(gè)事務(wù) Ti 而言,定義開始和提交事件eistart和eicommit,事務(wù)提交時(shí)間為si。對(duì)外部一致性的要求就變成了:
tabs(e1commit )<tabs(e2start ) s1<s2。執(zhí)行事務(wù)的協(xié)議和分配時(shí)間戳的協(xié)議,遵守兩條規(guī)則,二者一起保證外部一致性。對(duì)于一個(gè)寫操作 Ti 而言,擔(dān)任協(xié)調(diào)者的領(lǐng)導(dǎo)者發(fā)出的提交請(qǐng)求的事件為eiserver 。

Start. 為一個(gè)事務(wù) Ti 擔(dān)任協(xié)調(diào)者的領(lǐng)導(dǎo)者分配一個(gè)提交時(shí)間戳 si,不會(huì)小于 TT.now().latest 的值,TT.now().latest的值是在esierver事件之后計(jì)算得到的。要注意,擔(dān)任參與者的領(lǐng)導(dǎo)者, 在這里不起作用。第 4.2.1 節(jié)描述了這些擔(dān)任參與者的領(lǐng)導(dǎo)者是如何參與下一條規(guī)則的實(shí)現(xiàn)的。

Commit Wait. 擔(dān)任協(xié)調(diào)者的領(lǐng)導(dǎo)者,必須確保客戶端不能看到任何被 Ti 提交的數(shù)據(jù),直到 TT.after(si)為真。提交等待,就是要確保 si 會(huì)比 Ti 的絕對(duì)提交時(shí)間小。提交等待的實(shí)現(xiàn)在 4.2.1 節(jié)中描述。證明如下:

證明

4.1.3 在某個(gè)時(shí)間戳下的讀操作

第 4.1.2 節(jié)中描述的單調(diào)性,使得 Spanner 可以正確地確定一個(gè)副本是否足夠新,從而能夠滿足一個(gè)讀操作的要求。每個(gè)副本都會(huì)跟蹤記錄一個(gè)值,這個(gè)值被稱為安全時(shí)間 tsafe,它是一個(gè)副本最近更新后的最大時(shí)間戳。如果一個(gè)讀操作的時(shí)間戳是 t,當(dāng)滿足 t<=tsafe 時(shí), 這個(gè)副本就可以被這個(gè)讀操作讀取。

。。。

4.1.4 為只讀事務(wù)分配時(shí)間戳

一個(gè)只讀事務(wù)分成兩個(gè)階段執(zhí)行:分配一個(gè)時(shí)間戳 sread[8],然后當(dāng)成 sread 時(shí)刻的快照讀來(lái)執(zhí)行事務(wù)讀操作。快照讀可以在任何足夠新的副本上面執(zhí)行。

在一個(gè)事務(wù)開始后的任意時(shí)刻,可以簡(jiǎn)單地分配 sread=TT.now().latest,通過第 4.1.2 節(jié)中描述過的類似的方式來(lái)維護(hù)外部一致性。但是,對(duì)于時(shí)間戳 sread 而言,如果 tsafe 沒有增加到足夠大,可能需要對(duì) sread 時(shí)刻的讀操作進(jìn)行阻塞。除此以外還要注意,選擇一個(gè) sread 的值可 能也會(huì)增加 smax 的值,從而保證不連貫性。為了減少阻塞的概率,Spanner 應(yīng)該分配可以保持外部一致性的最老的時(shí)間戳。第 4.2.2 節(jié)描述了如何選擇這種時(shí)間戳。

4.2 細(xì)節(jié)

這部分內(nèi)容介紹一些讀寫操作和只讀操作的實(shí)踐細(xì)節(jié),以及用來(lái)實(shí)現(xiàn)原子模式變更的特定事務(wù)的實(shí)現(xiàn)方法。然后,描述一些基本模式的細(xì)化。

4.2.1 讀寫事務(wù)

就像 Bigtable 一樣,發(fā)生在一個(gè)事務(wù)中的寫操作會(huì)在客戶端進(jìn)行緩存,直到提交。由此導(dǎo)致的結(jié)果是,在一個(gè)事務(wù)中的讀操作,不會(huì)看到這個(gè)事務(wù)的寫操作的結(jié)果。這種設(shè)計(jì)在 Spanner 中可以很好地工作,因?yàn)橐粋€(gè)讀操作可以返回任何數(shù)據(jù)讀的時(shí)間戳,未提交的寫操作還沒有被分配時(shí)間戳。

在讀寫事務(wù)內(nèi)部的讀操作,使用傷停等待(wound-wait)[33]來(lái)避免死鎖。客戶端對(duì)位于合適組內(nèi)的領(lǐng)導(dǎo)者副本發(fā)起讀操作,需要首先獲得讀鎖,然后讀取最新的數(shù)據(jù)。當(dāng)一個(gè)客戶端事務(wù)保持活躍的時(shí)候,它會(huì)發(fā)送“保持活躍”信息,防止那些參與的領(lǐng)導(dǎo)者讓該事務(wù)過時(shí)。當(dāng)一個(gè)客戶端已經(jīng)完成了所有的讀操作,并且緩沖了所有的寫操作,它就開始兩階段提交。客戶端選擇一個(gè)協(xié)調(diào)者組,并且發(fā)送一個(gè)提交信息給每個(gè)參與的、具有協(xié)調(diào)者標(biāo)識(shí)的領(lǐng)導(dǎo)者,并發(fā)送提交信息給任何緩沖的寫操作。讓客戶端發(fā)起兩階段提交操作,可以避免在大范圍連接內(nèi)發(fā)送兩次數(shù)據(jù)。

一個(gè)參與其中的、扮演非協(xié)調(diào)者角色的領(lǐng)導(dǎo)者,首先需要獲得寫鎖。然后,它會(huì)選擇一 個(gè)預(yù)備時(shí)間戳,這個(gè)時(shí)間戳應(yīng)該比之前分配給其他事務(wù)的任何時(shí)間戳都要大(這樣可以保持 單調(diào)性),并且通過 Paxos 把準(zhǔn)備提交記錄寫入日志。然后,每個(gè)參與者就把自己的準(zhǔn)備時(shí) 間戳通知給協(xié)調(diào)者。

扮演協(xié)調(diào)者的領(lǐng)導(dǎo)者,也會(huì)首先獲得寫鎖,但是,會(huì)跳過準(zhǔn)備階段。在從所有其他的、扮演參與者的領(lǐng)導(dǎo)者那里獲得信息后,它就會(huì)為整個(gè)事務(wù)選擇一個(gè)時(shí)間戳。這個(gè)提交時(shí)間戳 s 必須大于或等于所有的準(zhǔn)備時(shí)間戳(這是為了滿足第 4.1.3 節(jié)討論的限制條件),在協(xié)調(diào)者收到它的提交信息時(shí),s 應(yīng)該大于 TT.now().latest,并且 s 應(yīng)該大于這個(gè)領(lǐng)導(dǎo)者為之前的其他 所有事務(wù)分配的時(shí)間戳(再次指出,這樣做是為了滿足單調(diào)性)。這個(gè)扮演協(xié)調(diào)者的領(lǐng)導(dǎo)者,就會(huì)通過 Paxos 在日志中寫入一個(gè)提交記錄(或者當(dāng)?shù)却渌麉⑴c者發(fā)生超時(shí)就在日志中寫 入終止記錄)。

在允許任何協(xié)調(diào)者副本去提交記錄之前,扮演協(xié)調(diào)者的領(lǐng)導(dǎo)者會(huì)一直等待到 TT.after(s), 從而可以保證遵循第 4.1.2 節(jié)中描述的提交等待規(guī)則。因?yàn)椋缪輩f(xié)調(diào)者的領(lǐng)導(dǎo)者會(huì)根據(jù) TT.now().latest 來(lái)選擇 s,而且必須等待直到那個(gè)時(shí)間戳可以確保成為過去,預(yù)期的等待時(shí)間 至少是 2*ε。這種等待時(shí)間通常會(huì)和 Paxos 通信時(shí)間發(fā)生重疊。在提交等待之后,協(xié)調(diào)者就會(huì)發(fā)送一個(gè)提交時(shí)間戳給客戶端和所有其他參與的領(lǐng)導(dǎo)者。每個(gè)參與的領(lǐng)導(dǎo)者會(huì)通過 Paxos 把事務(wù)結(jié)果寫入日志。所有的參與者會(huì)在同一個(gè)時(shí)間戳進(jìn)行提交,然后釋放鎖。

4.2.2 只讀事務(wù)

分配一個(gè)時(shí)間戳需要一個(gè)協(xié)商階段,這個(gè)協(xié)商發(fā)生在所有參與到該讀操作中的 Paxos 組之間。由此導(dǎo)致的結(jié)果是,Spanner 需要為每個(gè)只讀事務(wù)提供一個(gè) scope 表達(dá)式,它可以指出整個(gè)事務(wù)需要讀取哪些鍵。對(duì)于單獨(dú)的查詢,Spanner 可以自動(dòng)計(jì)算出 scope。

如果 scope 的值是由單個(gè) Paxos 組來(lái)提供的,那么,客戶端就會(huì)給那個(gè)組的領(lǐng)導(dǎo)者發(fā)起一個(gè)只讀事務(wù)(當(dāng)前的 Spanner 實(shí)現(xiàn)中,只會(huì)為 Paxos leader 中的只讀事務(wù)選擇一個(gè)時(shí)間戳), 為那個(gè)領(lǐng)導(dǎo)者分配 sread 并且執(zhí)行讀操作。對(duì)于一個(gè)單個(gè)位置的讀操作,Spanner 通常會(huì)比 TT.now().latest 做得更好。我們把 LastTS()定義為在 Paxos 組中最后提交的寫操作的時(shí)間戳。如果沒有準(zhǔn)備提交的事務(wù),這個(gè)分配到的時(shí)間戳 sread=LastTS()就很容易滿足外部一致性要求: 這個(gè)事務(wù)將可以看見最后一個(gè)寫操作的結(jié)果,然后排隊(duì)排在它之后。

如果 scope 的值是由多個(gè) Paxos 組來(lái)提供的,就會(huì)有幾種選擇。最復(fù)雜的選擇就是,和所有組的領(lǐng)導(dǎo)者進(jìn)行一輪溝通,大家根據(jù) LastTS()進(jìn)行協(xié)商得到 sread。Spanner 當(dāng)前實(shí)現(xiàn)了一個(gè)更加簡(jiǎn)單的選擇。這個(gè)選擇可以避免一輪協(xié)商,讓讀操作在 sread=TT.now().latest 時(shí)刻去 執(zhí)行(這可能會(huì)等待安全時(shí)間的增加)。這個(gè)事務(wù)中的所有讀操作,可以被發(fā)送到任何足夠 新的副本上執(zhí)行。

4.2.3 模式變更事務(wù)

TrueTime 允許 Spanner 支持原子模式變更。使用一個(gè)標(biāo)準(zhǔn)的事務(wù)是不可行的,因?yàn)閰⑴c者的數(shù)量(即數(shù)據(jù)庫(kù)中組的數(shù)量)可能達(dá)到幾百萬(wàn)個(gè)。Bigtable 可以支持在一個(gè)數(shù)據(jù)中心內(nèi)進(jìn)行原子模式變更,但是,這個(gè)操作會(huì)阻塞所有其他操作。

一個(gè) Spanner 模式變更事務(wù)通常是一個(gè)標(biāo)準(zhǔn)事務(wù)的、非阻塞的變種。首先,它會(huì)顯式地分配一個(gè)未來(lái)的時(shí)間戳,這個(gè)時(shí)間戳?xí)跍?zhǔn)備階段進(jìn)行注冊(cè)。由此,跨越幾千個(gè)服務(wù)器的模式變更,可以在不打擾其他并發(fā)活動(dòng)的前提下完成。其次,讀操作和寫操作,它們都是隱式地依賴于模式,它們都會(huì)和任何注冊(cè)的模式變更時(shí)間戳t保持同步:當(dāng)它們的時(shí)間戳小于 t 時(shí), 讀寫操作就執(zhí)行到時(shí)刻 t;當(dāng)它們的時(shí)間戳大于時(shí)刻 t 時(shí),讀寫操作就必須阻塞,在模式變更事務(wù)后面進(jìn)行等待。如果沒有 TrueTime,那么定義模式變更發(fā)生在 t 時(shí)刻,就變得毫無(wú)意義。

5. 實(shí)驗(yàn)分析

我們對(duì) Spanner 性能進(jìn)行了測(cè)試,包括復(fù)制、事務(wù)和可用性。然后,我們提供了一些關(guān)于 TrueTime 的實(shí)驗(yàn)數(shù)據(jù),并且提供了我們的第一個(gè)用例——F1。

5.1 微測(cè)試基準(zhǔn)

表 3 給出了一用于 Spanner 的微測(cè)試基準(zhǔn)(microbenchmark)。這些測(cè)試是在分時(shí)機(jī)器上實(shí)現(xiàn)的:每個(gè) spanserver 采用 4GB 內(nèi)存和四核 CPU(AMD Barcelona 2200MHz)。客戶端運(yùn)行在單獨(dú)的機(jī)器上。每個(gè) zone 都包含一個(gè) spanserver。客戶端和 zone 都放在一個(gè)數(shù)據(jù)中心集合內(nèi),它們之間的網(wǎng)絡(luò)距離不會(huì)超過 1ms。這種布局是很普通的,許多數(shù)據(jù)并不需要把數(shù) 據(jù)分散存儲(chǔ)到全球各地)。測(cè)試數(shù)據(jù)庫(kù)具有 50 個(gè) Paxos 組和 2500 個(gè)目錄。操作都是獨(dú)立的 4KB 大小的讀和寫。All reads were served out of memory after a compaction,從而使得我們只需要衡量 Spanner 調(diào)用棧的開銷。此外,還會(huì)進(jìn)行一輪讀操作,來(lái)預(yù)熱任何位置的緩存。

表3

對(duì)于延遲實(shí)驗(yàn)而言,客戶端會(huì)發(fā)起足夠少量的操作,從而避免在服務(wù)器中發(fā)生排隊(duì)。從 1 個(gè)副本的實(shí)驗(yàn)中,提交等待大約是 5ms,Paxos 延遲大約是 9ms。隨著副本數(shù)量的增加, 延遲大約保持不變,只具有很少的標(biāo)準(zhǔn)差,因?yàn)樵谝粋€(gè)組的副本內(nèi),Paxos 會(huì)并行執(zhí)行。隨著副本數(shù)量的增加,獲得指定投票數(shù)量的延遲對(duì)一個(gè) slave 副本的慢速度不會(huì)很敏感。

對(duì)于吞吐量的實(shí)驗(yàn)而言,客戶端發(fā)起足夠數(shù)量的操作,從而使得 CPU 處理能力達(dá)到飽和。快照讀操作可以在任何足夠新的副本上進(jìn)行,因此,快照讀的吞吐量會(huì)隨著副本的數(shù)量增加而線性增加。單個(gè)讀的只讀事務(wù),只會(huì)在領(lǐng)導(dǎo)者上執(zhí)行,因?yàn)椋瑫r(shí)間戳分配必須發(fā)生在領(lǐng)導(dǎo)者上。只讀事務(wù)吞吐量會(huì)隨著副本數(shù)量的增加而增加,因?yàn)橛行У?spanserver 的數(shù)量會(huì)增加:在這個(gè)實(shí)驗(yàn)的設(shè)置中,spanserver 的數(shù)量和副本的數(shù)量相同,領(lǐng)導(dǎo)者會(huì)被隨機(jī)分配到不同的 zone。寫操作的吞吐量也會(huì)從這種實(shí)驗(yàn)設(shè)置中獲得收益(副本從 3 變到 5 時(shí)寫操作吞吐量增加了,就能夠說(shuō)明這點(diǎn)),但是,隨著副本數(shù)量的增加,每個(gè)寫操作執(zhí)行時(shí)需要完 成的工作量也會(huì)線性增加,這就會(huì)抵消前面的收益。

表 4 顯示了兩階段提交可以擴(kuò)展到合理數(shù)量的參與者:它是對(duì)一系列實(shí)驗(yàn)的總結(jié),這些實(shí)驗(yàn)運(yùn)行在 3 個(gè) zone 上,每個(gè) zone 具有 25 個(gè) spanserver。擴(kuò)展到 50 個(gè)參與者,無(wú)論在平均值還是第 99 個(gè)百分位方面,都是合理的。在 100 個(gè)參與者的情形下,延遲開發(fā)明顯增加。

表4

5.2 可用性

圖 5 顯示了在多個(gè)數(shù)據(jù)中心運(yùn)行 Spanner 時(shí)的可用性方面的收益。它顯示了三個(gè)吞吐量實(shí)驗(yàn)的結(jié)果,并且存在數(shù)據(jù)中心失敗的情形,所有三個(gè)實(shí)驗(yàn)結(jié)果都被重疊放置到一個(gè)時(shí)間軸 上。測(cè)試用的 universe 包含 5 個(gè) zone Zi,每個(gè) zone 都擁有 25 個(gè) spanserver。測(cè)試數(shù)據(jù)庫(kù)被 分片成 1250 個(gè) Paxos 組,100 個(gè)客戶端不斷地發(fā)送非快照讀操作,累積速率是每秒 50K 個(gè)讀操作。所有領(lǐng)導(dǎo)者都會(huì)被顯式地放置到 Z1。每個(gè)測(cè)試進(jìn)行 5 秒鐘以后,一個(gè) zone 中的所有服務(wù)器都會(huì)被“殺死”:non-leader 殺掉 Z2,leader-hard 殺掉 Z1,leader-soft 殺掉 Z1,但是,它會(huì)首先通知所有服務(wù)器它們將要交出領(lǐng)導(dǎo)權(quán)。

圖5

殺掉 Z2 對(duì)于讀操作吞吐量沒有影響。殺掉 Z1,給領(lǐng)導(dǎo)者一些時(shí)間來(lái)把領(lǐng)導(dǎo)權(quán)交給另一個(gè) zone 時(shí),會(huì)產(chǎn)生一個(gè)小的影響:吞吐量會(huì)下降,不是很明顯,大概下降 3-4%。另一方面,沒有預(yù)警就殺掉 Z1 有一個(gè)明顯的影響:完成率幾乎下降到 0。隨著領(lǐng)導(dǎo)者被重新選擇,系統(tǒng)的吞吐量會(huì)增加到大約每秒 100K 個(gè)讀操作,主要是由于我們的實(shí)驗(yàn)設(shè)置:系統(tǒng)中有額外的能力,當(dāng)找不到領(lǐng)導(dǎo)者時(shí)操作會(huì)排隊(duì)。由此導(dǎo)致的結(jié)果是,系統(tǒng)的吞吐量會(huì)增加直到到達(dá) 系統(tǒng)恒定的速率。

我們可以看看把 Paxos 領(lǐng)導(dǎo)者租約設(shè)置為 10ms 的效果。當(dāng)我們殺掉這個(gè) zone,對(duì)于這 個(gè)組的領(lǐng)導(dǎo)者租約的過期時(shí)間,會(huì)均勻地分布到接下來(lái)的 10 秒鐘內(nèi)。來(lái)自一個(gè)死亡的領(lǐng)導(dǎo)者的每個(gè)租約一旦過期,就會(huì)選擇一個(gè)新的領(lǐng)導(dǎo)者。大約在殺死時(shí)間過去 10 秒鐘以后,所有的組都會(huì)有領(lǐng)導(dǎo)者,吞吐量就恢復(fù)了。短的租約時(shí)間會(huì)降低服務(wù)器死亡對(duì)于可用性的影響, 但是,需要更多的更新租約的網(wǎng)絡(luò)通訊開銷。我們正在設(shè)計(jì)和實(shí)現(xiàn)一種機(jī)制,它可以在領(lǐng)導(dǎo)者失效的時(shí)候,讓 slave 釋放 Paxos 領(lǐng)導(dǎo)者租約。

5.3 TrueTime

關(guān)于 TrueTime,必須回答兩個(gè)問題: ε 是否就是時(shí)鐘不確定性的邊界? ε 會(huì)變得多糟糕? 對(duì)于第一個(gè)問題,最嚴(yán)峻的問題就是,如果一個(gè)局部的時(shí)鐘漂移大于 200us/sec,那就會(huì)破壞 TrueTime 的假設(shè)。我們的機(jī)器統(tǒng)計(jì)數(shù)據(jù)顯示,壞的 CPU 的出現(xiàn)概率要比壞的時(shí)鐘出現(xiàn)概率大 6 倍。也就是說(shuō),與更加嚴(yán)峻的硬件問題相比,時(shí)鐘問題是很少見的。由此,我們也相信,TrueTime 的實(shí)現(xiàn)和 Spanner 其他軟件組件一樣,具有很好的可靠性,值得信任。

圖 6 顯示了 TrueTime 數(shù)據(jù),是從幾千個(gè) spanserver 中收集的,這些 spanserver 跨越了多 個(gè)數(shù)據(jù)中心,距離 2200 公里以上。圖中描述了 ε 的第 90 個(gè)、99 個(gè)和 99.9 個(gè)百分位的情況, 是在對(duì) timemaster 進(jìn)行投票后立即對(duì) timeslave daemon 進(jìn)行樣本抽樣的。這些抽樣數(shù)據(jù)沒有考慮由于時(shí)鐘不確定性帶來(lái)的 ε 值的鋸齒,因此測(cè)量的是 timemaster 不確定性(通常是 0) 再加上通訊延遲。

圖6

圖 6 中的數(shù)據(jù)顯示了,在決定 ε 的基本值方面的上述兩個(gè)問題,通常都不會(huì)是個(gè)問題。 但是,可能會(huì)存在明顯的拖尾延遲問題,那會(huì)引起更高的 ε 值。圖中,3 月 30 日拖尾延遲的降低,是因?yàn)榫W(wǎng)絡(luò)的改進(jìn),減少了瞬間網(wǎng)絡(luò)連接的擁堵。在 4 月 13 日 ε 的值增加了,持續(xù)了大約 1 個(gè)小時(shí),主要是因?yàn)槔芯S護(hù)時(shí)關(guān)閉了兩個(gè) time master。我們會(huì)繼續(xù)調(diào)研并且消除引起 TrueTime 突變的因素。

5.4 F1

Spanner 在 2011 年早期開始進(jìn)行在線負(fù)載測(cè)試,它是作為谷歌廣告后臺(tái) F1[35]的重新實(shí)現(xiàn)的一部分。這個(gè)后臺(tái)最開始是基于 MySQL 數(shù)據(jù)庫(kù),在許多方面都采用手工數(shù)據(jù)分區(qū)。未 經(jīng)壓縮的數(shù)據(jù)可以達(dá)到幾十 TB,雖然這對(duì)于許多 NoSQL 實(shí)例而言數(shù)據(jù)量是很小的,但是, 對(duì)于采用數(shù)據(jù)分區(qū)的 MySQL 而言,數(shù)據(jù)量是非常大的。MySQL 的數(shù)據(jù)分片機(jī)制,會(huì)把每個(gè)客戶和所有相關(guān)的數(shù)據(jù)分配給一個(gè)固定的分區(qū)。這種布局方式,可以支持針對(duì)單個(gè)客戶的 索引構(gòu)建和復(fù)雜查詢處理,但是,需要了解一些商業(yè)知識(shí)來(lái)設(shè)計(jì)分區(qū)。隨著客戶數(shù)量的增長(zhǎng), 對(duì)數(shù)據(jù)進(jìn)行重新分區(qū),代價(jià)是很大的。最近一次的重新分區(qū),花費(fèi)了兩年的時(shí)間,為了降低風(fēng)險(xiǎn),在多個(gè)團(tuán)隊(duì)之間進(jìn)行了大量的合作和測(cè)試。這種操作太復(fù)雜了,無(wú)法常常執(zhí)行,由此導(dǎo)致的結(jié)果是,團(tuán)隊(duì)必須限制 MySQL 數(shù)據(jù)庫(kù)的增長(zhǎng),方法是,把一些數(shù)據(jù)存儲(chǔ)在外部的 Bigtable 中,這就會(huì)犧牲事務(wù)和查詢所有數(shù)據(jù)的能力。

F1 團(tuán)隊(duì)選擇使用 Spanner 有幾個(gè)方面的原因。首先,Spanner 不需要手工分區(qū)。其次, Spanner 提供了同步復(fù)制和自動(dòng)失敗恢復(fù)。在采用 MySQL 的 master-slave 復(fù)制方法時(shí),很難進(jìn)行失敗恢復(fù),會(huì)有數(shù)據(jù)丟失和當(dāng)機(jī)的風(fēng)險(xiǎn)。再次,F(xiàn)1 需要強(qiáng)壯的事務(wù)語(yǔ)義,這使得使用 其他 NoSQL 系統(tǒng)是不實(shí)際的。應(yīng)用語(yǔ)義需要跨越任意數(shù)據(jù)的事務(wù)和一致性讀。F1 團(tuán)隊(duì)也需要在他們的數(shù)據(jù)上構(gòu)建二級(jí)索引(因?yàn)?Spanner 沒有提供對(duì)二級(jí)索引的自動(dòng)支持),也有能力使用 Spanner 事務(wù)來(lái)實(shí)現(xiàn)他們自己的一致性全球索引。

所有應(yīng)用寫操作,現(xiàn)在都是默認(rèn)從 F1 發(fā)送到 Spanner。而不是發(fā)送到基于 MySQL 的應(yīng) 用棧。F1 在美國(guó)的西岸有兩個(gè)副本,在東岸有三個(gè)副本。這種副本位置的選擇,是為了避免發(fā)生自然災(zāi)害時(shí)出現(xiàn)服務(wù)停止問題,也是出于前端應(yīng)用的位置的考慮。實(shí)際上,Spanner 的失敗自動(dòng)恢復(fù),幾乎是不可見的。在過去的幾個(gè)月中,盡管有不在計(jì)劃內(nèi)的機(jī)群失效,但是,F(xiàn)1 團(tuán)隊(duì)最需要做的工作仍然是更新他們的數(shù)據(jù)庫(kù)模式,來(lái)告訴 Spanner 在哪里放置 Paxos 領(lǐng)導(dǎo)者,從而使得它們盡量靠近應(yīng)用前端。

Spanner 時(shí)間戳語(yǔ)義,使得它對(duì)于 F1 而言,可以高效地維護(hù)從數(shù)據(jù)庫(kù)狀態(tài)計(jì)算得到的、放在內(nèi)存中的數(shù)據(jù)結(jié)構(gòu)。F1 會(huì)為所有變更都維護(hù)一個(gè)邏輯歷史日志,它會(huì)作為每個(gè)事務(wù)的 一部分寫入到 Spanner。F1 會(huì)得到某個(gè)時(shí)間戳下的數(shù)據(jù)的完整快照,來(lái)初始化它的數(shù)據(jù)結(jié)構(gòu), 然后根據(jù)數(shù)據(jù)的增量變化來(lái)更新這個(gè)數(shù)據(jù)結(jié)構(gòu)。

表 5 顯示了 F1 中每個(gè)目錄的分片數(shù)量的分布情況。每個(gè)目錄通常對(duì)應(yīng)于 F1 上的應(yīng)用棧中的一個(gè)用戶。絕大多數(shù)目錄(同時(shí)意味著絕大多數(shù)用戶)都只會(huì)包含一個(gè)分片,這就意味著,對(duì)于這些用戶數(shù)據(jù)的讀和寫操作只會(huì)發(fā)生在一個(gè)服務(wù)器上。多于 100 個(gè)分片的目錄,是那些包含 F1 二級(jí)索引的表:對(duì)這些表的多個(gè)分片進(jìn)行寫操作,是極其不尋常的。F1 團(tuán)隊(duì)也只是在以事務(wù)的方式進(jìn)行未經(jīng)優(yōu)化的批量數(shù)據(jù)加載時(shí),才會(huì)碰到這種情形。

表5

表 6 顯示了從 F1 服務(wù)器來(lái)測(cè)量的 Spanner 操作的延遲。在東海岸數(shù)據(jù)中心的副本,在 選擇 Paxos 領(lǐng)導(dǎo)者方面會(huì)獲得更高的優(yōu)先級(jí)。表 6 中的數(shù)據(jù)是從這些數(shù)據(jù)中心的 F1 服務(wù)器 上測(cè)量得到的。寫操作延遲分布上存在較大的標(biāo)準(zhǔn)差,是由于鎖沖突引起的肥尾效應(yīng)(fat tail)。在讀操作延遲分布上存在更大的標(biāo)準(zhǔn)差,部分是因?yàn)?Paxos 領(lǐng)導(dǎo)者跨越了兩個(gè)數(shù)據(jù)中心,只有其中的一個(gè)是采用了固態(tài)盤的機(jī)器。此外,測(cè)試內(nèi)容還包括系統(tǒng)中的每個(gè)針對(duì)兩個(gè) 數(shù)據(jù)中心的讀操作:字節(jié)讀操作的平均值和標(biāo)準(zhǔn)差分別是 1.6KB 和 119KB。

表6

6. 相關(guān)工作

Megastore[5]和 DynamoDB[3]已經(jīng)提供了跨越多個(gè)數(shù)據(jù)中心的一致性復(fù)制。DynamoDB 提供了鍵值存儲(chǔ)接口,只能在一個(gè) region 內(nèi)部進(jìn)行復(fù)制。Spanner 和 Megastore 一樣,都提供了半關(guān)系數(shù)據(jù)模型,甚至采用了類似的模式語(yǔ)言。Megastore 無(wú)法活動(dòng)高性能。Megastore 是架構(gòu)在 Bigtable 之上,這帶來(lái)了很高的通訊代價(jià)。Megastore 也不支持長(zhǎng)壽命的領(lǐng)導(dǎo)者, 多個(gè)副本可能會(huì)發(fā)起寫操作。來(lái)自不同副本的寫操作,在 Paxos 協(xié)議下一定會(huì)發(fā)生沖突,即使他們不會(huì)發(fā)生邏輯沖突:會(huì)嚴(yán)重影響吞吐量,在一個(gè) Paxos 組內(nèi)每秒鐘只能執(zhí)行幾個(gè)寫操作。Spanner 提供了更高的性能,通用的事務(wù)和外部一致性。

Pavlo 等人[31]對(duì)數(shù)據(jù)庫(kù)和 MapReduce[12]的性能進(jìn)行了比較。他們指出了幾個(gè)努力的方向,可以在分布式鍵值存儲(chǔ)之上充分利用數(shù)據(jù)庫(kù)的功能[1][4][7][41],二者可以實(shí)現(xiàn)充分的融合。我們比較贊同這個(gè)結(jié)論,并且認(rèn)為集成多個(gè)層是具有優(yōu)勢(shì)的:把復(fù)制和并發(fā)控制集成起來(lái),可以減少 Spanner 中的提交等待代價(jià)。

在一個(gè)采用了復(fù)制的存儲(chǔ)上面實(shí)現(xiàn)事務(wù),可以至少追述到 Gifford 的論文[16]。Scatter[17] 是一個(gè)最近的基于 DHT 的鍵值存儲(chǔ),可以在一致性復(fù)制上面實(shí)現(xiàn)事務(wù)。Spanner 則要比 Scatter 在更高的層次上提供接口。Gray 和 Lamport[18]描述了一個(gè)基于 Paxos 的非阻塞的提交協(xié)議,他們的協(xié)議會(huì)比兩階段提交協(xié)議帶來(lái)更多的代價(jià),而兩階段提交協(xié)議在大范圍分布 式的組中的代價(jià)會(huì)進(jìn)一步惡化。Walter[36]提供了一個(gè)快照隔離的變種,但是無(wú)法跨越數(shù)據(jù)中心。相反,我們的只讀事務(wù)提供了一個(gè)更加自然的語(yǔ)義,因?yàn)槲覀儗?duì)于所有的操作都支持外部語(yǔ)義。

最近,在減少或者消除鎖開銷方面已經(jīng)有大量的研究工作。Calvin[40]消除了并發(fā)控制: 它會(huì)重新分配時(shí)間戳,然后以時(shí)間戳的順序執(zhí)行事務(wù)。HStore[39]和 Granola[11]都支持自己的事務(wù)類型劃分方法,有些事務(wù)類型可以避免鎖機(jī)制。但是,這些系統(tǒng)都無(wú)法提供外部一致性。Spanner 通過提供快照隔離,解決了沖突問題。

VoltDB[42]是一個(gè)分片的內(nèi)存數(shù)據(jù)庫(kù),可以支持在大范圍區(qū)域內(nèi)進(jìn)行主從復(fù)制,支持災(zāi)難恢復(fù),但是沒有提供通用的復(fù)制配置方法。它是一個(gè)被稱為 NewSQL 的實(shí)例,這是實(shí)現(xiàn) 可擴(kuò)展的 SQL[38]的強(qiáng)大的市場(chǎng)推動(dòng)力。許多商業(yè)化的數(shù)據(jù)庫(kù)都可以支持歷史數(shù)據(jù)讀取,比如 Marklogic[26]和 Oracle’ Total Recall[30]。Lomet 和 Li[24]對(duì)于這種時(shí)間數(shù)據(jù)庫(kù)描述了一種 實(shí)現(xiàn)策略。

Faresite 給出了與一個(gè)受信任的時(shí)鐘參考值相關(guān)的時(shí)鐘不確定性的邊界[13](要比 TrueTime 更加寬松):Farsite 中的服務(wù)器租約的方式,和 Spanner 中維護(hù) Paxos 租約的方式 相同。在之前的工作中[2][23],寬松同步時(shí)鐘已經(jīng)被用來(lái)進(jìn)行并發(fā)控制。我們已經(jīng)展示了 TrueTime 可以從 Paxos 狀態(tài)機(jī)集合中推導(dǎo)出全球時(shí)間。

7. 未來(lái)的工作

在過去一年的大部分時(shí)間里,我們都是 F1 團(tuán)隊(duì)一起工作,把谷歌的廣告后臺(tái)從 MySQL 遷移到 Spanner。我們正在積極改進(jìn)它的監(jiān)控和支撐工具,同時(shí)在優(yōu)化性能。此外,我們已經(jīng)開展了大量工作來(lái)改進(jìn)備份恢復(fù)系統(tǒng)的功能和性能。我們當(dāng)前正在實(shí)現(xiàn) Spanner 模式語(yǔ)言,自動(dòng)維護(hù)二級(jí)索引和自動(dòng)基于負(fù)載的分區(qū)。在未來(lái),我們會(huì)調(diào)研更多的特性。以最優(yōu)化的方式并行執(zhí)行讀操作,是我們追求的有價(jià)值的策略,但是,初級(jí)階段的實(shí)驗(yàn)表明,實(shí)現(xiàn)這個(gè)目標(biāo)比較艱難。此外,我們計(jì)劃最終可以支持直接變更 Paxos 配置[22]34]。

我們希望許多應(yīng)用都可以跨越數(shù)據(jù)中心進(jìn)行復(fù)制,并且這些數(shù)據(jù)中心彼此靠近。 TrueTime ε 可能會(huì)明顯影響性能。把 ε 值降低到 1ms 以內(nèi),并不存在不可克服的障礙。 Time-master-query 間隔可以繼續(xù)減少,Time-master-query 延遲應(yīng)該隨著網(wǎng)絡(luò)的改進(jìn)而減少, 或者通過采用分時(shí)技術(shù)來(lái)避免延遲。

最后,還有許多有待改進(jìn)的方面。盡管 Spanner 在節(jié)點(diǎn)數(shù)量上是可擴(kuò)展的,但是與節(jié)點(diǎn)相關(guān)的數(shù)據(jù)結(jié)構(gòu)在復(fù)雜的 SQL 查詢上的性能相對(duì)較差,因?yàn)椋鼈兪潜辉O(shè)計(jì)成服務(wù)于簡(jiǎn)單的鍵值訪問的。來(lái)自數(shù)據(jù)庫(kù)文獻(xiàn)的算法和數(shù)據(jù)結(jié)構(gòu),可以極大改進(jìn)單個(gè)節(jié)點(diǎn)的性能。另外,根據(jù)客戶端負(fù)載的變化,在數(shù)據(jù)中心之間自動(dòng)轉(zhuǎn)移數(shù)據(jù),已經(jīng)成為我們的一個(gè)目標(biāo),但是,為了有效實(shí)現(xiàn)這個(gè)目標(biāo),我們必須具備在數(shù)據(jù)中心之間自動(dòng)、協(xié)調(diào)地轉(zhuǎn)移客戶端應(yīng)用進(jìn)程的能力。轉(zhuǎn)移進(jìn)程會(huì)帶來(lái)更加困難的問題——如何在數(shù)據(jù)中心之間管理和分配資源。

8. 總結(jié)

總的來(lái)說(shuō),Spanner 對(duì)來(lái)自兩個(gè)研究群體的概念進(jìn)行了結(jié)合和擴(kuò)充:一個(gè)是數(shù)據(jù)庫(kù)研究群體,包括熟悉易用的半關(guān)系接口,事務(wù)和基于 SQL 的查詢語(yǔ)言;另一個(gè)是系統(tǒng)研究群體,包括可擴(kuò)展性,自動(dòng)分區(qū),容錯(cuò),一致性復(fù)制,外部一致性和大范圍分布。自從 Spanner 概念成形,我們花費(fèi)了 5 年以上的時(shí)間來(lái)完成當(dāng)前版本的設(shè)計(jì)和實(shí)現(xiàn)。花費(fèi)這么長(zhǎng)的時(shí)間,一部分原因在于我們慢慢意識(shí)到,Spanner 不應(yīng)該僅僅解決全球復(fù)制的命名空間問題,而且也應(yīng)該關(guān)注 Bigtable 中所丟失的數(shù)據(jù)庫(kù)特性。

我們的設(shè)計(jì)中一個(gè)亮點(diǎn)特性就是 TrueTime。我們已經(jīng)表明,在時(shí)間 API 中明確給出時(shí)鐘不確定性,可以以更加強(qiáng)壯的時(shí)間語(yǔ)義來(lái)構(gòu)建分布式系統(tǒng)。此外,因?yàn)榈讓拥南到y(tǒng)在時(shí)鐘不確定性上采用更加嚴(yán)格的邊界,實(shí)現(xiàn)更強(qiáng)壯的時(shí)間語(yǔ)義的代價(jià)就會(huì)減少。作為一個(gè)研究群體,我們?cè)谠O(shè)計(jì)分布式算法時(shí),不再依賴于弱同步的時(shí)鐘和較弱的時(shí)間 API。

致謝

許多人幫助改進(jìn)了這篇論文:Jon Howell,Atul Adya, Fay Chang, Frank Dabek, Sean Dorward, Bob Gruber, David Held, Nick Kline, Alex Thomson, and Joel Wein. 我們的管理層對(duì)于我們的工作和論文發(fā)表都非常支持:Aristotle Balogh, Bill Coughran, Urs H ?olzle, Doron Meyer, Cos Nicolaou, Kathy Polizzi, Sridhar Ramaswany, and Shivakumar Venkataraman.

我們的工作是在Bigtable和Megastore團(tuán)隊(duì)的工作基礎(chǔ)之上開展的。F1團(tuán)隊(duì),尤其是Jeff Shute ,和我們一起工作,開發(fā)了數(shù)據(jù)模型,跟蹤性能和糾正漏洞。Platforms團(tuán)隊(duì),尤其是Luiz Barroso 和Bob Felderman,幫助我們一起實(shí)現(xiàn)了TrueTime。最后,許多谷歌員工都曾經(jīng)在我們的團(tuán)隊(duì)工作過,包括Ken Ashcraft, Paul Cychosz, Krzysztof Ostrowski, Amir Voskoboynik, Matthew Weaver, Theo Vassilakis, and Eric Veach; or have joined our team recently: Nathan Bales, Adam Beberg, Vadim Borisov, Ken Chen, Brian Cooper, Cian Cullinan, Robert-Jan Huijsman, Milind Joshi, Andrey Khorlin, Dawid Kuroczko, Laramie Leavitt, Eric Li, Mike Mammarella, Sunil Mushran, Simon Nielsen, Ovidiu Platon, Ananth Shrinivas, Vadim Suvorov, and Marcel van der Holst.

參考文獻(xiàn)

[1] Azza Abouzeid et al. ―HadoopDB: an architectural hybrid of MapReduce and DBMS technologies for analytical workloads‖. Proc. of VLDB. 2009, pp. 922–933.
[2] A. Adya et al. ―Efficient optimistic concurrency control using loosely synchronized clocks‖. Proc. of SIGMOD. 1995, pp. 23–34.
[3] Amazon. Amazon DynamoDB. 2012.
[4] Michael Armbrust et al. ―PIQL: Success-Tolerant Query Processing in the Cloud‖. Proc. of VLDB. 2011, pp. 181–192.
[5] Jason Baker et al. ―Megastore: Providing Scalable, Highly Available Storage for Interactive Services‖. Proc. of CIDR. 2011, pp. 223–234.
[6] Hal Berenson et al. ―A critique of ANSI SQL isolation levels‖. Proc. of SIGMOD. 1995, pp. 1–10. [7] Matthias Brantner et al. ―Building a database on S3‖. Proc. of SIGMOD. 2008, pp. 251–264.
[7] Matthias Brantner et al. ―Building a database on S3‖. Proc. of SIGMOD. 2008, pp. 251–264.
[8] A. Chan and R. Gray. ―Implementing Distributed Read-Only Transactions‖. IEEE TOSE SE-11.2 (Feb. 1985), pp. 205–212.
[9] Fay Chang et al. ―Bigtable: A Distributed Storage System for Structured Data‖. ACM TOCS 26.2 (June 2008), 4:1–4:26.
[10] Brian F. Cooper et al. ―PNUTS: Yahoo!’s hosted data serving platform‖. Proc. of VLDB. 2008, pp. 1277–1288.
[11] James Cowling and Barbara Liskov. ―Granola: Low-Overhead Distributed Transaction Coordination‖. Proc. of USENIX ATC. 2012, pp. 223–236.
[12] Jeffrey Dean and Sanjay Ghemawat. ―MapReduce: a flexible data processing tool‖. CACM 53.1 (Jan. 2010), pp. 72–77.
[13] John Douceur and Jon Howell. Scalable Byzantine-Fault-Quantifying Clock Synchronization. Tech. rep. MSR-TR-2003-67. MS Research, 2003.
[14] John R. Douceur and Jon Howell. ―Distributed directory service in the Farsite file system‖. Proc. of OSDI. 2006, pp. 321–334.
[15] Sanjay Ghemawat, Howard Gobioff, and Shun-Tak Leung. ―The Google file system‖. Proc. of SOSP. Dec. 2003, pp. 29–43.
[16] David K. Gifford. Information Storage in a Decentralized Computer System. Tech. rep. CSL-81-8. PhD dissertation. Xerox PARC, July 1982.
[17] Lisa Glendenning et al. ―Scalable consistency in Scatter‖. Proc. of SOSP. 2011.
[18] Jim Gray and Leslie Lamport. ―Consensus on transaction commit‖. ACM TODS 31.1 (Mar. 2006), pp. 133–160.
[19] Pat Helland. ―Life beyond Distributed Transactions: an Apostate’s Opinion‖. Proc. of CIDR. 2007, pp. 132–141.
[20] Maurice P. Herlihy and Jeannette M. Wing. ―Linearizability: a correctness condition for
concurrent objects‖. ACM TOPLAS 12.3 (July 1990), pp. 463–492.
[21] Leslie Lamport. ―The part-time parliament‖. ACM TOCS 16.2 (May 1998), pp. 133–169.
[22] Leslie Lamport, Dahlia Malkhi, and Lidong Zhou. ―Reconfiguring a state machine‖. SIGACT News 41.1 (Mar. 2010), pp. 63–73.
[23] Barbara Liskov. ―Practical uses of synchronized clocks in distributed systems‖. Distrib. Comput. 6.4 (July 1993), pp. 211–219.
[24] David B. Lomet and Feifei Li. ―Improving Transaction-Time DBMS Performance and Functionality‖. Proc. of ICDE (2009), pp. 581–591.
[25] Jacob R. Lorch et al. ―The SMART way to migrate replicated stateful services‖. Proc. of EuroSys. 2006, pp. 103–115.
[26] MarkLogic. MarkLogic 5 Product Documentation. 2012.
[27] Keith Marzullo and Susan Owicki. ―Maintaining the time in a distributed system‖. Proc. of PODC. 1983, pp. 295–305.
[28] Sergey Melnik et al. ―Dremel: Interactive Analysis of Web-Scale Datasets‖. Proc. of VLDB. 2010, pp. 330–339.
[29] D.L. Mills. Time synchronization in DCNET hosts. Internet Project Report IEN–173. COMSAT Laboratories, Feb. 1981.
[30] Oracle. Oracle Total Recall. 2012.
[31] Andrew Pavlo et al. ―A comparison of approaches to large-scale data analysis‖. Proc. of SIGMOD. 2009, pp. 165–178.
[32] Daniel Peng and Frank Dabek. ―Large-scale incremental processing using distributed transactions and notifications‖. Proc. of OSDI. 2010, pp. 1–15.
[33] Daniel J. Rosenkrantz, Richard E. Stearns, and Philip M. Lewis II. ―System level concurrency control for distributed database systems‖. ACM TODS 3.2 (June 1978), pp. 178–198.
[34] Alexander Shraer et al. ―Dynamic Reconfiguration of Primary/Backup Clusters‖. Proc. of
SENIX ATC. 2012, pp. 425–438.
[35] Jeff Shute et al. ―F1—The Fault-Tolerant Distributed RDBMS Supporting Google’s Ad Business‖. Proc. of SIGMOD. May 2012, pp. 777–778.
[36] Yair Sovran et al. ―Transactional storage for geo-replicated systems‖. Proc. of SOSP. 2011, pp. 385–400.
[37] Michael Stonebraker. Why Enterprises Are Uninterested in NoSQL. 2010.
[38] Michael Stonebraker. Six SQL Urban Myths. 2010.
[39] Michael Stonebraker et al. ―The end of an architectural era: (it’s time for a complete rewrite)‖. Proc. of VLDB. 2007, pp. 1150–1160.
[40] Alexander Thomson et al. ―Calvin: Fast Distributed Transactions for Partitioned Database Systems‖. Proc. of SIGMOD.2012, pp. 1–12.
[41] Ashish Thusoo et al. ―Hive — A Petabyte Scale Data Warehouse Using Hadoop‖. Proc. of ICDE. 2010, pp. 996–1005.
[42] VoltDB. VoltDB Resources. 2012.

linbingdong.com

歡迎進(jìn)入博客 :linbingdong.com 獲取最新文章哦~

FullStackPlan

歡迎關(guān)注公眾號(hào): FullStackPlan 獲取更多干貨哦~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容