本篇文章講述了Greenplum如何把一個以AP為主的資料庫打造成HTAP資料庫:
- 全局死鎖檢測;
- 2PC+1PC優化;
- 資源隔離;
由Gartner提出的HTAP資料庫是近年來資料庫領域的一個熱門方向,由HTAP資料庫提供的實時分析能力已經成為企業的核心競争力之一:
- 在TP系統裡增加AP的能力;
- 從NewSQL轉向HTAP;
- 而 Greenplum的論文則展示了如何從AP系統轉向HTAP;
首先分析了對于目前MPP-OLAP在保證ACID時的兩個開銷:restrictive lock和兩階段送出;
Greenplum團隊提出一種全新的全局死鎖檢測來減少獨占鎖的使用。可以極大的提高資料庫在高并發狀态下的性能。
此外對于隻在單節點上的查詢,Greenplum将兩階段送出優化為單階段送出,這樣可以大幅減少原本兩階段送出中的時間和網絡開銷。
為了進一步提高HTAP的性能,Greenplum引入了資源組的概念,使得資料庫可以很好的對OLAP查詢負載和OLTP查詢負載進行對應的資源隔離,提高了整個系統的使用率。
論文中的優化均已應用在了最新版本的Greenplum 中,基于TPC-B和CH-benCHmark資料集進行的測試也顯示出最新版本的Greenplum的OLTP性能有了極大的提升,與此同時之前的OLAP查詢的性能沒有受到任何影響。
摘要
Greenplum在傳統意義上是一個OLAP的資料倉庫,具有有限處理OLTP的能力:
- 瓶頸:restrictive lock和兩階段送出協定;
- TP與AP之間的資源競争;
1. Introduction
Greenplum是資料倉庫系統,有企業版和開源版本的實作。把資料分割成不相交的部分以存放在share nothing的segment server上。和其他大規模資料倉庫系統比較類似,比如Oracle Exadata, Teradata, 以及Vertica,包括DWaaS系統(AWS Redshift, AnalyticDB和BigQuery)。這些資料倉庫系統能夠有效地管理并查詢PB級的資料。
而分布式TP資料庫(如CockroachDB, Amazon RDS)則主要專注于為TB級提供可擴充的存儲和事務查詢。
Greenplum的使用者通過一個協調者跟資料倉庫系統打交道,底層的分布式結構對使用者來說是透明的。對于一個給定的查詢,協調者将其優化以作并行查詢,并将生成的查詢計劃分發給執行查詢的segment server。每個segment server以并行的方式執行查詢,并在需要時在segment server之間shuffles tuples。協調者聚集查詢結果并傳回給使用者。
DML修改存放在segment server上的資料。原子性是通過二階段送出協定來保障。分布式快照用來隔離并發事務。Greenplum通過一系列壓縮算法支援列存(Column-oriented),這些列存表格很适合OLAP負載中的大範圍讀和讀操作。
圖1給出了一個典型的資料處理工作流,這個資料通過ETL子產品周期性地被轉換,并被加載到資料倉庫中以作後期的分析使用。使用者更希望有一個可以同時滿足OLAP和OLTP查詢負載的單一系統。換句話說,這樣的系統需要支援對點查詢和分析查詢。這個需求在相關文獻中被稱為混合事務和分析處理(HTAP)系統。

