1. 程式人生 > >Google準實時資料倉庫Mesa(一)

Google準實時資料倉庫Mesa(一)

本文來自網易雲社群

作者:王潘安


以下是本人在學習Google的Mesa資料倉庫論文的記錄,翻譯出來給大家分享,翻譯水平有限,請多多包涵。因論文比較長,本人將論文按照Mesa不同的模組分開翻譯,方便閱讀。


摘要:Mesa是一個可伸縮性的分析型資料倉庫系統,它主要為Google的網際網路廣告業務服務。Mesa的設計是為了滿足一系列的來自使用者和系統的複雜的挑戰。包括近乎實時的資料獲取和查詢,高可用性,可靠性,容錯性以及伸縮性。Mesa每秒處理PB級的資料以及百萬行的更新。每天服務十億次查詢,獲取萬億行資料。Mesa是一個跨多個數據中心的資料倉庫,它提供一致的,可重複,低延遲的查詢服務,即使是在一個數據中心完全癱瘓的情況下。


一.介紹

  隨著業務量的增大,資料的處理,儲存和查詢都面臨挑戰。對資料儲存的要求有如下幾點(此處省略一堆廢話):

  原子更新。一個單使用者的操作就可能引起相關資料的多次更新,影響大量的定義在跨多維度上的多指標集的一致性檢視。不允許存在對系統進行查詢時,只有一部分資料更新成功的情況。

  一致性和正確性。出於商業和法律上的考慮。系統必須返回一致和正確的資料。即使一個查詢跨多個數據中心,我們也要提供強一致性和可重複的查詢結果。

        可用性。系統不允許出現單點故障。不會出現由於計劃中或非計劃中的維護或故障所造成的停機,即使出現影響整個資料中心或地域性的斷電也不能造成停機。         

        近實時的更新。系統必須支援大約每秒幾百萬行規模的持續更新,包括新增新資料行和對現有資料行的增量更新。這些更新必須在幾分鐘內對跨不同檢視和資料中心的查詢可見。

        查詢效能。系統必須對那些對時間延遲敏感的使用者提供支援,按照超低延遲的要求為他們提供實時的客戶報表,而進行批處理的使用者需要非常高的吞吐量。總的來說,系統必須支援將99%的點查詢的延遲控制在數百毫秒之內,並且整體查詢控制在每天獲取萬億行的吞吐量。

  可伸縮性。系統規模必須可以隨著資料規模和查詢總量的增長而伸展。舉個例子,它必須支援萬億行規模和PB級的資料。但是即使上述引數再出現顯著增長,更新和查詢的效能必須仍然得以保持。

  線上的資料和元資料轉換。為了支援新功能的釋出或對現有資料粒度的變更,客戶端經常需要對資料模式進行轉換或對現有資料的值進行修改。這些變更必須對正常的查詢和更新操作沒有干擾。

  Mesa是針對這些技術上和操作上的挑戰的解決方案。儘管這些需求的某一部分已經被現有的資料倉庫系統解決了。Mesa是一個能同時解決上述問題的解決方案。Mesa是一個針對結構化資料的分散式,可備份並且高可用的資料處理,儲存和查詢系統。Mesa從生成資料的流服務中獲取資料,在內部進行聚合和持久化,通過查詢給使用者提供服務。儘管這篇論文主要討論的是廣告業務,但是Mesa是一個能滿足上述所有需求的通用的資料倉庫。 

  Mesa利用谷歌的基礎設施和服務,比如Colossus(谷歌下一代的分散式檔案系統),BigTable以及MapReduce,將資料被水平分片和備份,來實現儲存的可擴充套件性和可用性。更新操作可能會發生在一個單表的粒度上或者跨多張表。為了實現一致性以及滿足在更新的時候的反覆查詢,基礎資料是多版本的。為了實現資料更新的可擴充套件性,資料是批量的,帶版本號的,週期性的合併進入Mesa中的。為了實現跨多資料中心的更新一致性,Mesa使用基於Paxos的分散式一致性協議。

    許多基於關係型和資料立方體的資料倉庫產品不支援在給使用者提供近實時查詢的同時,每幾分鐘就將資料倉庫中的資料連續的整合和匯聚。通常,這些解決方法都是與傳統企業資料倉庫相關的。在傳統企業資料倉庫中,資料匯聚進入資料倉庫的頻率低,通常是按天或者周匯聚。類似的,谷歌內部的關於大資料的技術,比如說BigTable, Megastore, Spanner和F1,也都不能滿足這個場景。BigTable不能滿足Mesa提出的必要的原子性的需求。Megastore, Spanner和F1通常用來處理線上業務,他們支援跨地域的資料的強一致性,但是它們不能滿足Mesa更新操作吞吐量的峰值。但是,Mesa確實使用了BigTable和Paxos技術以及Spanner的元資料儲存的技術。

  (這段實在不想翻譯了。總之,目前市面上的大資料產品都不行!真是狂拽酷炫吊炸天!)

  這篇論文的貢獻主要如下:

  • 我們展示瞭如何建立一個PB級資料倉庫,同時又擁有ACID這些事物性處理功能的系統。並且它可伸縮,來滿足谷歌高吞吐率的廣告指標。

  • 我們描述了一個版本管理系統,它使得高吞吐量的批量更新操作在可接受的延遲內完成,同時也支援大量的查詢在低延遲下完成。

  • 我們描述了一個高擴充套件性的分散式架構,在單資料中心中,它可以從宕機和網路故障中恢復。我們也展示了一個跨地域備份的架構來應對資料中心的癱瘓。這種設計的不同之處在於,業務資料是通過獨立且冗餘的程序在多資料中心間非同步備份。只有關鍵的元資料是同步的拷貝到每個地方。這種技術可以使跨資料中心的同步代價最小,並且還可以提供高吞吐的更新操作。

  • 我們展示瞭如何在不影響正確性和已存在應用的效能的條件下,動態和高效的處理大量表模型的變化。

  • 我們描述了應對由硬體或者軟體引起的資料錯誤的關鍵技術。

  • 我們描述了這種規模的系統在保證正確性,一致性和效能上的挑戰。並且提出幾點供新的研究來改進。


