雲計算

[Snowflake核心技術解讀系列二]雲原生技術

背景:2020年9月16日,Snowflake成功IPO,交易首日市場估值達到704億美元,募集資金34億美元。Snowflake成為迄今為止規模最大的軟件IPO,市值最高突破1200億美元。Snowflake提供基於雲的數據存儲和分析服務,一般被稱為 "數據倉庫即服務",它允許企業用戶使用基於雲的硬件和軟件來存儲和分析數據。Snowflake自2014年起在亞馬遜S3上運行,自2018年起在微軟Azure上運行,自2019年起在谷歌雲平臺上運行,其Snowflake Data Exchange允許客戶發現、交換和安全地共享數據。[維基百科]

Snowflake取得了巨大的商業成功,技術是如何支撐起它的千億美元市值呢?它技術強在哪?OLAP內核技術愛好者浙川為大家傾情解讀Snowflake的核心技術原理。本文為該系列二。

Snowflake中的雲原生技術

本章節將圍繞數據存儲、虛擬倉庫和雲服務組件,來詳細展開介紹Snowflake設計中的技術細節,分析他們是如何充分利用底層雲服務的架構和資源的。

數據存儲

Snowflake的數據存儲組件是構建在Amazone S3存儲服務之上的,之所以採用這樣的設計選擇,是因為Amazon S3存儲服務提供了高易用性、高服務可靠性,以及嚴格的數據持久性保證。S3的這些特性大大降低了Snowflake進行數據存儲開發的成本,Snowflake的數據存儲設計只需要考慮本地緩存、數據傾斜修復等特性即可。

然而,和直接使用本地存儲比起來,S3卻存在一些限制。S3具有更高的數據訪問延遲,同時每個S3的I/O請求需要更高的CPU開銷,尤其是使用HTTPS連接的情況下。另外,S3是對象存儲,其數據存儲操作接口就是PUT/GET/DELETE等簡單接口,數據對象只能作為整體被寫入,不支持帶有偏移量的寫入(但支持帶有偏移量的讀取),也不支持數據追加寫(append)。

S3的這些特點影響著Snowflake在數據表文件格式上的設計選擇。Snowflake將其數據庫橫向分區為多個大文件,每個文件就類似於傳統數據庫存儲系統中的數據塊或者數據頁概念,文件一旦生成,就不再改變。每個文件中,表數據以列存格式進行存儲,每一列數據在物理上存放到一起,然後再進行壓縮。每個文件都對應一個文件頭,文件頭包括基本存儲元數據信息,例如每一列數據在文件中的偏移。由於S3是支持帶有偏移量的數據讀取的,因此,只需要將文件頭數據拿到,就可以根據需要訪問某一列的數據了。

Snowflake還會利用S3存儲複雜查詢(例如大規模join)計算過程中產生的臨時數據,這樣可以支持系統運行任意複雜類型的查詢,而不會導致系統內存或本地存儲被耗盡。Snowflake還會將查詢結果存儲到S3中,以簡化用戶執行交互式查詢的系統複雜度,因為不需要再像傳統數據庫那樣針對交互式查詢維護一個cursor了。

數據庫級別的元數據信息如表的元數據、表對應的S3文件、統計信息、事務信息等,保存在雲服務相關組件中的分佈式key-value存儲中。

虛擬倉庫

虛擬倉庫實質上是由EC2實例組成的集群,組成虛擬倉庫的每個獨立的EC2實例又稱為計算節點。Snowflake的用戶不會直接和計算節點進行交互,他們甚至不需要關注由多少計算節點組成了他們的虛擬倉庫。用戶只需要選擇虛擬倉庫的配置,而這些配置就像T恤衫的尺碼一樣,被抽象成X-Small到XX-large的範圍供用戶選擇。


彈性和隔離性。作為純粹、彈性的計算資源,虛擬倉庫可以在任意時間進行按需地創建、銷燬或者重新配置。創建或者銷燬虛擬倉庫不會影響數據倉庫中存儲的用戶數據,這樣設計的好處就是用戶可以根據他們的計算需求動態地申請計算資源,用戶甚至可以在沒有任何計算需求的情況下銷燬所有的數據倉庫,而不用關心他們數據存儲量的大小。

