導讀:隨着數據量的快速增加,愈來愈多的企業迎來業務數據化時代,數據成爲了最重要的生產資料和業務升級依據。本文由阿里AnalyticDB團隊出品,近萬字長文,首次深度解讀阿里在海量數據實時分析領域的多項核心技術。java
數字經濟時代已經來臨,但願能和業界同行共同探索,加速行業數字化升級,服務更多中小企業和消費者。算法
隨着數據量的快速增加,愈來愈多的企業迎來業務數據化時代,數據成爲了最重要的生產資料和業務升級依據。伴隨着業務對海量數據實時分析的需求愈來愈多,數據分析技術這兩年也迎來了一些新的挑戰和變革:數據庫
在線化和高可用,離線和在線的邊界愈來愈模糊,一切數據皆服務化、一切分析皆在線化。數組
高併發低延時,愈來愈多的數據系統直接服務終端客戶,對系統的併發和處理延時提出了新的交互性挑戰。緩存
混合負載, 一套實時分析系統既要支持數據加工處理,又要支持高併發低延時的交互式查詢。性能優化
融合分析, 隨着對數據新的使用方式探索,須要解決結構化與非結構化數據融合場景下的數據檢索和分析問題。網絡
阿里巴巴最初經過單節點Oracle進行準實時分析, 後來轉到Oracle RAC,隨着業務的飛速發展, 集中式的Shared Storage架構須要快速轉向分佈式,遷移到了Greenplum,但不到一年時間便遇到擴展性和併發的嚴重瓶頸。爲了迎接更大數據集、更高併發、更高可用、更實時的數據應用發展趨勢,從2011年開始,在線分析這個技術領域,阿里實時數倉堅決的走上了自研之路。多線程
分析型數據庫AnalyticDB架構
AnalyticDB是阿里巴巴自主研發、惟一通過超大規模以及核心業務驗證的PB級實時數據倉庫。自2012年第一次在集團發佈上線以來,至今已累計迭代發佈近百個版本,支撐起集團內的電商、廣告、菜鳥、文娛、飛豬等衆多在線分析業務。併發
AnalyticDB於2014年在阿里雲開始正式對外輸出,支撐行業既包括傳統的大中型企業和政府機構,也包括衆多的互聯網公司,覆蓋外部十幾個行業。AnalyticDB承接着阿里巴巴廣告營銷、商家數據服務、菜鳥物流、盒馬新零售等衆多核心業務的高併發分析處理, 每一年雙十一上述衆多實時分析業務高峯驅動着AnalyticDB不斷的架構演進和技術創新。
通過這2年的演進和創新,AnalyticDB已經成長爲兼容MySQL 5.x系列、並在此基礎上加強支持ANSI SQL:2003的OLAP標準(如window function)的通用實時數倉,躋身爲實時數倉領域極具行業競爭力的產品。近期,AnalyticDB成功入選了全球權威IT諮詢機構Forrester發佈"The Forrester Wave™: CloudData Warehouse,Q4 2018"研究報告的Contenders象限,以及Gartner發佈的分析型數據管理平臺報告 (Magic Quadrant forData Management Solutions for Analytics),開始進入全球分析市場。AnalyticDB旨在幫客戶將整個數據分析和價值化從傳統的離線分析帶到下一代的在線實時分析模式。
通過過去2年的架構演進和功能迭代,AnalyticDB當前總體架構以下圖。
AnalyticDB是一個支持多租戶的Cloud Native Realtime Data Warehouse平臺,每一個租戶DB的資源隔離,每一個DB都有相應獨立的模塊(圖中的Front Node, Compute Node, Buffer Node),在處理實時寫入和查詢時,這些模塊都是資源(CPU, Memory)使用密集型的服務,須要進行DB間隔離保證服務質量。同時從功能完整性和成本優化層面考慮,又有一系列集羣級別服務(圖中綠色部分模塊)。
下面是對每一個模塊的具體描述:
DB級別服務組件:
Front Node:負責JDBC, ODBC協議層接入,認證和鑑權,SQL解析、重寫;分區地址路由和版本管理;同時優化器,執行計劃和MPP計算的調度模塊也在Front Node。
Compute Node: 包含MPP計算Worker模塊,和存儲模塊(行列混存,元數據,索引)。
Buffer Node: 負責實時寫入,並根據實時數據大小觸發索引構建和合並。
集羣級別服務組件:
Management Console: 管理控制檯。
Admin Service:集羣管控服務,負責計量計費,實例生命週期管理等商業化功能,同時提供OpenAPI和InnerAPI給Management Console和第三方調用。
Global Meta Service:全局元數據管理,提供每一個DB的元數據管理服務,同時提供分區分配,副本管理,版本管理,分佈式DDL等能力。
Job Service:做業服務,提供異步做業調度能力。異步做業包括索引構建、擴容、無縫升級、刪庫刪表的後臺異步數據清理等。
Connector Service:數據源鏈接服務,負責外部各數據源(圖中右側部分)接入到AnalyticDB。目前該服務開發基本完成,即將上線提供雲服務。
Monitoring & Alerting Service:監控告警診斷服務,既提供面向內部人員的運維監控告警診斷平臺,又做爲數據源經過Management Console面向用戶側提供數據庫監控服務。
Resource Management Service:資源管理服務,負責集羣級別和DB級別服務的建立、刪除、DNS/SLB掛載/卸載、擴縮容、升降配,無縫升級、服務發現、服務健康檢查與恢復。
AnalyticDB中表組(Table Group)分爲兩類:事實表組和維度表組。
事實表組(Fact Table Group),表組在AnalyticDB裏是一個邏輯概念,用戶能夠將業務上關聯性比較多的事實表放在同一個事實表組下,主要是爲了方便客戶作衆多數據業務表的管理,同時還能夠加速Co-location Join計算。
維度表組(Dimension Table Group),用於存放維度表,目前有且僅有一個,在數據庫創建時會自動建立,維度表特徵上是一種數據量較小可是須要和事實表進行潛在關聯的表。
AnalyticDB中表分爲事實表(Fact Table)和維度表(Dimension Table)。
事實表建立時至少要指定Hash分區列和相關分區信息,而且指定存放在一個表組中,同時支持List二級分區。
Hash Partition將數據按照分區列進行hash分區,hash分區被分佈到多個Compute Node中。
List Partition(若是指定List分區列的話)對一個hash分區進行再分區,通常按照時間(如天天一個list分區)。
一個Hash Partition的全部List Partition默認存放於同一個Compute Node中。每一個Hash Partition配有多個副本(一般爲雙副本),分佈在不一樣的Compute Node中,作到高可用和高併發。
維度表能夠和任意表組的任意表進行關聯,而且建立時不須要配置分區信息,可是對單表數據量大小有所限制,而且須要消耗更多的存儲資源,會被存儲在每一個屬於該DB的Compute Node中。
下圖描述了從Database到List分區到數據模型:
對於Compute Node 來講,事實表的每一個List分區是一個物理存儲單元(若是沒有指定List分區列,可認爲該Hash分區只有一個List分區)。一個分區物理存儲單元採用行列混存模式,配合元數據和索引,提供高效查詢。
基於上述數據模型,AnalyticDB提供了單庫PB級數據實時分析能力。如下是生產環境的真實數據:
阿里巴巴集團某營銷應用單DB表數超過20000張
雲上某企業客戶單DB數據量近3PB,單日分析查詢次數超過1億
阿里巴巴集團內某單個AnalyticDB集羣超過2000臺節點規模
雲上某業務實時寫入壓力高達1000w TPS
菜鳥網絡某數據業務極度複雜分析場景,查詢QPS 100+
靈活的數據導入導出能力對一個實時數倉來講相當重要,AnalyticDB當前既支持經過阿里雲數據傳輸服務DTS、DataWorks數據集成從各類外部數據源導入入庫,同時也在不斷完善自身的數據導入能力。總體導入導出能力以下圖(其中導入部分數據源當前已支持,部分在開發中,即將發佈)。
首先,因爲AnalyticDB兼容MySQL5.x系列,支持經過MySQL JDBC方式把數據insert入庫。爲了得到最佳寫入性能,AnalyticDB提供了Client SDK,實現分區聚合寫的優化,相比經過JDBC單條insert,寫入性能有10倍以上提高。對於應用端業務邏輯須要直接寫入AnalyticDB的場景,推薦使用AnalyticDB Client SDK。
同時,對於快速上傳本地結構化的文本文件,可使用基於AnalyticDB Client SDK開發的Uploader工具。對於特別大的文件,能夠拆分後使用uploader工具進行並行導入。
另外,對於OSS,MaxCompute這樣的外部數據源,AnalyticDB經過分佈式的Connector Service數據導入服務併發讀取並寫入到相應DB中。Connector Service還將支持訂閱模式,從Kafka,MQ,RDS等動態數據源把數據導入到相應DB中。AnalyticDB對大數據生態的Logstash,Fluentd,Flume等日誌收集端、ETL工具等經過相應插件支持,可以快速把數據寫入相應DB。
今天在阿里巴巴集團內,天天有數萬張表從MaxCompute導入到AnalyticDB中進行在線分析,其中大量導入任務單表數據大小在TB級、數據量近千億。
AnalyticDB目前支持數據導出到OSS和MaxCompute,業務場景主要是把相應查詢結果在外部存儲進行保存歸檔,實現原理相似insert from select操做。insert from select是把查詢結果寫入到內部表,而導出操做則是寫入外部存儲, 經過改進實現機制,能夠方便地支持更多的導出數據源。
AnalyticDB通過數年的發展,語法解析器也經歷了屢次更新迭代。曾經使用過業界主流的 Antlr(http://www.antlr.org),JavaCC(https://javacc.org)等Parser生成器做爲SQL 語法解析器,可是二者在長期、大規模、複雜查詢場景下,Parser的性能、語法兼容、API設計等方面不知足要求,因而咱們引入了自研的SQL Parser組件FastSQL。
AnalyticDB主打的場景是高併發、低延時的在線化分析,對SQL Parser性能要求很高,批量實時寫入等場景要求更加苛刻。FastSQL經過多種技術優化提高Parser性能,例如:
快速對比:使用64位hash算法加速關鍵字匹配,使用fnv_1a_64 hash算法,在讀取identifier的同時計算好hash值,並利用hash64低碰撞機率的特色,使用64位hash code直接比較,比常規Lexer先讀取identifier,在查找SymbolTable速度更快。
高性能的數值Parser:Java自帶的Integer.parseInt()/Float.parseFloat()須要構造字符串再作parse,FastSQL改進後能夠直接在原文本上邊讀取邊計算數值。
分支預測:在insert values中,出現常量字面值的機率比出現其餘的token要高得多,經過分支預測能夠減小判斷提高性能。
以TPC-DS99個Query對比來看,FastSQL比Antlr Parser(使用Antlr生成)平均快20倍,比JSQLParser(使用JavaCC生成)平均快30倍,在批量Insert場景、多列查詢場景下,使用FastSQL後速度提高30~50倍。
在結合AnalyticDB的優化器的SQL優化實踐中,FastSQL不斷將SQL Rewrite的優化能力前置化到SQL Parser中實現,經過與優化器的SQL優化能力協商,將盡量多的表達式級別優化前置化到SQL Parser中,使得優化器能更加專一於基於代價和成本的優化(CBO,Cost-Based Optimization)上,讓優化器能更多的集中在理解計算執行計劃優化上。FastSQL在AST Tree上實現了許多SQL Rewrite的能力,例如:
常量摺疊:
SELECT * FROMt1 t
WHEREcomm_week
BETWEEN((('day',-('20180605'), CASTdate_formatdate_addday_of_week
date('20180605')),'%Y%m%d') AS bigint)
AND((('day',-('20180605') CASTdate_formatdate_addday_of_week
,date('20180605')),'%Y%m%d') AS bigint)
------>
SELECT * FROMt1 t
WHEREBETWEEN20180602AND20180602comm_week
函數變換:
SELECT * FROMt1 t
WHERE(."pay_time",'%Y%m%d')>='20180529'DATE_FORMATt
AND(."pay_time",'%Y%m%d')<='20180529' DATE_FORMATt
------>
SELECT * FROMt1 t
WHERE."pay_time">= TIMESTAMP'2018-05-29 00:00:00't
AND."pay_time"< TIMESTAMP'2018-05-30 00:00:00't
表達式轉換:
SELECT,FROMabt1
WHERE+1=10;b
------>
SELECT,FROMabt1
WHERE=9;b
函數類型推斷:
-- f3類型是TIMESTAMP類型
SELECT(,1)concatf3
FROM;nation
------>
SELECT((AS CHAR),'1')concatCASTf3
FROM;nation
常量推斷:
SELECT * FROMt
WHERE<AND=AND=5abbca
------>
SELECT * FROMt
WHERE>5AND=5AND=babc
語義去重:
SELECT * FROMt1
WHERE>'2017-05-01'max_adate
AND!='2017-04-01' max_adate
------>
SELECT * FROMt1
WHERE> DATE '2017-05-01'max_adate
玄武存儲引擎
爲保證大吞吐寫入,以及高併發低時延響應,AnalyticDB自研存儲引擎玄武,採用多項創新的技術架構。玄武存儲引擎採用讀/寫實例分離架構,讀節點和寫節點可分別獨立擴展,提供寫入吞吐或者查詢計算能力。在此架構下大吞吐數據寫入不影響查詢分析性能。同時玄武存儲引擎構築了智能全索引體系,保證絕大部分計算基於索引完成,保證任意組合條件查詢的毫秒級響應。
傳統數據倉庫並無將讀和寫分開處理,即這些數據庫進程/線程處理請求的時候,無論讀寫都會在同一個實例的處理鏈路上進行。所以全部的請求都共享同一份資源(內存資源、鎖資源、IO資源),並相互影響。在查詢請求和寫入吞吐都很高的時候,會存在嚴重的資源競爭,致使查詢性能和寫入吞吐都降低。
爲了解決這個問題,玄武存儲引擎設計了讀寫分離的架構。以下圖所示,玄武存儲引擎有兩類關鍵的節點:Buffer Node和Compute Node。Buffer Node專門負責處理寫請求,Compute Node專門負責查詢請求,Buffer Node和Compute Node徹底獨立並互相不影響,所以,讀寫請求會在兩個徹底不相同的鏈路中處理。上層的Front Node會把讀寫請求分別路由給Buffer Node和Compute Node。
實時寫入鏈路:
業務實時數據經過JDBC/ODBC協議寫入到Front Node。
Front Node根據實時數據的hash分區列值,路由到相應Buffer Node。
Buffer Node將該實時數據的內容(相似於WAL)提交到盤古分佈式文件系統,同時更新實時數據版本,並返回Front Node,Front Node返回寫入成功響應到客戶端。
Buffer Node同時會異步地把實時數據內容推送到Compute Node,Compute Node消費該實時數據並構建實時數據輕量級索引。
當實時數據積攢到必定量時,Buffer Node觸發後臺Merge Baseline做業,對實時數據構建徹底索引並與基線數據合併。
實時查詢鏈路:
業務實時查詢請求經過JDBC/ODBC協議發送到Front Node。
Front Node首先從Buffer Node拿到當前最新的實時數據版本,並把該版本隨執行計劃一塊兒下發到Compute Node。
Compute Node檢查本地實時數據版本是否知足實時查詢要求,若知足,則直接執行並返回數據。若不知足,需先到Buffer Node把指定版本的實時數據拖到本地,再執行查詢,以保證查詢的實時性(強一致)。
AnalyticDB提供強實時和弱實時兩種模式,強實時模式執行邏輯描述如上。弱實時模式下,Front Node查詢請求則不帶版本下發,返回結果的實時取決於Compute Node對實時數據的處理速度,通常有秒極延遲。因此強實時在保證數據一致性的前提下,當實時數據寫入量比較大時對查詢性能會有必定的影響。
玄武存儲引擎爲Buffer Node和Compute Node提供了高可靠機制。用戶能夠定義Buffer Node和Compute Node的副本數目(默認爲2),玄武保證同一個數據分區的不一樣副本必定是存放在不一樣的物理機器上。Compute Node的組成採用了對等的熱副本服務機制,全部Compute Node節點均可以參與計算。另外,Computed Node的正常運行並不會受到Buffer Node節點異常的影響。若是Buffer Node節點異常致使Compute Node沒法正常拉取最新版本的數據,Compute Node會直接從盤古上獲取數據(即使這樣須要忍受更高的延遲)來保證查詢的正常執行。數據在Compute Node上也是備份存儲。以下圖所示,數據是經過分區存放在不一樣的ComputeNode上,具備相同hash值的分區會存儲在同一個Compute Node上。數據分區的副本會存儲在其餘不一樣的Compute Node上,以提供高可靠性。
玄武的兩個重要特性設計保證了其高可擴展性:1)Compute Node和Buffer Node都是無狀態的,他們能夠根據業務負載需求進行任意的增減;2)玄武並不實際存儲數據,而是將數據存到底層的盤古系統中,這樣,當Compute Node和Buffer Node的數量進行改變時,並不須要進行實際的數據遷移工做。
傳統關係型數據庫通常採用行存儲(Row-oriented Storage)加B-tree索引,優點在於其讀取多列或全部列(SELECT *)場景下的性能,典型的例子如MySQL的InnoDB引擎。可是在讀取單列、少數列而且行數不少的場景下,行存儲會存在嚴重的讀放大問題。
數據倉庫系統通常採用列存儲(Column-oriented Storage),優點在於其單列或少數列查詢場景下的性能、更高的壓縮率(不少時候一個列的數據具備類似性,而且根據不一樣列的值類型能夠採用不一樣的壓縮算法)、列聚合計算(SUM, AVG, MAX, etc.)場景下的性能。可是若是用戶想要讀取整行的數據,列存儲會帶來大量的隨機IO,影響系統性能。
爲了發揮行存儲和列存儲各自的優點,同時避免二者的缺點,AnalyticDB設計並實現了全新的行列混存模式。以下圖所示:
對於一張表,每k行數據組成一個Row Group。在每一個Row Group中,每列數據連續的存放在單獨的block中,每Row Group在磁盤上連續存放。
Row Group內列block的數據可按指定列(彙集列)排序存放,好處是在按該列查詢時顯著減小磁盤隨機IO次數。
每一個列block可開啓壓縮。
行列混存存儲相應的元數據包括:分區元數據,列元數據,列block元數據。其中分區元數據包含該分區總行數,單個block中的列行數等信息;列元數據包括該列值類型、整列的MAX/MIN值、NULL值數目、直方圖信息等,用於加速查詢;列block元數據包含該列在單個Row Group中對應的MAX/MIN/SUM、總條目數(COUNT)等信息,一樣用於加速查詢。
用戶的複雜查詢可能會涉及到各類不一樣的列,爲了保證用戶的複雜查詢可以獲得秒級響應,玄武存儲引擎在行列混合存儲的基礎上,爲基線數據(即歷史數據)全部列都構建了索引。玄武會根據列的數據特徵和空間消耗狀況自動選擇構建倒排索引、位圖索引或區間樹索引等,而用的最多的是倒排索引。
如上圖所示,在倒排索引中,每列的數值對應索引的key,該數值對應的行號對應索引的value,同時全部索引的key都會進行排序。依靠全列索引,交集、並集、差集等數據庫基礎操做能夠高性能地完成。以下圖所示,用戶的一個複雜查詢包含着對任意列的條件篩選。玄武會根據每一個列的條件,去索引中篩選知足條件的行號,而後再將每列篩選出的行號,進行交、並、差操做,篩選出最終知足全部條件的行號。玄武會依據這些行號去訪問實際的數據,並返回給用戶。一般通過篩選後,知足條件的行數可能只佔總行數的萬分之一到十萬分之一。所以,全列索引幫助玄武在執行查詢請求的時候,大大減少須要實際遍歷的行數,進而大幅提高查詢性能,知足任意複雜查詢秒級響應的需求。
使用全列索引給設計帶來了一個很大挑戰:須要對大量數據構建索引,這會是一個很是耗時的過程。若是像傳統數據庫那樣在數據寫入的路徑上進行索引構建,那麼這會嚴重影響寫入的吞吐,並且會嚴重拖慢查詢的性能,影響用戶體驗。爲了解決這個挑戰,玄武採用了異步構建索引的方式。當寫入請求到達後,玄武把寫SQL持久化到盤古,而後直接返回,並不進行索引的構建。
當這些未構建索引的數據(稱爲實時數據)積累到必定數量時,玄武會開啓多個MapReduce任務,來對這些實時數據進行索引的構建,並將實時數據及其索引,同當前版本的基線數據(歷史數據)及其索引進行多版本歸併,造成新版本的基線數據和索引。這些MapReduce任務經過伏羲進行分佈式調度和執行,異步地完成索引的構建。這種異步構建索引的方式,既不影響AnalyticDB的高吞吐寫入,也不影響AnalyticDB的高性能查詢。
異步構建索引的機制還會引入一個新問題:在進行MapReduce構建索引的任務以前,新寫入的實時數據是沒有索引的,若是用戶的查詢會涉及到實時數據,查詢性能有可能會受到影響。玄武採用爲實時數據構建排序索引(Sorted Index)的機制來解決這個問題。
以下圖所示,玄武在將實時數據以block形式刷到磁盤以前,會根據每一列的實時數據生成對應的排序索引。排序索引實際是一個行號數組,對於升序排序索引來講,行號數組的第一個數值是實時數據最小值對應的行號,第二個數值是實時數據第二小值對應的行號,以此類推。這種狀況下,對實時數據的搜索複雜度會從O(N)下降爲O(lgN)。排序索引大小一般很小(60KB左右),所以,排序索引能夠緩存在內存中,以加速查詢。
針對低延遲高併發的在線分析場景需求,AnalyticDB自研了羲和大規模分析引擎,其中包括了基於流水線模型的分佈式並行計算引擎,以及基於規則 (Rule-Based Optimizer,RBO) 和代價(Cost-Based Optimizer,CBO)的智能查詢優化器。
優化規則的豐富程度是可否產生最優計劃的一個重要指標。由於只有可選方案足夠多時,纔有可能選到最優的執行計劃。AnalyticDB提供了豐富的關係代數轉換規則,用來確保不會遺漏最優計劃。
基礎優化規則:
裁剪規則:列裁剪、分區裁剪、子查詢裁剪
下推/合併規則:謂詞下推、函數下推、聚合下推、Limit下推
去重規則:Project去重、Exchange去重、Sort去重
常量摺疊/謂詞推導
探測優化規則:
Joins:BroadcastHashJoin、RedistributedHashJoin、NestLoopIndexJoin
Aggregate:HashAggregate、SingleAggregate
JoinReordering
GroupBy下推、Exchange下推、Sort下推
高級優化規則:CTE
例以下圖中,CTE的優化規則的實現將兩部分相同的執行邏輯合爲一個。經過相似於最長公共子序列的算法,對整個執行計劃進行遍歷,並對一些能夠忽略的算子進行特殊處理,如Projection,最終達到減小計算的目的。
單純基於規則的優化器每每過於依賴規則的順序,一樣的規則不一樣的順序會致使生成的計劃徹底不一樣,結合基於代價的優化器則能夠經過嘗試各類可能的執行計劃,達到全局最優。
AnalyticDB的代價優化器基於Cascade模型,執行計劃通過Transform模塊進行了等價關係代數變換,對可能的等價執行計劃,估算出按Cost Model量化的計劃代價,並從中最終選擇出代價最小的執行計劃經過Plan Generation模塊輸出,存入Plan Cache(計劃緩存),以下降下一次相同查詢的優化時間。
在線分析的場景對優化器有很高的要求,AnalyticDB爲此開發了三個關鍵特性:存儲感知優化、動態統計信息收集和計劃緩存。
生成分佈式執行計劃時,AnalyticDB優化器能夠充分利用底層存儲的特性,特別是在Join策略選擇,Join Reorder和謂詞下推方面。
底層數據的哈希分佈策略將會影響Join策略的選擇。基於規則的優化器,在生成Join的執行計劃時,若是對數據物理分佈特性的不感知,會強制增長一個數據重分佈的算子來保證其執行語義的正確。 數據重分佈帶來的物理開銷很是大,涉及到數據的序列化、反序列化、網絡開銷等等,所以避免屢次數據重分佈對於分佈式計算是很是重要的。除此以外,優化器也會考慮對數據庫索引的使用,進一步減小Join過程當中構建哈希的開銷。
調整Join順序時,若是大多數Join是在分區列,優化器將避免生成Bushy Tree,而更偏向使用Left Deep Tree,並儘可能使用現有索引進行查找。
優化器更近一步下推了謂詞和聚合。聚合函數,好比count(),和查詢過濾能夠直接基於索引計算。
全部這些組合下降了查詢延遲,同時提升集羣利用率,從而使得AnalyticDB能輕鬆支持高併發。
統計信息是優化器在作基於代價查詢優化所需的基本信息,一般包括有關表、列和索引等的統計信息。傳統數據倉庫僅收集有限的統計信息,例如列上典型的最常值(MFV)。商業數據庫爲用戶提供了收集統計信息的工具,但這一般取決於DBA的經驗,依賴DBA來決定收集哪些統計數據,並依賴於服務或工具供應商。
上述方法收集的統計數據一般都是靜態的,它可能須要在一段時間後,或者當數據更改達到必定程度,來從新收集。可是,隨着業務應用程序變得愈來愈複雜和動態,預約義的統計信息收集可能沒法以更有針對性的方式幫助查詢。例如,用戶能夠選擇不一樣的聚合列和列數,其組合可能會有很大差別。可是,在查詢生成以前很難預測這樣的組合。所以,很難在統計收集時決定正確統計方案。可是,此類統計信息可幫助優化器作出正確決定。
咱們設計了一個查詢驅動的動態統計信息收集機制來解決此問題。守護程序動態監視傳入的查詢工做負載和特色以提取其查詢模式,並基於查詢模式,分析缺失和有益的統計數據。在此分析和預測之上,異步統計信息收集任務在後臺執行。這項工做旨在減小收集沒必要要的統計數據,同時使大多數即將到來的查詢受益。對於前面提到的聚合示例,收集多列統計信息一般很昂貴,尤爲是當用戶表有大量列的時候。根據咱們的動態工做負載分析和預測,能夠作到僅收集必要的多列統計信息,同時,優化器可以利用這些統計數據來估計聚合中不一樣選項的成本並作出正確的決策。
從在線應用案件看,大多數客戶都有一個共同的特色,他們常常反覆提交相似的查詢。在這種狀況下,計劃緩存變得相當重要。爲了提升緩存命中率,AnalyticDB不使用原始SQL文本做爲搜索鍵來緩存。相反,SQL語句首先經過重寫並參數化來提取模式。例如,查詢 「SELECT * FROM t1 WHERE a = 5 + 5」將轉化爲「SELECT * FROM t1 WHERE a =?」。參數化的SQL模版將被做爲計劃緩存的關鍵字,若是緩存命中,AnalyticDB將根據新查詢進行參數綁定。因爲這個改動,即便使用有限的緩存大小,優化器在生產環境也能夠保持高達90%以上的命中率,而以前只能達到40%的命中率。
這種方法仍然有一個問題。假設咱們在列a上有索引,「SELECT * FROM t1 WHERE a = 5」的優化計劃能夠將索引掃描做爲其最佳訪問路徑。可是,若是新查詢是「SELECT * FROM t1 WHERE a = 0」而且直方圖告訴咱們數值0在表t1佔大多數,那麼索引掃描可能不如全表掃描有效。在這種狀況下,使用緩存中的計劃並非一個好的決定。爲了不這類問題,AnalyticDB提供了一個功能Literal Classification,使用列的直方圖對該列的值進行分類,僅當與模式相關聯的常量「5」的數據分佈與新查詢中常量「0」的數據分佈相似時,才實際使用高速緩存的計劃。不然,仍會對新查詢執行常規優化。
在優化器之下,AnalyticDB在MPP架構基礎上,採用流水線執行的DAG架構,構建了一個適用於低延遲和高吞吐量工做負載的執行器。以下圖所示,當涉及到多個表之間非分區列JOIN時,CN(MPP Worker)會先進行data exchange (shuffling)而後再本地JOIN (SourceTask),aggregate後發送到上一個stage(MiddleTask),最後彙總到Output Task。因爲絕大多狀況都是in-memory計算(除複雜ETL類查詢,儘可能無中間Stage 落盤)且各個stage之間都是pipeline方式協做,性能上要比MapReduce方式快一個數量級。
在接下來的幾節中,將介紹其中三種特性,包括混合工做負載管理,CodeGen和矢量化執行。
做爲一套完備的實時數倉解決方案,AnalyticDB中既有須要較低響應時間的高併發查詢,也有相似ETL的批處理,二者爭用相同資源。傳統數倉體系每每在這兩個方面的兼顧性上作的不夠好。
AnalyticDB worker接收coordinator下發的任務, 負責該任務的物理執行計劃的實際執行。這項任務能夠來自不一樣的查詢, worker會將任務中的物理執行計劃按照既定的轉換規則轉換成對應的operator,物理執行計劃中的每個Stage會被轉換成一個或多個operator。
執行引擎已經能夠作到stage/operator級別中斷和Page級別換入換出,同時線程池在全部同時運行的查詢間共享。可是,這之上仍然須要確保高優先級查詢能夠得到更多計算資源。
根據經驗,客戶老是指望他們的短查詢即便當系統負載很重的時候也能快速完成。爲了知足這些要求,基於以上場景,經過時間片的分配比例來體現不一樣查詢的優先級,AnalyticDB實現了一個簡單版本的類Linux kernel 的調度算法。系統記錄了每個查詢的總執行耗時,查詢總耗時又是經過每個Task耗時來進行加權統計的,最終在查詢層面造成了一顆紅黑樹,每次老是挑選最左側節點進行調度,每次取出或者加入(被喚醒以及從新入隊)都會從新更新這棵樹,一樣的,在Task被喚醒加入這顆樹的時候,執行引擎考慮了補償機制,即時間片耗時若是遠遠低於其餘Task的耗時,確保其在整個樹裏面的位置,同時也避免了由於長時間的阻塞形成的飢餓,相似於CFS 調度算法中的vruntime補償機制。
這個設計雖然有效解決了慢查詢佔滿資源,致使其餘查詢得不到執行的問題,卻沒法保障快查詢的請求延遲。這是因爲軟件層面的多線程執行機制,線程個數大於了實際的CPU個數。在實際的應用中,計算線程的個數每每是可用Core的2倍。這也就是說,即便快查詢的算子獲得了計算線程資源進行計算,也會在CPU層面與慢查詢的算子造成競爭。所下圖所示,快查詢的算子計算線程被調度到VCore1上,該算子在VCore1上會與慢查詢的計算線程造成競爭。另外在物理Core0上,也會與VCore0上的慢查詢的計算線程造成競爭。
在Kernel sched模塊中,對於不一樣優先級的線程之間的搶佔機制,已經比較完善,且時效性比較高。於是,經過引入kernel層面的控制能夠有效解決快查詢低延遲的問題,且無需對算子的實現進行任何的改造。執行引擎讓高優先級的線程來執行快查詢的算子,低優先級的線程來執行慢查詢的算子。因爲高優先級線程搶佔低優先級線程的機制,快查詢算子天然會搶佔慢查詢的算子。此外,因爲高優先級線程在Kernel sched模塊調度中,具備較高的優先級,也避免了快慢查詢算子在vcore層面的CPU競爭。
一樣的在實際應用中是很難要求用戶來辨別快慢查詢,由於用戶的業務自己可能就沒有快慢業務之分。另外對於在線查詢,查詢的計算量也是不可預知的。爲此,計算引擎在Runtime層面引入了快慢查詢的識別機制,參考Linux kernel中vruntime的方式,對算子的執行時間、調度次數等信息進行統計,當算子的計算量達到給定的慢查詢的閾值後,會把算子從高優先級的線程轉移到低優先級的線程中。這有效提升了在壓力測試下快查詢的響應時間。
Dynamic code generation(CodeGen)廣泛出如今業界的各大計算引擎設計實現中。它不只可以提供靈活的實現,減小代碼開發量,一樣在性能優化方面也有着較多的應用。可是同時基於ANTLR ASM的AnalyticDB代碼生成器也引入了數十毫秒編譯等待時間,這在實時分析場景中是不可接受的。爲了進一步減小這種延遲,分析引擎使用了緩存來重用生成的Java字節碼。可是,它並不是能對全部狀況都起很好做用。
隨着業務的普遍使用以及對性能的進一步追求,系統針對具體的狀況對CodeGen作了進一步的優化。使用了Loading Cache對已經生成的動態代碼進行緩存,可是SQL表達式中每每會出現常量(例如,substr(col1,1, 3),col1 like‘demo%’等),在原始的生成邏輯中會直接生成常量使用。這致使不少相同的方法在遇到不一樣的常量值時須要生成一整套新的邏輯。這樣在高併發場景下,cache命中率很低,而且致使JDK的meta區增加速度較快,更頻繁地觸發GC,從而致使查詢延遲抖動。
substr(col1, 1, 3) => cacheKey<CallExpression(substr), inputReferenceExpression(col1), constantExpression(1), constantExpression(3)>cacheValue bytecode; |
經過對錶達式的常量在生成bytecode階段進行rewrite,對出現的每一個常量在Class級別生成對應的成員變量來存儲,去掉了Cachekey中的常量影響因素,使得能夠在不一樣常量下使用相同的生成代碼。命中的CodeGen將在plan階段instance級別的進行常量賦值。
substr(col1, 1, 3) => cacheKey<CallExpression(substr), inputReferenceExpression(col1)>cacheValue bytecode; |
在測試與線上場景中,通過優化不少高併發的場景再也不出現meta區的GC,這顯著增長了緩存命中率,總體運行穩定性以及平均延遲均有必定的提高。
AnalyticDB CodeGen不只實現了謂詞評估,還支持了算子級別運算。例如,在複雜SQL且數據量較大的場景下,數據會屢次shuffle拷貝,在partitioned shuffle進行數據拷貝的時候很容易出現CPU瓶頸。用於鏈接和聚合操做的數據Shuffle一般會複製從源數據塊到目標數據塊的行,僞代碼以下所示:
foreach row foreach column type.append(blockSrc, position, blockDest); |
從生產環境,大部分SQL每次shuffle的數據量較大,可是列不多。那麼首先想到的就是forloop的展開。那麼上面的僞代碼就能夠轉換成
foreach row type(1).append(blockSrc(1), position, blockDest(1)); type(2).append(blockSrc(2), position, blockDest(2)); type(3).append(blockSrc(3), position, blockDest(3)); |
上面的優化經過直接編碼是沒法完成的,須要根據SQL具體的column狀況動態的生成對應的代碼實現。在測試中1000w的數據量級拷貝延時能夠提高24%。
相對於行式計算,AnalyticDB的矢量化計算因爲對緩存更加友好,並避免了沒必要要的數據加載,從而擁有了更高的效率。在這之上,AnalyticDB CodeGen也將運行態因素考慮在內,可以輕鬆利用異構硬件的強大功能。例如,在CPU支持AVX-512指令集的集羣,AnalyticDB能夠生成使用SIMD的字節碼。同時AnalyticDB內部全部計算都是基於二進制數據,而不是Java Object,有效避免了序列化和反序列化開銷。
在多租戶基礎上,AnalyticDB對每一個租戶的DB支持在線升降配,擴縮容,操做過程當中無需停服,對業務幾乎透明。如下圖爲例:
用戶開始能夠在雲上開通包含兩個C4資源的DB進行業務試用和上線(圖中的P1, P2...表明表的數據分區)
隨着業務的增加,當兩個C4的存儲或計算資源沒法知足時,用戶可自主對該DB發起升配或擴容操做,升配+擴容可同時進行。該過程會按副本交替進行,保證整個過程當中始終有一個副本提供服務。另外,擴容增長節點後,數據會自動在新老節點間進行重分佈。
對於臨時性的業務增加(如電商大促),升配擴容操做都可逆,在大促事後,可自主進行降配縮容操做,作到靈活地成本控制。
在線升降配,平滑擴縮容能力,對今年雙十一阿里巴巴集團內和公共雲上和電商物流相關的業務庫起到了相當重要的保障做用。
某客戶數據業務的數據量在半年時間內由不到200TB增長到1PB,而且還在快速翻番,截止到發稿時爲止已經超過1PB。該業務計算複雜,查詢時間跨度週期長,需按照任意選擇屬性過濾,單個查詢計算涉及到的算子包括20個以上同時交併差、多表join、多值列(相似array)group by等以及上述算子的各類複雜組合。傳統的MapReduce離線分析方案時效性差,極大限制了用戶快速分析、快速鎖定人羣並即時投放廣告的訴求,業務發展面臨新的瓶頸。
GPU加速AnalyticDB的作法是在Compute Node中新增GPU Engine對查詢進行加速。GPU Engine主要包括: Plan Rewriter、Task Manager、Code Generator、CUDA Manager、Data Manager和VRAM Manager。
SQL查詢從Front Node發送到Compute Node,通過解析和邏輯計劃生成之後,Task Manager先根據計算的數據量以及查詢特徵選擇由CPU Engine仍是GPU Engine來處理,而後根據邏輯計劃生成適合GPU執行的物理計劃。
GPU Engine收到物理計劃後先對執行計劃進行重寫。若是計劃符合融合特徵,其中多個算子會被融合成單個複合算子,從而大量減小算子間臨時數據的Buffer傳輸。
Rewriting以後物理計劃進入Code Generator,該模塊主功能是將物理計劃編譯成PTX代碼。Code Generator第一步藉助LLVM JIT先將物理計劃編譯成LLVM IR,IR通過優化之後經過LLVMNVPTX Target轉換成PTX代碼。CUDA運行時庫會根據指定的GPU架構型號將PTX轉換成本地可執行代碼,並啓動其中的GPU kernel。Code Generator能夠支持不一樣的Nvidia GPU。
CUDA Manager經過jCUDA調用CUDA API,用於管理和配置GPU設備、GPU kernel的啓動接口封裝。該模塊做爲Java和GPU之間的橋樑,使得JVM能夠很方便地調用GPU資源。
Data Manager主要負責數據加載,將數據從磁盤或文件系統緩存加載到指定堆外內存,從堆外內存加載到顯存。CPU Engine的執行模型是數據庫經典的火山模型,即表數據需逐行被拉取再計算。這種模型明顯會極大閒置GPU上萬行的高吞吐能力。目前Data Manager可以批量加載列式數據塊,每次加載的數據塊大小爲256M,而後經過PCIe總線傳至顯存。
VRAM Manager用於管理各GPU的顯存。顯存是GPU中最稀缺的資源,須要合理管理和高效複用,有別於如今市面上其餘GPU數據庫系統使用GPU的方式,即每一個SQL任務獨佔全部的GPU及其計算和顯存資源。爲了提高顯存的利用率、提高併發能力,結合AnalyticDB多分區、多線程的特色,咱們設計基於Slab的VRAM Manager統一管理全部顯存申請:Compute Node啓動時,VRAM Manager先申請所需空間並切分紅固定大小的Slab,這樣能夠避免運行時申請帶來的時間開銷,也下降經過顯卡驅動頻繁分配顯存的DoS風險。
在須要顯存時,VRAM Manager會從空閒的Slab中查找空閒區域劃分顯存,用完後返還Slab並作Buddy合併以減小顯存空洞。性能測試顯示分配時間平均爲1ms,對於總體運行時間而言可忽略不計,明顯快於DDR內存分配的700ms耗時,也利於提升系統總體併發度。在GPU和CPU數據交互時,自維護的JVM堆外內存會做爲JVM內部數據對象(如ByteBuffer)和顯存數據的同步緩衝區,也必定程度減小了Full GC的工做量。
GPU Engine採用即時代碼生成技術主要有以下優勢:
相對傳統火山模型,減小計劃執行中的函數調用等,尤爲是分支判斷,GPU中分支跳轉會下降執行性能
靈活支持各類複雜表達式,例如projection和having中的複雜表達式。例如HAVING SUM(double_field_foo) > 1這種表達式的GPU代碼是即時生成的
靈活支持各類數據類型和UDF查詢時追加
利於算子融合,如group-by聚合、join再加聚合的融合,便可減小中間結果(特別是Join的鏈接結果)的拷貝和顯存的佔用
根據邏輯執行計劃動態生成GPU執行碼的整個過程以下所示:
該客戶數據業務使用了GPU實時加速後,將計算複雜、響應時間要求高、併發需求高的查詢從離線分析系統切換至AnalyticDB進行在線分析運行穩定,MapReduce離線分析的平均響應時間爲5到10分鐘,高峯時可能須要30分鐘以上。無縫升級到GPU加速版AnalyticDB以後,全部查詢徹底實時處理並保證秒級返回,其中80%的查詢的響應時間在2秒之內(以下圖),而節點規模降至原CPU集羣的三分之一左右。 業務目前能夠隨時嘗試各類圈人標籤組合快速對人羣畫像,即時鎖定廣告投放目標。據客戶方反饋,此加速技術已經幫助其在競爭中構建起高壁壘,使該業務成爲同類業務的核心能力,預計明年用戶量有望翻番近一個數量級。
簡單對本文作個總結,AnalyticDB作到讓數據價值在線化的核心技術可概括爲:
高性能SQL Parser:自研Parser組件FastSQL,極致的解析性能,無縫集合優化器
玄武存儲引擎:數據更新實時可見,行列混存,粗糙集過濾,聚簇列,索引優化
羲和計算引擎:MPP+DAG融合計算,CBO優化,向量化執行,GPU加速
極致彈性:業務透明的在線升降配,擴縮容,靈活控制成本。
GPU加速:利用GPU硬件加速OLAP分析,大幅度下降查詢延時。
分析型數據AnalyticDB, 做爲阿里巴巴自研的下一代PB級實時數據倉庫, 承載着整個集團內和雲上客戶的數據價值實時化分析的使命。 AnalyticDB爲數據價值在線化而生,做爲實時雲數據倉庫平臺,接下來會在體驗和周邊生態建設上繼續加快建設,但願能將最領先的下一代實時分析技術能力普惠給全部企業,幫助企業轉型加速數據價值探索和在線化。
轉自:https://mp.weixin.qq.com/s/kt-xtvM77UZ3kD-3dpU7sw