二 .  Mesa儲存子系統

       Mesa中的資料持續不斷的生成,它是谷歌量級最大,價值最高的資料集。在這個資料集上的分析型查詢包括簡單的查詢,諸如:“某一個特定的廣告在某一天有多少點選量?”和涉及更多內容的查詢,諸如:“某一個特定的廣告,在十月份第一個星期的上午8點到11點間,通過移動裝置在某個特定的地理位置,通過關鍵字decaf在google.com上搜索獲得的點選量是多少?”

  資料在Mesa中以多維模型存放,它依據不同的維度獲取了所有谷歌廣告平臺上最細節的事實。這些事實由兩部分屬性組成:維度屬性(我們稱為鍵)和度量屬性(我們稱為值)。因為很多維度屬性是分層的,甚至有多層,比如日期維度中年/月/日或者周/季度/年。那麼單一事實就需要根據這些層次維度匯聚成多個物化檢視,來滿足資料分析中的上卷和下鑽操作。一個謹慎的資料倉庫設計要求一個事實在多個聚合和物化中保持一致性。


2.1 資料模型

  在Mesa中,資料以表的形式儲存。每張表有它的模型(schema)來描述它的結構。一個表模型有它的鍵空間K和相應的值空間V,K和V在這裡都是集合。表模型也有它的聚合函式F: V × V -> V 用來聚合跟同一鍵相關的多個值。聚合函式必須滿足結合律。在很多情況下,它也滿足交換律,儘管Mesa中包含不滿足交換律的聚合函式。表模型中也包含一個或者多個K的全序索引。

        鍵空間K和值空間V表現為列的二元組。他們都有固定的資料型別,表模型為每個單獨的列指定了聚合函式F,F隱式的定義成如下形式(譯者注:說白了,就是把V放在一起寫,對應於每個二元組的聚合函式不單獨寫出來,統一寫成個F):

         F((x1,.....,xk),(y1,.....yk)) = (f1(x1, y1),......fk(xk, yk))

