本文來自網易雲社區算法
做者:王潘安網絡
如下是本人在學習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包含上千張表,每張表包含上百列,使用多個聚合函數。
2.2 更新和查詢
爲了實現大吞吐量的更新操做,Mesa採用批量更新。這些更新的批量包產生於Mesa系統外的上游系統,每隔幾分鐘產生(更小的頻率更高的更新包可使更新操做延遲低,可是它須要消耗更多的資源)。每次更新,Mesa都會指定一個版本號 n (從0開始的序列)以及這些更新行的構成(表名,鍵,值)。每個(表名,鍵)至多包含一個匯聚值。 Mesa上的一個查詢包含一個版本號 n 和 鍵空間上的謂語P。返回值包含一行符合條件P的鍵,這些鍵出如今一些更新中並帶上了版本號0到n。而數據值按照表結構中定義的聚合函數進行聚合後,返回聚合值。Mesa實際上支持更復雜的查詢功能,可是全部的均可以當作對這種基本查詢的預處理和後加工。 舉個例子,圖片2中的展現了兩次關於圖片1中的表的更新操做。爲了保證表的一致性,每一個更新操做包含對兩個表A,B的一致性的行(譯者注:說白了,就是要同時更新兩個表中的某一行),Mesa會自動算出表C的更新操做,這是由於它能夠直接源自表B的更新操做。理論上說,一個單次的更新操做同時包含AdvertiserId和PublisherId屬性也能夠被用做更新這三張表,可是這個代價比較大,特別是在表包含大量的屬性的狀況下。 注意表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組合完成,大大減小了查詢時的工做量。 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+款雲產品!
更多網易研發、產品、運營經驗分享請訪問網易雲社區。
文章來源: 網易雲社區