用戶的每個查詢請求會被分配到某個虛擬倉庫上進行執行。由於不同的虛擬倉庫並不會共享同一個計算節點,因此,不同虛擬倉庫上運行的查詢之間互相不會有資源競爭和性能影響,即性能隔離性得到了很好的滿足。當然,虛擬倉庫不共享計算節點也有它的弊端,比如整個系統的資源利用率會很低,Snowflake後續會專門針對這一點做優化和提升。

虛擬倉庫在執行查詢請求的時候,每個計算節點上會對應生成一個計算進程,計算進程的生命週期就是這個查詢請求的生命週期。當計算進程遇到了錯誤,可以簡單通過重試來解決。因此,Snowflake在查詢層面具有較高的容錯性,但是Snowflake目前只執行整個查詢的重試,並不支持重試查詢下的某個子任務。需要強調的是,查詢開始時創建計算進程、結束後銷燬計算進程這種模式適合執行時間比較長的分析型查詢,但對於執行時間很短的短查詢,創建、銷燬計算進程的開銷就太大了。為了對短查詢進行優化,Snowflake在一個由若干個計算節點組成的集合中維護特定的計算進程,這些進程專門用來執行短查詢,短查詢執行結束後,這些進程並不會被銷燬,而是重複利用執行後續的短查詢。

在Snowflake中,用戶可以申請多個虛擬倉庫,每個虛擬倉庫上可以併發運行多個查詢。每個虛擬倉庫都共享相同的表數據,他們不需要為了運行計算任務而單獨地拷貝數據。這樣的設計方案有效地利用了彈性和隔離性的優點:Snowflake的用戶可以任意按需擴展虛擬倉庫的數量和配置,但是只需要存儲和操作一份數據;不同負載的查詢任務可以運行在不同的虛擬倉庫上,虛擬倉庫之間的計算資源是互相獨立的,這樣可以保證不同負載的查詢之間互不影響性能。

根據Snowflake統計的實踐經驗,虛擬倉庫的彈性還可以為用戶帶來性價比更高的服務:在幾乎同樣的價格下,用戶可以享受更快的性能。例如,如果某個工作負載在4個計算節點上執行需要花費15個小時,那麼在32個計算節點上執行可能只需要花費2個小時。雖然這兩種模式的價格是差不多的,但是帶給用戶的體驗卻有著根本的區別:在同樣花費的情況下,性能越快用戶感受就會越好。而虛擬倉庫的彈性恰恰為用戶提供了極佳體驗的選擇,用戶可以配置虛擬倉庫,以更快地完成計算任務,但是並不需要額外多的花費開銷。


緩存和文件轉移。虛擬倉庫中,每個計算節點會在本地對訪問過的表數據進行緩存,緩存對象即為數據表在S3上對應的文件。本地一定會進行緩存的數據是文件頭(詳細內容參見5.3.1章節),根據文件頭的信息可以下載任意指定要訪問的數據計算節點上的緩存數據是可以被該節點上的查詢任務共享。當緩存容量達到上限時,Snowflake採取簡單的LRU(Least-Recently-Used)算法來進行緩存替換。

為了提高緩存命中率,同時為了避免在同一個虛擬倉庫中不同的計算節點上緩存相同的表數據文件,Snowflake將不同的表文件分佈到不同的計算節點上,分佈算法採用的是針對表名的一致性hash算法。需要操作同一個表文件的查詢請求都會訪問同一個計算節點。同時,Snowflake採用的是惰性一致性hash算法:即當計算節點的數目發生改變的時候,不會立即對計算節點上的文件進行重新分佈,而是當LRU算法需要對緩存的文件進行替換的時候,再將新的文件根據最新計算節點的數目進行一致性hash分佈。這樣設計的好處就是不會因為立即的數據重新分佈而影響正在執行的查詢任務,相比於會立即進行大量數據重新分佈的shared-nothing架構,具有更高的可用性和用戶體驗。