其中(x1,.....,xk)和(y1,.....yk)都屬於V,f1....fk這種形式是聚合函式的顯式表現形式。(真蛋疼)

        舉個例子。圖片1展示了Mesa中的三個表。這三張表都包含廣告的點選量和費用,只不過被分散到不同的屬性中,比如按天的點選量,(譯者注:圖中的Date, PublisherId, Country, AdvertiserId都是key, Clicks和Cost是value)。作用於所有列的聚合函式是SUM。假設相同的底層事件更新了這三張表的資料,那麼所有的指標都被一致的表現在三個表中。表1只是簡單的呈現了表模型。在生產環境中,Mesa包含上千張表,每張表包含上百列,使用多個聚合函式。

1c31c0da-978a-44f1-a986-9c677ae4e5df

2.2 更新和查詢

        為了實現大吞吐量的更新操作,Mesa採用批量更新。這些更新的批量包產生於Mesa系統外的上游系統,每隔幾分鐘產生(更小的頻率更高的更新包可以使更新操作延遲低,但是它需要消耗更多的資源)。每次更新,Mesa都會指定一個版本號 n (從0開始的序列)以及這些更新行的構成(表名,鍵,值)。每一個(表名,鍵)至多包含一個匯聚值。

        Mesa上的一個查詢包含一個版本號 n 和 鍵空間上的謂語P。返回值包含一行符合條件P的鍵,這些鍵出現在一些更新中並帶上了版本號0到n。而資料值按照表結構中定義的聚合函式進行聚合後,返回聚合值。Mesa實際上支援更復雜的查詢功能,但是所有的都可以看成對這種基本查詢的預處理和後加工。

        舉個例子,圖片2中的展示了兩次關於圖片1中的表的更新操作。為了保證表的一致性,每個更新操作包含對兩個表A,B的一致性的行(譯者注:說白了,就是要同時更新兩個表中的某一行),Mesa會自動算出表C的更新操作,這是因為它可以直接源自表B的更新操作。理論上說,一個單次的更新操作同時包含AdvertiserId和PublisherId屬性也可以被用作更新這三張表,但是這個代價比較大,特別是在表包含大量的屬性的情況下。

dd339868-82e7-4882-af7b-cc1e4d7d662f

        注意表C與以下這個表B的物化檢視的關係:SELECT SUM(Clicks), SUM(Cost) GROUP BY AdvertiserId, Country. 這個查詢可以直接當作Mesa中的表,這是因為查詢中的SUM函式就是對錶B中所有度量值列的匯聚函式。Mesa約束在所有的度量列上使用相同的聚合函式,才能稱作物化檢視。

        為了使更新原子性,Mesa採用了多版本的方法。Mesa按版本號的順序執行更新操作。通過在執行下一條更新操作之前完全合併此次更新操作來確保原子性。使用者永遠感受不到區域性合併更新帶來的影響。

        嚴格的按順序更新帶來的不僅僅是原子性的應用。Mesa中的有些聚合函式不滿足交換律,比如在標準的Key-Value儲存中,一個(Key, Value)的更新完全覆蓋它之前的值。更細緻的來看,按順序的約束使得Mesa支援將錯誤的事實用相反的行為來表示。特別的,谷歌使用欺詐探測來決定廣告的點選是否合法。欺詐性的點選可以用相反的事實來表示。比如在上圖2中,就可以跟一個版本2的更新,這個更新包括負值的點選數和費用,去標記之前處理的點選數是非法的。通過嚴格的按順序更新,Mesa保證了負的更新事實永遠不會在它的正事實之前被合併。


