Hologres(中文名交互式分析)是阿里云自研的一站式實時數(shù)倉于颖,這個云原生系統(tǒng)融合了實時服務(wù)和分析大數(shù)據(jù)的場景诗良,全面兼容PostgreSQL協(xié)議并與大數(shù)據(jù)生態(tài)無縫打通台猴,能用同一套數(shù)據(jù)架構(gòu)同時支持實時寫入實時查詢以及實時離線聯(lián)邦分析。它的出現(xiàn)簡化了業(yè)務(wù)的架構(gòu)叽奥,與此同時為業(yè)務(wù)提供實時決策的能力扔水,讓大數(shù)據(jù)發(fā)揮出更大的商業(yè)價值。從阿里集團(tuán)誕生到云上商業(yè)化朝氓,隨著業(yè)務(wù)的發(fā)展和技術(shù)的演進(jìn)魔市,Hologres也在持續(xù)不斷優(yōu)化核心技術(shù)競爭力主届,為了讓大家更加了解Hologres,我們計劃持續(xù)推出Hologers底層技術(shù)原理揭秘系列待德,從高性能存儲引擎到高效率查詢引擎岂膳,高吞吐寫入到高QPS查詢等,全方位解讀Hologers磅网,請大家持續(xù)關(guān)注谈截!
往期精彩內(nèi)容:
- _ 2020年VLDB的論文《Alibaba Hologres: A cloud-Native Service for Hybrid Serving/Analytical Processing》_
- Hologres揭秘:首次公開!阿里巴巴云原生實時數(shù)倉核心技術(shù)揭秘
- Hologres揭秘:首次揭秘云原生Hologres存儲引擎
本期我們將帶來Hologers高效率分布式查詢引擎的技術(shù)原理解析涧偷。
Hologres作為HSAP服務(wù)分析一體化的落地最佳實踐簸喂,其查詢引擎是一個完全自研的執(zhí)行引擎,它的核心設(shè)計目標(biāo)是支持所有類型的分布式分析和服務(wù)查詢燎潮,并做到極致查詢性能喻鳄。為了做到這一點,我們借鑒了各種分布式查詢系統(tǒng)确封,包括分析型數(shù)據(jù)庫除呵,實時數(shù)倉等,吸取了各方面的優(yōu)勢從零開始打造出一個全新的執(zhí)行引擎爪喘。
為什么要選擇從零開始做一個新的查詢引擎颜曾?開源的分布式分析查詢系統(tǒng)主要有兩大類:
- 一類是傳統(tǒng)的 Massively Parallel Processing 系統(tǒng),能夠支持通用的 SQL 查詢秉剑,但是對實時場景支持不夠好泛豪,性能不夠理想。
- 一類是 Apache Druid 和 ClickHouse這些實時數(shù)倉侦鹏,是專門為實時場景設(shè)計和優(yōu)化的诡曙,能夠比較好地支持一些常見的單表實時查詢,但是復(fù)雜查詢的性能比較差略水。
- 另外大數(shù)據(jù)生態(tài)圈基于 MapReduce 的引擎比較適合批處理 ETL价卤,一般不太適合在線服務(wù)和多維分析的場景,性能也差不少渊涝。
Hologres 執(zhí)行引擎是在一個能支持復(fù)雜查詢和上述高性能實時服務(wù)查詢的通用架構(gòu)慎璧,先首先實現(xiàn)了常用的實時數(shù)倉場景,深入優(yōu)化并用內(nèi)部 Benchmark 驗證了性能和穩(wěn)定性超過包括專用實時數(shù)倉的其它競品之后驶赏,再擴(kuò)展到其它復(fù)雜查詢的支持炸卑。擴(kuò)展的過程中既鞠,在不可避免地系統(tǒng)變得越來越復(fù)雜的同時煤傍,也用 Benchmark 幫助保持簡單實時查詢的性能沒有回退。如果在已有的查詢引擎上做改進(jìn)嘱蛋,因為很多架構(gòu)和設(shè)計上的選擇已經(jīng)定型蚯姆,牽一發(fā)而動全身五续,就很難達(dá)到這樣的效果。
Hologres執(zhí)行引擎從開發(fā)到落地實踐面臨了非常多的挑戰(zhàn)龄恋,但也給我們提供了機(jī)會把這個領(lǐng)域的各種新進(jìn)展都結(jié)合利用起來疙驾,并超越已有系統(tǒng)做到對各種查詢類型的高性能處理,其背后主要是基于以下特點:
- 分布式執(zhí)行模型:一個和存儲計算分離架構(gòu)配合的分布式執(zhí)行模型郭毕。執(zhí)行計劃由異步算子組成的執(zhí)行圖 DAG(有向無環(huán)圖) 表示它碎,可以表達(dá)各種復(fù)雜查詢,并且完美適配 Hologres 的數(shù)據(jù)存儲模型显押,方便對接查詢優(yōu)化器扳肛,利用業(yè)界各種查詢優(yōu)化技術(shù)。
- 全異步執(zhí)行:端到端的全異步處理框架乘碑,可以避免高并發(fā)系統(tǒng)的瓶頸挖息,充分利用資源,并且最大可能地避免存儲計算分離系統(tǒng)帶來的讀數(shù)據(jù)延遲的影響兽肤。
- 向量化和列處理:算子內(nèi)部處理數(shù)據(jù)時最大可能地使用向量化執(zhí)行套腹,和存儲引擎的深度集成,通過靈活的執(zhí)行模型资铡,充分利用各種索引电禀,并且最大化地延遲向量物化和延遲計算,避免不必要的讀數(shù)據(jù)和計算笤休。
- 自適應(yīng)增量處理:對常見實時數(shù)據(jù)應(yīng)用查詢模式的自適應(yīng)增量處理鞭呕。
- 特定查詢深度優(yōu)化:對一些查詢模式的獨特優(yōu)化
下面將會對各個模塊一一介紹。
分布式執(zhí)行模型
Hologres 是能夠彈性無限水平擴(kuò)展數(shù)據(jù)量和計算能力的系統(tǒng)宛官,需要能夠支持高效的分布式查詢葫松。
Hologres 查詢引擎執(zhí)行的是由優(yōu)化器生成的分布式執(zhí)行計劃。執(zhí)行計劃由算子組成底洗。因為 Hologres 的一個表的數(shù)據(jù)會根據(jù) Distribution Key 分布在多個 Shard 上腋么,每個 Shard 內(nèi)又可以包含很多 Segment,執(zhí)行計劃也會反映這樣的結(jié)構(gòu)亥揖,并分布到數(shù)據(jù)所在的節(jié)點去執(zhí)行珊擂。每個Table Shard 會被加載到一個計算節(jié)點,數(shù)據(jù)會被緩存到這個節(jié)點的內(nèi)存和本地存儲费变。因為是存儲計算分離的架構(gòu)摧扇,如果一個節(jié)點出錯,其服務(wù)的 Shard 可以被重新加載到任意一個計算節(jié)點挚歧,只是相當(dāng)于清空了緩存扛稽。
例如一個比較簡單的查詢。
select key, count(value) as total from table1 group by key order by total desc limit 100滑负。
如果是單機(jī)數(shù)據(jù)庫在张,可以用這樣的執(zhí)行計劃用含。如果數(shù)據(jù)和計算分布在多個節(jié)點上,就需要更復(fù)雜的執(zhí)行計劃帮匾。
在分布式表上啄骇,為了更高效地執(zhí)行,盡量減少數(shù)據(jù)傳輸瘟斜,可以把執(zhí)行計劃分為不同片段(Fragment)分布到相應(yīng)節(jié)點執(zhí)行缸夹,并且把一些操作下推來減少 Fragment 輸出的數(shù)據(jù),可能就變成這樣的執(zhí)行計劃:
根據(jù)數(shù)據(jù)的特性螺句,優(yōu)化器可能會生成不同的計劃明未。例如在某一個局部聚合并沒有顯著減少數(shù)據(jù)量的時候,可以省略這個算子壹蔓。又例如在 Key 就是 Distribution key 的時候趟妥,可以優(yōu)化為:
從這些例子可以看出,Hologres 的執(zhí)行計劃根據(jù)數(shù)據(jù)的特性切分為不同的片段之后分布式并發(fā)執(zhí)行佣蓉。片段之間通過 Exchange 算子進(jìn)行數(shù)據(jù)交換披摄。更復(fù)雜的比如多表關(guān)聯(lián)(Join)查詢,會有更多的片段和更復(fù)雜的數(shù)據(jù)交換模式勇凭。
比如以下SQL
select user_name, sum(value) as total from t1 join t2 on t1.user_id = t2.user_id where … group by user_name order by total limit 100
在Hologres中可以是這樣的執(zhí)行計劃
如果 Join key 和 Distribution Key 一致疚膊,可以優(yōu)化為如下執(zhí)行計劃,減少遠(yuǎn)程數(shù)據(jù)傳輸虾标。根據(jù)需要的查詢合理地設(shè)置 Distribution Key坤候,可能顯著提高查詢性能球匕。
根據(jù)過濾條件和統(tǒng)計信息等等,優(yōu)化器還可能生成不同的優(yōu)化執(zhí)行計劃,比如包含動態(tài)過濾由蘑,局部聚合等等椭员。
這樣的分布式執(zhí)行計劃足夠通用状您,可以表達(dá)所有的 SQL 查詢和一些其它查詢例驹。執(zhí)行計劃和大部分 Massively Parallel Processing (MPP) 系統(tǒng)也比較類似,方便借鑒和集成業(yè)界的一些適用的優(yōu)化库继。稍微獨特一些的地方是很多查詢計劃片段的實例是和 Hologres 的存儲結(jié)構(gòu)對齊的箩艺,能夠進(jìn)行高效的分區(qū)裁剪和文件裁剪。
同時宪萄,Hologres 實現(xiàn)了 PostgreSQL 的 Explain 和 Explain Analyze 系列語句艺谆,可以展示文本格式的執(zhí)行計劃和相應(yīng)的執(zhí)行信息,方便用戶自助了解執(zhí)行計劃拜英,并針對性做出SQL優(yōu)化調(diào)整静汤。
全異步執(zhí)行
高并發(fā)系統(tǒng),特別是有大量 I/O 的系統(tǒng),頻繁地等待或者任務(wù)切換是常見的系統(tǒng)瓶頸撒妈。異步處理是一種已經(jīng)被證明行之有效的避免這些瓶頸恢暖,并把高并發(fā)系統(tǒng)性能推到極致的方法排监。
Hologres 的整個后端狰右,包括執(zhí)行引擎、存儲引擎和其它組件舆床,統(tǒng)一使用 HOS(Hologres Operation System) 組件提供的異步無鎖編程框架棋蚌,能夠最大化異步執(zhí)行的效果。每個 Fragment 的實例使用 HOS 的一個 EC (邏輯調(diào)度單位)挨队,使得一個 Fragment 里的所有算子和存儲引擎可以異步執(zhí)行并且無鎖安全訪問絕大多數(shù)資源谷暮。
算子和 Fragment 都是類似這樣的接口:
future<> Open(const SeekParameters& parameters, ...)
future<RecordBatchPtr, bool> GetNext(...)
future<> Close(...)
除了一般異步處理的好處外,異步算子接口較好地規(guī)避了存儲計算分離架構(gòu)下相對較高的讀數(shù)據(jù)延遲對查詢性能的影響盛垦,并且對分布式查詢的執(zhí)行模型本身也有獨特的好處湿弦。
DAG 執(zhí)行引擎一般可以分為拉數(shù)據(jù)的模性(比如火山模型)和推的模型(比如很多大數(shù)據(jù)的分階段執(zhí)行模型),各有其優(yōu)缺點腾夯。而 Hologres采用的異步的拉模型能夠取得兩種模型的好處并且避免其缺點(已經(jīng)申請了專利)颊埃。舉一個常見的 Hash Join 來說明:
火山模型可以簡單做到先拉完 b 的數(shù)據(jù)構(gòu)建 hash table,然后流式處理 a 的數(shù)據(jù)不用全放在內(nèi)存里蝶俱。但是當(dāng) a 或者 b 需要讀數(shù)據(jù)的時候班利,簡單的實現(xiàn)需要等待不能把 CPU 打滿,需要通過提高 Fragment 的并發(fā)數(shù)或者引入復(fù)雜的 pre-fetch 機(jī)制來充分利用資源榨呆,而這些又會引入別的性能問題罗标。
推數(shù)據(jù)的模型,比較容易做到并發(fā)讀數(shù)據(jù)請求并在完成的時候觸發(fā)下游處理积蜻,但是上述 Join算子的實現(xiàn)會比較復(fù)雜闯割。比如 a 處理完一批數(shù)據(jù)推到 Join 算子而 b 的 hash table 還沒有構(gòu)建完成,這批數(shù)據(jù)就需要暫存到內(nèi)存里或者盤上竿拆,或者引入反壓機(jī)制纽谒。在 Fragment 的邊界也會有類似問題,造成一些在拉數(shù)據(jù)模型下不需要的數(shù)據(jù)緩存如输。
Hologres 的算子和 Fragment 的異步拉數(shù)據(jù)模型鼓黔,可以像火山模型一樣簡單做到按需從上游獲取數(shù)據(jù),而同時又可以像推數(shù)據(jù)模型一樣簡單做到讀數(shù)據(jù)并發(fā)不见,只要向上游發(fā)出多個異步 GetNext澳化,上游處理完成時會自然觸發(fā)后續(xù)處理。異步 GetNext 的數(shù)目和時機(jī)稳吮,可以看做是天然的流控機(jī)制缎谷,可以有效做到提高 CPU 利用率并且避免不必要的數(shù)據(jù)暫存。
Hologres 已經(jīng)用這個異步模型實現(xiàn)了一個完整的查詢引擎灶似,可以支持所有 PostgreSQL 的查詢列林。
列處理和向量化
按列處理和向量化執(zhí)行都是分析查詢引擎常用的優(yōu)化機(jī)制瑞你,可以大幅度提高數(shù)據(jù)處理的效率。Hologres 也不例外希痴,在能使用向量處理的時候盡量使用者甲。
Hologres 在內(nèi)存里也采用列式存儲。在內(nèi)存里按列存儲數(shù)據(jù)能夠使用更多的向量處理砌创。列式組織數(shù)據(jù)還有一個好處虏缸,就是對延遲計算比較友好。比如 select … where a = 1 and b = 2 …嫩实,對一批數(shù)據(jù)(一般對應(yīng)存儲的一個 row group)刽辙,Hologres的 scan 算子輸出的 a 和 b 可以是延遲讀取的 a 和 b 的信息,在處理 a = 1 的時候會讀取這一批的 a甲献。如果 a=1 對這一批的所有行都不滿足宰缤,這一批的 b 這一列就根本不會被讀取。
但是對某些按行處理的算子晃洒,比如 Join慨灭,按列存儲的數(shù)據(jù)可能會造成更多的 CPU cache miss ,帶來較大的性能問題锥累。很多查詢引擎會在不同的點引入按列存儲和按行存儲的轉(zhuǎn)換缘挑,但是頻繁的轉(zhuǎn)換本身會帶來不小的開銷,而且列轉(zhuǎn)行會造成上述延遲讀取列被不必要地讀取桶略,還有一些其它的性能問題语淘。
自適應(yīng)增量處理
很多實時數(shù)據(jù)應(yīng)用經(jīng)常會對一個查詢用不同的時間段反復(fù)執(zhí)行。比如一個監(jiān)控指標(biāo)頁面打開后际歼,會定期執(zhí)行 select avg(v1) from metrics where d1 = x and d2 = y and ts >= '2020-11-11 00:00:00' and ts < '2020-11-11 03:01:05' and … group by d3 …
這樣的查詢惶翻,下一次會改成 ts < '2020-11-11 00:03:10'
,再下一次 ts < '2020-11-11 00:03:15'
鹅心。
流計算或者增量計算可以對這種查詢進(jìn)行非常高效的處理吕粗。但是對這種用戶可以隨意生成的交互式查詢,通常不可能對所有組合都配置流計算或者增量計算任務(wù)旭愧。如果每次都簡單執(zhí)行查詢颅筋,又可能有大量的重復(fù)計算造成資源浪費和性能不理想。
Hologres充分利用存儲引擎和計算引擎的深度集成和列式存儲大部分?jǐn)?shù)據(jù)在只讀文件中的特性输枯,在能提供包含最新寫入數(shù)據(jù)的查詢結(jié)果的同時盡量避免重復(fù)計算议泵,對這種類型的查詢能夠顯著提升性能和減少資源使用。
針對特定查詢模式的深度優(yōu)化
Hologres 對一些特定查詢模式有獨特的優(yōu)化桃熄。這里以Filter Aggregate 優(yōu)化為例子先口。
很多數(shù)據(jù)應(yīng)用都有開放列的需求,相當(dāng)于可以動態(tài)添加邏輯列而不用改 Table Schema。比如有一列是多值列 tags(Postgres 可以用 Array 類型)里面存了'{c1:v1, c2:u1}' 這樣的多個邏輯列的值碉京。查詢的時候厢汹,如果使用普通列,一類常見的查詢是
-- Q1:
select c1, sum(x) from t1 where c1 in (v1, v2, v3) and name = 'abc' group by c1
使用開放列后谐宙,這樣的查詢會轉(zhuǎn)變?yōu)?/p>
-- Q2:
select unnest(tags), sum(x) from t1 where name = 'abc' and tags && ARRAY['c1:v1', 'c1:v2', c1:v3']
group by unnest(tags)
having unnest(tags) in ('c1:v1', 'c1:v2', c1:v3')
這種查詢烫葬,Hologres 可以利用位圖索引快速計算過濾條件得到相關(guān)的行,但是之后從多值列里面取出相關(guān)數(shù)據(jù)操作不能使用向量處理卧惜,性能不能達(dá)到最優(yōu)厘灼。經(jīng)過調(diào)研夹纫,可以把查詢的執(zhí)行轉(zhuǎn)換為
Q3:
select 'c1:v1', sum(x) from t1 where tags && ARRAY['c1:v1']
UNION ALL
select 'c1:v2', sum(x) from t1 where tags && ARRAY['c1:v2']
UNION ALL
…
這樣每個 UNION ALL 分支可以只讀取 name 和 tags 的位圖索引計算過濾條件咽瓷,然后用 x 列的數(shù)據(jù)和過濾條件進(jìn)行向量計算 SUM_IF 即可得出想要的結(jié)果。這樣的問題是舰讹,每個分支都要過一遍 t1茅姜,讀取 x 列以及 name 列的位圖索引,帶來重復(fù)計算月匣。最后引入了一個 filter aggregate 的特殊算子來把這類常用查詢優(yōu)化到極致性能钻洒,可以只過一遍 t1 并且去掉重復(fù)操作,只用向量計算即可得到結(jié)果锄开,不需要讀取 tags 列的數(shù)據(jù)素标。在一個幾十 TB的表上實測性能提升 3 倍以上。
類似的優(yōu)化萍悴,Hologres 的執(zhí)行引擎都會盡量抽象為比較通用的算子头遭,可以適用于更多場景。Filter Aggregate 算子也是 Hologres 申請的專利之一癣诱。
總結(jié)
Hologres 執(zhí)行引擎在一個架構(gòu)里集中了相關(guān)分布式查詢系統(tǒng)的幾乎所有最高效的優(yōu)化方式(包括各種類型的索引)并作出了特有的改進(jìn)计维。通過和存儲引擎深度整合,能充分發(fā)揮異步模型的優(yōu)勢撕予,并高效利用各種類型的索引來加速查詢鲫惶。所有這些加起來,帶來了超越已有系統(tǒng)的性能实抡,并在阿里巴巴雙 11 的數(shù)據(jù)規(guī)模下通過了實戰(zhàn)的考驗欠母,(2020年雙11頂住了5.96億/秒的實時數(shù)據(jù)洪峰,基于萬億級數(shù)據(jù)對外提供多維分析和服務(wù)吆寨,99.99%的查詢可以在80ms以內(nèi)返回結(jié)果)赏淌,對外高并發(fā)高性能地提供分布式 HSAP 查詢服務(wù)。
后續(xù)我們將會陸續(xù)推出有關(guān)Hologres的技術(shù)底層原理揭秘系列鸟废,具體規(guī)劃如下猜敢,敬請持續(xù)關(guān)注!
- Hologres揭秘:首次公開!阿里巴巴云原生實時數(shù)倉核心技術(shù)揭秘
- Hologres揭秘:首次揭秘云原生Hologres存儲引擎
- Hologres揭秘:深度解析高效率分布式查詢引擎(本文)
- Hologres揭秘:透明加速MaxCompute查詢核心原理
- Hologres揭秘:如何實現(xiàn)MaxCompute與Hologres數(shù)據(jù)同步速度快百倍
- Hologres揭秘:如何支持高吞吐Upsert
- Hologres揭秘:如何支持在線服務(wù)場景的超高QPS
- Hologres揭秘:如何支持高并發(fā)查詢
- Hologres揭秘:如何支持高可用架構(gòu)
- Hologres揭秘:如何支持資源隔離缩擂,支持多種負(fù)載
- Hologres揭秘:向量檢索引擎Proxima原理與使用實踐
- Hologres揭秘:讀懂執(zhí)行計劃鼠冕,查詢性能翻十倍
- Hologres揭秘:分布式系統(tǒng)如何設(shè)計Shard與Table Group
- Hologres揭秘:如何支持更多Postgres生態(tài)擴(kuò)展包
- Hologres揭秘:高吞吐寫入Hologres的N種姿勢
- ......