在實際運行中,Snowflake還會遇到傾斜(skew)問題:一些計算節點可能由於虛擬化、網絡競爭、負載過高等問題,其響應速度遠遠低於其他計算節點,這就會導致這些計算節點可能會拖慢需要訪問它們緩存數據的其他查詢的性能。為了解決這樣的傾斜問題,Snowflake在文件掃描階段做了額外的處理邏輯。當某個計算節點掃描完輸入文件而需要從其他計算節點讀取數據文件時,它會向目標節點發送文件讀取請求。如果目標節點目前負載很高,它不會直接返回文件數據,而是回覆將該文件的使用權轉移給請求節點。發生文件轉移後,請求節點在當前查詢的生命週期內,可以直接從S3上下載數據文件,而不需要再從目標節點那裡訪問數據文件。這樣就避免了在慢節點上再增加額外的負載,以減輕系統的傾斜情況。


執行引擎。保證系統的可擴展性十分重要,提升系統單節點的計算性能同樣十分重要:同樣的執行時間下,能用10臺計算節點就肯定不用1000臺計算節點。Snowflake針對其系統的執行引擎也做了大量優化,以提升其單計算節點上的計算性能,進而為用戶提供更好性價比的服務。Snowflake的計算引擎採用了三大技術:列存、向量化、結果下推。

對於分析型場景來說,列式存儲的收益往往優於行式存儲的效率,因為在只訪問較少列的情況下,列式存儲的CPU利用率和I/O利用率會更高。同時,列式存儲可以更方便地應用SIMD指令集,也具有更高的數據壓縮率。

Snowflake採用的向量化執行方案源自於MonetDB/X100方案。Snowflake避免了中間結果的物化,而是以流水線的形式批量地處理數據(一次處理幾千行對應的列數據),這種方式不僅大大降低了I/O的開銷,而且有效地提升了cache的使用效率。

Snowflake的結果下推採用的是經典的火山模型:在Snowflake中,關係型算子可以將它們的結果直接下推給下游的算子,而不是等著下游的算子來這裡拉取結果。這種下推方式可以減少不必要的控制流邏輯,提升cache的使用效率。結果下推還讓Snowflake有能力處理DAG(Directed Acyclic Graph)執行計劃,DAG執行計劃可以對中間結果數據進行更高效的共享和流水線化。

很多傳統數據庫執行引擎所不得不面臨的設計開銷對Snowflake的執行引擎而言可能並不需要關注。比較典型的就是Snowflake在執行查詢請求的時候,並需要考慮事務管理相關的問題。如5.3.1章節所述,Snowflake的文件一旦寫入到S3中,就不會再改變了,因此,Snowflake的查詢執行是建立在不可變文件上的,所以事務管理是不需要的。同時,Snowflake也沒有維護內存緩衝區。在Snowflake中,大部分查詢操作的數據量都非常的大,如果採用內存緩衝區來緩存這麼大量的數據,雖然會提升查詢性能,但是代價也是非常大的:會消耗大量寶貴且昂貴的內存。相反,Snowflake會將複雜查詢(包括join、group by、sort等)的中間結果保存到本地磁盤上,並遞歸地對磁盤數據進行操作。磁盤的容量遠遠高於內存,價格也相對便宜。基於這樣的設計,Snowflake幾乎可以處理任意負載類型的查詢任務,包括極其複雜的大規模join或者agg計算。

注:譯文來自 https://www.snowflake.com/resource/sigmod-2016-paper-snowflake-elastic-data-warehouse/

[[Snowflake核心技術解讀系列一]架構設計](鏈接地址https://developer.aliyun.com/article/780125?spm=a2c6h.13148508.0.0.e93f4f0etphv6M)

隨時歡迎技術圈的小夥伴們過來交流^_^

AnalyticDB詳情見:產品詳情

AnalyticDB產品試用:產品試用

AnalyticDB知乎公眾號:雲原生數據倉庫

AnalyticDB開發者社區公眾號:雲原生數據倉庫

AnalyticDB開發者釘釘群:23128105

image


Leave a Reply

Your email address will not be published. Required fields are marked *