2.3 資料版本管理

         資料版本在Mesa的更新和查詢中扮演了十分重要的角色。但是它也帶來了很多挑戰。首先,對於那些可以被聚合的廣告統計資料,單獨儲存每一個版本從儲存的角度來看非常昂貴。聚合後的資料量就要小的多。其次,在查詢的時候,遍歷所有的版本並且聚合它們的代價也很大,並且會加大查詢的延遲。再次,在每次更新時都提前聚合所有的版本也需要極高的代價。

        為了處理這個問題。Mesa提前聚合某些版本的資料並且使用deltas儲存(譯者注:說白了就是分版本區間儲存),每一個delta包含一組不重複鍵的資料,以及一個delta版本號,用[V1, V2]表示,其中V1和V2是更新操作版本號,並且V1小於或等於V2。我們用版本號來表示delta就很清楚了。delta[V1, V2]中的行指的是那些出現在版本號為V1和V2之間的更新操作的鍵,值對應的就是這些更新操作聚合後的值。更新操作被當做是一個單例delta合併進Mesa。一個單例delta版本[V1, V2]滿足V1=V2=n, 其中n就是此次更新的版本號。

        delta[V1, V2]和delta[V2+1, V3]可以通過簡單的合併鍵/聚合值的方式合併成一個delta[V1, V3](2.4章節中會討論,所有的行都是以鍵的方式儲存的,所以說,兩個delta可以線上性時間內合併完成),這個計算的正確性是由聚合函式F確保的。這個正確性並不依賴函式F的交換律。無論何時Mesa通過一個給定的鍵合併兩個值時,delta的版本都是形如[V1, V2]和[V2+1, V3]的,並且這個操作是在不斷增長的有序版本號上進行的。

        Mesa僅僅允許使用者查詢一段時間以內的所有版本,比如24小時以內的。這就說明,早於這個時間的版本就可以聚合到一個基礎delta中,設它的版本號為[0, B], 其中B大於或等於0,這樣,任意一個delta[V1, V2]只要滿足0 <= V1 <= V2 <= B就可以被刪除。這個過程被稱為base compaction(基礎壓縮聚合,譯者注:真不知道該如何翻譯這個專業名詞)。Mesa同其他操作,比如查詢和更新,併發的非同步執行這個base compaction操作。

        注意一下,跟更新版本有關的的時間是由那個版本生成的,它獨立於資料中的任何時間資訊。舉個例子,圖1中的Mesa表,資料中的2014/01/01這個時間是永遠不會被移除的。Mesa可能會拒絕超過某個時間後的版本的查詢。資料中的時間資料其實是另外一個屬性並且它對Mesa不透明(譯者注:提醒讀者資料中的時間和Mesa中記錄版本的時間不要混為一談)。

        有了base compaction, 回答某個版本n上的查詢,我們可以聚合一個基本的delta[0, B]和一系列單例delta[B+1, B+1]. [B+2, B+2],...,[n,n],然後返回值。雖然我們經常的聚合成一個基礎delta(比如說每天),但是我們的單例delta個數很容易上百,甚至上千,特別是對於那些更新密集的表。為了支援更高效的查詢,Mesa包含了一些形如[U,V]的累積delta D,其中B < U < V。這些累積的delta可以被用來求解一個版本n的delta劃分,比如{[0, B],[B+1, V1],[V1+1, V2],...,[Vk+1, n]},這樣就比直接使用單例delta需要更少的聚合操作。當然,這些累積delta也需要一些處理和儲存上的開銷。但是這些開銷被分攤到了所有的操作中去了,特別是查詢操作。所以用這些delta代替單例delta是可行的。

         delta的聚合策略決定了每個時刻deta在Mesa上是如何維護的。它的基本目的是平衡那些查詢操作,更新操作以及處理和儲存累積delta的開銷。這個delta的策略要考慮三件事情:1. 哪些delta(除了單例delta)需要優先生成來滿足這些更新版本可以被查詢到。這個操作是在更新路徑上同步進行的,會降低更新的速度。2. 哪些delta是可以在更新路徑以外非同步的生成的。3. 那些delta是可以被刪除的。

         如圖3所示的一個delta匯聚策略就是一個雙重級別的策略。在這種策略中,任何時刻都存在一個基本delta[0, B], 一系列的累積delta[B+1, B+10], [B+1, B+20],[B+1, B+30],...以及B以後的所有單例delta。每當第B+10X個版本合併時,就非同步的生成delta[B+1, B+10X]。新的基礎delta[0, B1]每天生成一次,但是這個新的基礎delta在所有基於它的累積delta還沒完全生成之前是不可用的。當基礎delta B切換到B1時,這個策略就將老的基礎delta,累積delta以及所有B1版本之前的單例delta刪除。這樣的話,一個查詢就只需要一個基礎delta,一個累積delta和幾個單例delta組合完成,大大減少了查詢時的工作量。