為滿足Greenplum企業使用者的需求,提出了增強版的HTAP Greenplum,專注于以下問題:
- 改進并行資料加載,使其具備ACID;
- 降低執行OLTP點查詢的響應時間;
- 資源組,隔離不同負載或使用者組之間的資源。
Greenplum設計的初衷是将OLAP查詢作為一等公民,而OLTP負載不是其主要焦點。兩階段送出會對僅更新幾個元組的事務造成性能損失。協調者上執行的比較重量的鎖(heavy locking)旨在防止分布式死鎖,但過于嚴格,影響了點查。
如圖2,一個耗時10s、占用少量連接配接的查詢來講,鎖執行時間超過25%。當并發超過100時,鎖機制消耗的時間将變得無法接受。
增強版的HTAP Greenplum:
- 分析并找出了将OLAP轉換為HTAP面臨的挑戰;
- 提出全局鎖檢測器來降低鎖引起的開銷,提高OLTP的響應時間,與此同時不會犧牲OLAP的性能;
- 通過轉換為一階段送出協定,加速僅需在某個segment server上執行的事務;
- 一個新的資源隔離子產品,用以管理OLTP和OLAP負載,避免資源競争;
- 執行全面的性能評估。實驗結果表明HTAP版本的Greenplum跟傳統OLTP資料庫性能相當;同時仍然能夠為高并發和混合的負載提供實時計算的能力。
2. Related Work
- HTAP 系統:與純粹的OLAP或OLTP系統相比,HTAP系統帶來了=以下好處:1)HTAP能夠減少資料分析任務的等待時間,因為沒有ETL傳輸時延。無需額外的系統或外部組間即可進行實時資料分析。2)HTAP系統還可以降低硬體和管理方面的成本。許多商用OLTP DBMS轉向類HTAP。但是,在商用OLAP中對OLTP負載的支援仍沒有實作。随着HTAP概念的流行,越來越多的資料庫系統正在支援HTAP功能。Ozcan等人将HTAP資料庫分為兩類:single systems for OLTP&OLAP 以及seperated OLTP&OLAP systems。将讨論HTAP資料庫的不同演化路徑。
- 從OLTP到HTAP:OLTP支援高并發性和低延時的事務型處理。Oracle Exadata可同時執行OLTP負載和分析處理。Exadata引入了智能擴充存儲、RDMA和infiniBand網絡以及NVMe閃存來提高HTAP性能。最近,它支援帶有記憶體列存(column-level checksum with in-memory column cache)和智能OLTP緩存等功能,減少閃存磁盤故障或更換的影響。Aurora是一個基于AWS的雲OLTP資料庫,将繁重的日志處了解除安裝到存儲層。為了支援OLAP負載,Aurora支援并行查詢,将單個查詢的計算下推到數千個CPU的存儲層。使分析查詢加快兩個數量級。
- 從NewSQL到HTAP:自從Google Spanner以來,具有擴充性和強ACID保證的NewSQL資料庫克服了NoSQL在擴充性和強ACID保證方面的缺陷。早期NewSQL資料庫的實作,如CockroachDB、TiDB和F1,基于Paxos或Raft等共識協定,以支援分布式OLTP。最近,幾個NewSQL資料庫聲稱自己已變成了HTAP資料庫。其中,TiDB引入了TiFlush來處理OLAP工作負載。它對Raft進行擴充,将資料以異步形式複制到Raft“Learner”中,并将行存轉成列存以服務于OLAP工作負載。類似地,傳統的資料庫(例如Vertica)同樣使用write-optimized stores(WOS, 寫優化存儲)來處理插入、更新和删除查詢。然後将WOS異步轉換為ROS,以處理OLAP工作負載。F1 lighting提供“HTAP即服務”。在谷歌,Lighting被用來從OLTP資料庫(如SPanner和F1)中拷貝資料,并将這些資料轉換成列形式,以處理OLAP負載。與TiFlash不同,Lighting提供了與OLTP資料庫的快照隔離(此處應該是作者了解有誤,TiFlash也是快照隔離)。
Greenplum提供了另一種進化成HTAP資料庫的途徑。其在傳統的OLAP資料庫上增加了OLTP功能,并且支援細粒度的資源隔離。
3. GreenPlum’s MPP Architecture
Greenplum基于MPP架構,建構了一個資料庫叢集。運作中的Greenplum叢集由多個正在運作的worker segments組成,可以視為增強版的PostgreSQL,圖3顯示了整個架構。
接下來,介紹Greenplum MPP架構的幾個重要子產品和設計。這些概念對于了解Greenplum的HTAP改進至關重要。
3.1 Roles and Responsibility of Segments
一個Greenplum叢集由很多跨主機的segments組成。有一個segment server稱為協調者,其他的稱為segment server。協調者直接連接配接到使用者用戶端。協調者接收來自客戶的指令或查詢,生成分布式查詢計劃,根據計劃生成分布式程序,将其配置設定到每個程序,收集結果,并最終發送回用戶端。
segment server存儲資料,并從協調者處執行分布式計劃的子樹。為了高可用性,segment server可被配置為鏡像節點。鏡像不會直接參與計算。相反,他們會連續地從相應的主segment server接收WAL日志并回放日志。
Greenplum是無共享的架構,協調者和segment server都有它們自己的共享記憶體和資料目錄。協調者僅通過網絡與segment server進行通信。
3.2 分布式查詢和分布式執行器
通常,對于分布式表來說,每個segment server僅存儲整個資料的一小部分。當對兩個表進行join時,通常需要檢查來自不同的segment server的兩個元組是否符合join的條件。這意味着Greenplum必須在segment server之間移動資料,以保證所有可能比對的元組在同一個segment server中。Greenplum中引入一個算子來實作這樣的資料移動,稱作Motion。
Motion算子通過網絡從不同的segment server發送和接收資料。Motion算子将計劃切成slice,Motion下面或上面的每一個slice都被稱為Greenplum切片。每個切片由一組分布式程序執行,這組程序稱為gang。
有了上述的Motion算子和gang,Greenplum的查詢計劃以及執行器就變成了分布式的。計劃會被分發到每一個程序,根據程序的上下文狀态,每一個程序執行自己的計劃切片以完成查詢的執行。執行是單程式多資料技術:将相同的計劃配置設定給跨叢集的程序組,由不同segment server生成不同的程序,都有自己的本地上下文、狀态和資料。
下面使用一個例子來說明上述概念。圖4的頂部是一個join的分布式計劃樹,底部是在具有兩個segment server的叢集中的執行過程。頂部slice由協調者上的單個程序執行,其他slice在segment server上執行。一個slice掃描表,然後通過redistributed Motion将元組發送出去。另一個執行hash join的slice将從Motion節點接收元組,掃描學生表,建構hashtable,計算hashjoin,最後将元組發送到頂部slice。
3.3 分布式事務管理
在一個Greenplum叢集中,每個segment server運作着一個增強版的PostgreSQL執行個體,并且事務在每個segment server中同步地送出或終止。為了確定ACID屬性,Greenplum使用分布式快照和兩階段送出協定。分布式事務管理的性能對于增強Greenplum作為一個可行的HTAP系統至關重要。詳情将在第5章進行讨論。
3.4 混合存儲與優化
Greenplu支援PostgreSQL原生的heap表(heap tables),heap表是行存儲,在segment server上共享bufferpool,以友善并發讀寫操作。
Greenplum中引入了兩種新的表類型:
- Append Optimized的行存儲(AO行);
- Append Optimized的列存儲(AO列);
AO表支援批量I/O,而不是随機通路,這使得它們更适合AP的工作負載。在AO清單中,為每列配置設定一個單獨的檔案。進一步減少從一個大表中僅選擇幾列的I/O。AO表可用各種算法進行壓縮,如zstd、quicklz和zlib。在AO清單中,每一個列都可以使用特定的算法進行壓縮,包括帶有增量壓縮的運作長度編碼(run-length-encoding, RLE)。Greenplum中的查詢執行引擎不感覺表的存儲類型。AO行、AO列和heap表可以在同一查詢中被join。
表可以按使用者指定的關鍵字和分區政策(list、range)進行分區。這是通過在根表下面建立一個表的層次結構來實作的,其中隻有葉子表中包含使用者資料。層次結構中的每個分區都可以是堆、AO行、AO列或外部表。外部表用于讀取/寫存儲在Greenplum以外的資料,例如存儲在 Amazon S3中的資料。
圖5顯示了按銷售日期劃分的銷售表,每個分區由日期範圍定義。最近的分區為heap表(6月至8月)。AO列存儲用于稍舊的銷售資料(9月至12月),而前幾年的銷售資料則存檔在外部表中。可以對銷售表或其單獨的分區進行查詢,無需關心該表的存儲性質。
與存儲一樣,Greenplum中的查詢優化也是靈活的。查詢優化取決于工作負載。分析類的工作負載由包含許多join和aggregates的複雜查詢組成。查詢性能主要由查詢計劃的效率決定。Greenplum的Orca查詢優化器是一個cost-based的優化器,專為OLAP設計。另一方面,TP的工作負載由短查詢組成,這些查詢對查詢計劃延遲很敏感。在生成一個簡單的計劃時,它需要快速的優化器。Greenplum的PostgreSQL内置優化器适用于這類事務型查詢。使用者可以從SQL、會話或資料庫級别,在兩個優化器之間進行選擇。選擇最合适優化器,幫助Greenplum更有效地處理HTAP工作。
4. Object Lock Optimization
本節重點介紹鎖優化,這是Greenplum優化OLTP性能的基石。其核心思想是通過檢測器算法來解決分布式環境中的全局死鎖問題。
4.1 Greenplum中的鎖
鎖在資料庫中被廣泛使用,以防止在不同粒度級别上的競争情況。Greenplum中有三種鎖:spin鎖、LW鎖和對象級别鎖。spin鎖和LW鎖用于保護讀取或寫入共享記憶體的臨界區,并遵循一些規則(例如,以相同的順序取得鎖),來避免死鎖。在操作表、元組或事物等資料庫對象時,對象鎖定會直接影響程序的并發性。在本節中關注對象鎖。
一些對象,比如表,可以由事務并發操作。在通路此類對象時,要以正确的模式上鎖,以保護該對象。
Greenplum采用兩階段鎖:上鎖保持在第一階段,并在送出或中止事務時釋放。從PostgreSQL繼承而來,Greenplum有8種不同級别的鎖模式。更進階别的鎖定模式支援更嚴格的并發控制粒度。所有的鎖模式、沖突模式及對應的典型語句見表1。
作為一個MPP資料庫,Greenplum中的鎖邏輯和算法與PostgreSQL有所不同。PostgreSQL鎖邏輯無法檢測或解決在Greenplum等MPP資料庫中經常遇到的全局死鎖問題,必須增加DML操作的鎖級别,以避免出現此類問題。
在基于PostgreSQL鎖機制的Greenplum中,并發事務的性能非常糟糕:因為一次隻能處理同個表上的一個事務更新或删除。
4.2 全局死鎖問題
在像Greenplum這樣的分布式系統中,在處理全局死鎖時,DML語句(插入、删除和更新)的鎖定級别非常重要。這些DML語句的鎖定行為如下:
- 首先,在解析/分析階段,事務會對表上鎖;
- 其次,在執行過程中,事務會上tuplelock;
在單segment server資料庫中,如PostgreSQL,第一階段通常以RowExclusive模式鎖定目标表,以便它們可以并發運作。隻有當兩個事務恰好寫入(更新或删除)同一進制組時,一個事務才會等待該元組的事務鎖定,直到另一個事務被送出或中止。鎖依賴關系存儲在每個segment server執行個體的共享記憶體中。如果發生死鎖,則很容易掃描共享記憶體中的鎖資訊。
這種方法在Greenplum的分布式架構中是不夠的。即使Greenplum叢集中的每個segment server都是具有本地死鎖處理程式的增強PostgreSQL執行個體,如果等待行為跨越不同的segment server發生,無法避免全局死鎖。
如圖6所示:
- 事務A更新存儲在segment server0中的一個元組,并持有segment server0上的一個tuplelock;
- 事務B更新存儲在segment server1中的一個元組,它保持在segment server1上的一個tuplelock。直到現在,一切都很順利,沒有等待的情況發生;
- 事務B更新segment server0上事務A剛剛更新的相同元組,因為事務A尚未送出或中止,事務B必須等待。事務A工作正常,正在等待下一個語句;
- 事務A更新被事務B鎖定的segment server1上的元組,是以它也必須等待;
- 現在,在segment server0上,事務B等待事務A,在segment server1上,事務A等待事務B。每個PostgreSQL執行個體都沒有本地死鎖。但導緻全局死鎖。
圖7顯示了一個更加複雜的情況,其中包括協調者在内的所有segment server都涉及全局死鎖。下面的順序号與圖7中的順序号一緻。
- 事務A通過更新語句鎖定segment server0上的c1=2的表t1;
- 事務B通過更新語句鎖定segment server1上的c1=1的表t1;
- 事務C通過LOCK語句鎖定協調者上的表t2,以及所有的segment server;
- 事務C嘗試擷取segment server0上c1=2的相關元組鎖,但該元組已被事務A鎖定,是以事務C等待;
- 事務A試圖鎖定segment server1上的c1=1的表,但segment server1已被事務B鎖定,是以事務A等待;
- 事務D通過更新語句鎖定segment server0上c1=3的表t1相關元組;
- 事務D繼續嘗試通過LOCK語句鎖定協調者上的表t2,它将等待,因為事務C持有t2上的鎖;
- 事務B繼續嘗試鎖定與t1相關的c1=3上的元組,該segment server被事務D鎖定,是以事務B也在等待;
- 現在,在segment server1上,事務A等待事務B,在segment server0上,事務B等待事務D,在協調者上,事務D等待事務C,在segment server0,事務C等待事務A,進而發生全局死鎖。
在Greenplum5和以前的所有版本中,在協調者的parse/analyze階段,使用X模式鎖定目标表,是以執行更新或删除的事務實際上是以串行形式運作的;
并且事務鎖定等待不是在segment server上的,而是在協調者節點上的(本地死鎖檢測算法),這就避免了全局死鎖。但是,該方法會導緻OLTP性能不佳,因為它不允許并發地寫入同一個表,即使這兩個事務實際上更新了不同的元組。
4.3 全局死鎖檢測算法
為了解決全局死鎖問題,提出了一種檢測機制,作為Greenplum 6的一部分。全局死鎖檢測算法(簡稱GDD)的工作流程如下:
- Greenplum在協調者上啟動一個守護程序;
- 守護程序定期收集每個segment server上的Wait-for圖;
- 守護程序檢查是否發生全局死鎖;
- 守護程序使用預定義的政策終止全局死鎖,例如終止最年輕的事務;
GDD守護程序收集每個segment server的本地wait-for(包括協調者),并建構一個全局wait-for。每個頂點表示一個事務,并且邊是從等待事務開始指向持有鎖的事務。對于表示事務的每個頂點,其輸出邊的數量是頂點的出度,其輸入邊的數量是頂點的入度。
頂點的局部度:是其僅在某單個segment server的wait-for中計算的值;
頂點的全局度:是所有segment server的所有局部度的總和。
使用
來表示頂點V的全局出度,degi(V)表示頂點V在segment server-i上的局部出度。舉個例子,在圖7中,deg(G)(C) = 1,因為在事務C僅在segment server0上對C有依賴,并且deg-1(C)=0,因為在segment server1上事務C沒有出度。
需要強調的是,從每個segment server收集的等待資訊是異步的,并且在協調者中分析時,不能忽略延時。GDD算法中最重要的思想是貪婪規則。該算法不斷删除等待邊緣,當無法删除等待邊時,如果存在剩餘等待邊,則會發生全局死鎖。在這種情況下,檢測器守護程序将鎖定協調者中的所有程序,檢查剩下的邊是否仍然有效。如果某些事務已完成(已中止或已送出),GDD守護程序隻需丢棄本輪檢測所有資訊,并在下次運作中繼續執行全局死鎖檢測。請注意,運作作業的周期是Greenplum的可配置參數,以滿足各種業務需求。
在全局wait-for中有兩個不同的等待邊符号:
- 實邊:隻有在持有鎖的事務結束(已送出或中止)後,Wait-for才會消失。一個典型情況是在更新或删除語句中對目标表上鎖,該鎖隻能在事務結束時才會被釋放。隻有當持有鎖的事務不會在任何地方被阻塞時,這樣的邊才能被删除,因為基于貪婪規則,可以假設持有鎖的事務會結束并釋放它所持有的所有鎖;
- 虛邊:表示持有鎖的事務,即使不結束事務,也可以釋放其所持有的鎖。例如,在修改元組的内容時持有的tuplelock。隻有當特定segment server中的其他人沒有阻塞持有鎖的事務時,才能删除這樣的邊。這是基于貪婪的規則,可以假設持有鎖的事務将釋放阻塞等待事務的鎖,而不送出或中止。
完整的GDD算法如算法1所示。在每輪循環中:
- 首先将全局出度為0的頂點對應的輸入邊删除掉(沒有任何事務依賴,是以可以直接删除掉);
- 然後掃描每一個局部wait-for,并将局部出度為0的點所對應的輸入虛邊删除掉(虛變代表事務依賴本地tuple lock,而它鎖依賴的事務并沒有local出度,說明該依賴關系可以在事務執行完之前執行完,是以可以删除掉);
GDD是一個貪心算法,換句話說,如果有可能讓持有鎖的事務繼續運作,總是假設它們最終會把其所持有的鎖釋放掉。
GDD in Action
下面使用GDD算法來分析幾個實際例子。
對圖6中提到的死鎖而言,從它的wait-for中可以看出,沒有全局出度為0的頂點,是以第一輪循環中沒有邊被删除掉;同時在每個segment server上都不存在虛邊,是以第二輪也沒有邊被删除。原始wait-for即為最終狀态,其中含有一個全局的環,意味着發生了全局死鎖。
圖8描述了另一種情況。語句的執行過程按時間順序如下:
- 事務A通過Update語句,對segment server0上表t1中c1=3的元組上鎖;
- 事務C通過Update語句,對segment server1上表t1中的c1=1的元組上鎖;
- 事務B嘗試給表t1上c1=1,或c2=3的元組上鎖,它将被segment server0上的事務A和segment server1上的事務C阻塞();
- 事務A嘗試給segment server1中t1上c1=1的元組上鎖,它将被segment server1上的事務B所有持有的tupelock阻塞;
圖8中,GDD算法的執行過程可通過圖9進行描述,具體如下:
- 圖9.a中,deg(G)(C) = 0(即源wait-for),基于GDD算法,可以把頂點C以及所有指向C的邊删除,執行這一步操作後,可以得到圖9.b;
- 圖9.b中沒有頂點滿足deg(G)(V)=0了,接着檢查本地wait-for中頂點的出度,可以發現deg1(B) = 0,基于GDD算法可以把segment server1上所有指向B的虛邊都删除掉,執行完後可以得到圖9.c;
- 接下來在圖9.c中,發現deg(G)(A)=0,是以所有指向A的邊都會被删除掉,這步操作之後可以得到圖9.d;
- 最後沒有邊剩下,是以GDD算法将輸出該情況下未産生死鎖。
《Greenplum: A Hybrid Database for Transactional and Analytical Workloads》摘要1. Introduction2. Related Work3. GreenPlum’s MPP Architecture4. Object Lock Optimization6. Resource Isolation7. Performance Evaluation8. Conclusion
GDD Correctness
GDD依賴最終的狀态屬性,如下所示:
- 如果圖中沒有邊能夠被删除,那麼圖就不會再更新了;
- 所有的事務仍然存在;
根據性質1和性質2,可以得出結論:最終的等待邊是最新的了。基于邊删除政策,如果最終wait-for中包含環,那麼會導緻全局死鎖。如果全局死鎖發生了,基于定義,全局wait-for必須包含一個環,而且在圖中的事務都不能更進一步地執行了。GDD算法不能移除任何邊并且會彙報一個全局死鎖。是以,證明GDD算法是完備的。
GDD Overhead
啟動GDD後,UPDATE和INSERT操作的鎖定級别會降級。是以,在同一個表上執行更新和删除的事務可以并行執行。
GDD守護程序僅僅周期性地執行一個簡單的調用,從各個segment server上拉去wait-for,是以它并不會在叢集上消耗太多的資源。
5. 分布式事務
Greenplum中的事務是由協調者建立并分發到segment server上。協調者為每一個事務配置設定一個單調遞增的整數,作為分布式事務id。
而segment server給每個從協調者那裡獲得的分布式事務配置設定一個本地事務标id:使用原生的PG事務機制來生成本地事務标id。
分布式事務id惟一的辨別了全局級别上的事務。而本地事務标id唯一辨別某個segment server上的事務。
segment server使用PG原生快照機制來生成本地快照。
協調者:建立分布式事務、建立分布式快照以及在參與segment server之間協調兩階段送出協定。
5.1 分布式事務隔離
Greenplum增加了分布式快照,處理分布式環境下的事務隔離。元組的可見性是由本地和分布式快照共同決定的。
接下來,讓考慮在segment server上對元組執行DML操作。對一個給定的事務,當修改一個元組時,為這個元組建立一個新的版本并且打上局部事務标id。對每個元組,也維護一個從局部事務标id至全局事務标id的映射。結合該分布式事務标id以及分布式快照(有協調者提供),掃描算子決定元組的可見性。
将本地事務标id映射到分布式事務标id所産生的開銷非常大。為了減少這項開銷,僅維護至最大的分布式事務标id,其可能被任何分布式快照認為正在執行。
segment server使用這個邏輯來頻繁地截斷映射的中繼資料。如果查找不到映射,一個segment server結合本地事務标id和本地快照來決定元組的可見性。
5.2 一階段送出協定
協調者使用兩階段送出來保證事務要麼在所有segment server上都被送出或都被中止。
協調者建立一個後端程序來處理使用者的連接配接。後端程序參與segment server之間初始化兩階段送出協定,來接收使用者的commit請求。
兩階段送出的優化就是縮短commit過程,使得鎖釋放得更快,進而提升并發度。
一階段送出是針對僅在同一個segment server上更新資料的事務執行的優化。
圖10展示了一階段送出的好處。協調者能夠決定一個寫操作僅發生在一個segment server上。如果上述條件成立,協調者将跳過PREPARE階段,把Commit指令分發至參與segment server上。一階段送出節省了一個網絡來回的PREPARE消息,和檔案系統同步操作:
- segment server上的PREPARE;
- 協調者上的COMMIT;
讓看看資料一緻性是如何不受一階段送出優化所影響的:
- 一階段送出事務由協調者配置設定分布式事務标id和分布式快照;
- 在參與的segment server節點上,元組版本被一階段送出事務建立出來,并打上本地事務标id;
- segment server記住本地和分布式事務标id之間的映射,就像兩階段送出事務那樣;
- 目前一階段送出事務和此時取到的分布式快照是并發的關系,直到協調者從參與segment server接收到“Commit OK”認可;
- 在這之後,一階段送出事務在新建立的分布式快照中以Committed狀态出現;
- 簡單而言,一階段送出優化使用與兩階段送出事務一樣的機制來維護資料庫的一緻性;
- 是以,一階段送出對OLTP負載中單執行個體的insert, update和delete操作來說是正确且有效的。
《Greenplum: A Hybrid Database for Transactional and Analytical Workloads》摘要1. Introduction2. Related Work3. GreenPlum’s MPP Architecture4. Object Lock Optimization6. Resource Isolation7. Performance Evaluation8. Conclusion
在上述例子中,所有10個元組都在列c1上具有相同分布鍵1。所有的元組都将被發送至hash值為1的segment server,一階段送出優化。
5.3 其他優化
最後一個Query和Prepared/Commit消息合并。
6. Resource Isolation
如何在高并發、混合工作負載中減輕資源競争造成的性能下降是一個具有挑戰性的問題。在本節中,将讨論Greenplum如何為HTAP工作負載隔離和排程資源,如CPU和記憶體。
當分析型工作負載和事務型工作負載同時運作時,分析型的工作負載會對事務型工作負載産生重大影響。通常,分析型的工作負載會消耗大量的CPU、記憶體和IO帶寬,這将占用事務型工作負載的資源,并導緻事務型查詢被延遲。
為了減少幹擾,Greenplum引入了資源組,以在不同類型的工作負載或使用者組之間隔離資源。目前,資源組支援使用不同的方式隔離計算資源和記憶體資源。
CPU隔離是基于cgroup技術實作的。Cgroup是一個Linux核心功能,它限制和隔離程序組的資源使用情況。從Cgroup樹結構的角度來看,一個資源組被實作為一個内部節點,并且屬于該資源組的所有程序都是子節點。
有兩種方式為每個資源組的程序配置設定CPU的使用情況。其中一個是cpu.shares,它控制着CPU的使用百分比或者優先級;另一個是cpuset.cpus,指定了該資源組的CPU核數。
第一種配置是軟控制:如果沒有并發的工作負載,資源組中的程序可以使用超過指定限額的CPU資源;第二個配置則是硬控制,嚴格限制了一個資源組中最多能使用的CPU核數。
在Greenplum中,記憶體隔離是通過基于記憶體管理子產品Vmemtracker實作的。Vmemtracker負責跟蹤Greenplum資料庫核心的記憶體使用情況。Greenplum使用該特性來控制不同資源組之間的記憶體使用。
不像CPU,記憶體是一個硬體資源,并且一旦配置設定就不能立馬收回。當一個資源組的記憶體使用超過了限制,該組内的查詢将被取消。
但是在實際的工作負載中,想要控制顯式記憶體的使用情況,并不是一件容易的事。如:很難獲得一個hash表的顯式記憶體的大小。
為了使記憶體資源執行得更加健壯,資源組引入了三個層次來管理記憶體使用情況:
- slot memory:控制單個查詢的記憶體使用情況,計算公式是組非共享記憶體除以并發數;
- shared memory:在同一資源組中的查詢超過slot memory時使用該層,組共享記憶體可以由參數MEMORY_SHARED_QUOTA為每個資源組設定;
- global shared memory:不同組間記憶體使用量的最後守護者,隻有當這三層都不能限制查詢記憶體時,才會使用查詢取消機制。
可以使用以下文法建立資源組:
要隔離不同使用者組之間的資源,DBA可以使用“ALTER ROLE”或“CREATE ROLE”指令将資源組配置設定給一個角色。例如:
上面所示兩個資源組:
- 一個專門用于分析型工作負載;
- 另一個專門用于事務型工作負載;
對于CPU資源,為事務型資源組配置設定更多的CPU速率限制,因為事務型查詢很短,而且對查詢延遲很敏感。通過将CPU資源優先配置設定給事務型資源組,希望當長時間執行的查詢并發執行時,能夠減輕對短時間運作query的延遲和TPS影響。
對于記憶體資源,為分析資源組配置設定更高的記憶體限制,以允許分析查詢使用更多的記憶體,并避免過度的spill磁盤。相反,事務型查詢的記憶體使用量通常很低。
并發性是資源組的另一參數,它控制最大連接配接數量。事務型工作負載通常涉及到更高的并發性。
另一方面,分析類的工作負載需要對并發性的細粒度控制。如前所述,記憶體不能立即回收,這将使每個查詢使用的記憶體量變小,進而在并發限制設定為太大時,導緻更頻繁的spill磁盤。這是并發性和性能之間的權衡。在未來,計劃引入一個工作負載預測子產品,它允許負載不大時,即使當資源組的并發數設定為很大時,仍然可以使用更多的記憶體。
未來的工作。除了CPU和記憶體隔離外,磁盤IO和網絡IO隔離對于混合工作負載也至關重要。與PG和其他資料庫系統類似,Greenplum中的後端程序會更改共享記憶體緩沖池中的頁面,髒頁面通過背景程序異步刷到磁盤中。是以,很難将磁盤IO從greenplum叢集中的不同程序中分離出來。然而,發現,對于許多工作負載,磁盤IO和網絡IO的使用情況與CPU的使用情況有關。是以,限制CPU的使用也可以限制磁盤和網絡IO的使用。計劃在未來探索如何隔離磁盤和網絡IO。
7. Performance Evaluation
7.1 測試環境
在8個主機的叢集上進行了實驗(其中每個主機分别有4個片segment server)。網絡是10Gbps的以太網絡。每個節點有32個IntelXeon CPU核心(2.2GHZ)、120GB RAM和500GB SSD。
本文讨論的HTAP優化在Greenplum 6.0中實作。為了驗證方法的有效性,比較了GPDB6和Greenplum 5.0(實驗基線)的性能。
7.2 OLTP性能
以前的Greenplum版本是傳統的資料倉庫,由于資料的批量處理,使得它的事務處理能力和資料分析延遲低。從Greenplum 6開始,其引入了全局死鎖檢測器、單階段送出和資源組(本文的核心貢獻)等許多特性,以提高整體的OLTP性能。Greenplum繼續迎合大資料分析市場,這使得Greenplum能夠将分析型、深度學習、報表和專門的查詢(ad-hoc queries)視為一等的公民。相比之下,CockroachDB和TiDB等HTAP系統主要關注對TB級别資料的事務型查詢,并試圖減少執行分析的時間。雖然它們的分析查詢得到了改進,但不能像Greenplum這樣查詢PB級别的資料。
為了更好地了解Greenplum 6中的事務處理優化,使用TPC-B基準測試來評估OLTP的性能。比較了GPDB6、GPDB5和PG的性能。
結果顯示,與GPDB5相比,GPDB6每秒可以多處理80倍的事務,如圖12所示。這些改進與第4節和第5節中讨論的優化直接相關。一開始,TPS中的吞吐量随着用戶端的數量呈線性增長。超過100個用戶端時,吞吐量的增長減少了,最後在600個用戶端時,吞吐量開始下降。
的分析表明,這個下降是由于轉向了LWLock的瓶頸引起的,這将在Greenplum的後續版本中得到解決。
還比較了GPDB6和PG 9.4的性能。使用pgbench來生成具有不同尺度因子的資料。比例因子1K對應于14GB資料,10K對應于143GB資料,100K對應于1.4TB資料。圖13顯示,當資料規模比較小時,PG在TPS中的吞吐量高于GPDB6。随着資料大小的增加,PG吞吐量急劇下降,而Greenplum吞吐量保持穩定。這是一個令人鼓舞的證據,表明Greenplum能夠持續提高OLTP。
下面研究針對OLTP工作負載的單個優化對性能的影響。為了評估全局死鎖檢測器的影響,使用了update-only的工作負載。圖14顯示,GPDB6的TPS高于12000,大概是GPDB5的TPS的100倍。原因是GPDB5必須序列化在同一表上的更新操作,而全局死鎖檢測器允許GPDB6對同一張表進行并發更新。
為了更好地研究單階段送出優化的影響,分析了insert-only工作負載的性能。此工作負載的每個插入語句涉及的值都映射到了同一個segment server。單階段送出優化可以應用于此類事務。
圖15中的結果顯示,GPDB6每秒處理的事務量是GPDB5的5倍。原因是單階段送出協定不僅能降低協調者和segment server之間的通信開銷,也可以消除實際上沒有插入任何元組的segment server上不必要的CPU成本。除了單階段送出協定之外,Insert-only的查詢也受益于事務管理器優化,這反過來又降低了LWLock的開銷。
考慮到協調者經常成為Greenplum的OLTP性能瓶頸。在未來,計劃增加具有分布式事務的hot standby和multi-master。
7.3 HTAP性能
為了評估Greenplum在HTAP工作負載上的性能,使用HTAP基準測試CH-benCHmark進行了一個實驗。CH-benCHmark是一個混合基準,它由TPC-H OLAP基準和TPC-C OLTP基準組成。在的實驗中,OLAP工作負載和OLTP工作負載同時運作,并且設定了不同的用戶端數目和資源組配置。
接下來,比較了GPDB5和GPDB6之間的HTAP性能。圖16顯示了在不同OLAP用戶端數目和兩個固定的OLTP客戶數目(0和100)的情況下OLAP工作負載的QPH(queries per hour)。本實驗展示了OLTP工作負載對OLAP工作負載的影響。結果表明,在GPDB6中,OLAP的QPH性能下降了超過2倍,但在GPDB5中沒有顯著差異。這是因為GPDB5中的每分鐘OLTP查詢(QPM)太小,無法搶占OLAP工作負載的資源。
為了更好地評估OLAP工作負載對OLTP工作負載的影響,比較在不同OLTP用戶端數和兩個固定的OLAP用戶端數目(0和20)情況下,OLTP工作負載的QPM數目。圖17中顯示,GPDB6上的OLTP性能降低了3倍,而GPDB5上沒有差異,因為QPM數量受到鎖沖突而不是系統資源的限制。上述兩個實驗也證明了HTAP能力的顯著改進。GPDB6能夠處理1萬個OLTP查詢,并同時執行複雜的專門查詢。
上述實驗表明,OLAP和OLTP工作負載在并發運作時将搶占系統資源。為了展示Greenplum的資源隔離能力,建立了兩個資源組,一個用于OLAP工作負載,另一個用于OLTP工作負載。資源組的配置因CPU優先級而異。下面列出了三種不同的配置:
- 配置I均勻地配置設定了CPU,具有相同的CPU速度限制;
- 配置II将32個CPU中的4個配置設定給OLTP資源組;
- 配置III将32個CPU中的16個配置設定給OLTP資源組。
下面實驗評估了當OLTP工作負載與固定數量的OLAP并發性(20)同時運作時對OLTP工作負載的性能影響,并使用上述不同的資源組配置。
圖18中的結果顯示,當通過CPU隔離将特定的CPU配置設定給OLTP資源組時,OLTP工作負載的延遲就減少了。資源組能夠靈活地調整HTAP工作負載的資源配置設定和查詢性能。
8. Conclusion
論述了如何将分布式資料倉庫轉換為一個可以同時滿足OLAP和OLTP工作負載的HTAP系統。正如在兩階段送出和鎖看到的那樣,OLAP工作負載的設計對于OLTP工作負載的設是非常昂貴的。
對于短的OLTP查詢來說,看似無關緊要的開銷變得相當重要了。的新方法在不犧牲性能和ACID的情況下減少了這種開銷。
詳細的性能分析表明,全局死鎖檢測器和單階段送出協定顯著提高了Greenplum對OLTP工作負載的性能。
Greenplum通過資源組限制CPU和記憶體,能夠在單個系統中同時運作OLTP和OLAP工作負載。
Greenplum後續會有更多功能使得分析查詢系統能夠與專門的OLTP(如PG)相媲美。