dc48ea24-ae31-48ff-90f1-29946a105e10

         Mesa目前所使用的是兩級別delta的變種策略,它使用多種級別的累積delta,對於最近的版本,累積delta包含少量的單例delta,對於比較老的版本,累積delta包含較多的單例delta。一個delta層級可能包含一個基礎delta,一個包含100個版本的delta,一個包含10個版本的累積delta,以及多個單例delta。類似的基於日誌結構的儲存引擎有LevelDB和BigTable。我們注意到,基於差異更新的Mesa維護資料的方式,是一個簡單的對不同儲存模型的適配。並且它可以被用於增長性檢視和列存的更新。(譯者注:我真看不懂這句話,隨便翻譯的。)

2.4 物理資料和索引形式

        Mesa中的delta是基於delta聚合策略來建立和刪除的。一旦delta被建立,它就是不可變的,所以物理的儲存結構不需要支援高效的增量更新。

        不可變的delta就允許Mesa使用一個相當簡單的儲存結構。因為儲存是Mesa的主要開銷,因此,對這種儲存結構的基本要求就是省空間。Mesa還必須支援根據鍵的快速查詢,因為一個查詢往往關係幾個delta,然後根據鍵將值聚合起來。為了使查詢鍵變的高效,每個Mesa表包含一個或多個表索引,每個表索引都包含一個根據索引排序的資料的拷貝(譯者注:空間換時間咯)。

        儲存結構的細節比較偏向技術,所以我們只關注最重要的部分。delta中的行按順序儲存在有大小限制的資料檔案中(這是針對檔案系統檔案大小限制的優化)。這些行本身被組織在行塊中,每個行塊被單獨的變換和壓縮。每個行塊中的資料按列式儲存來進行變換壓縮,提高壓縮率。因為儲存是Mesa主要的開銷,並且在查詢時解壓效能比寫入時壓縮效能重要。所以我們在選用壓縮演算法的時候更強調壓縮比和解壓速率。

        Mesa為每份資料檔案儲存一份索引檔案。每個索引例項包含一個行塊的短鍵,這個短鍵由這個行塊第一個鍵的固定長度字首以及這個壓縮行塊在資料檔案中的偏移量組成。那麼查詢一個指定的鍵的演算法就可以分為兩步,首先通過二分法從索引檔案中找出可能包含這個短鍵的行塊,然後在這個壓縮的行塊中通過二分法找到想要的鍵。


這一篇就翻譯到這裡,其中的思想很值得借鑑,有些開源的專案已經採用了部分技術。下一篇我們一起看看Mesa的架構。


網易雲免費體驗館,0成本體驗20+款雲產品!

更多網易研發、產品、運營經驗分享請訪問網易雲社群


相關文章:
【推薦】 聊一聊資料分析師這個職業
【推薦】 Spring Boot + Mybatis 多資料來源配置實現讀寫分離
【推薦】 網易物件儲存NOS圖床神器