共计 6443 个字符,预计需要花费 17 分钟才能阅读完成。
Hologres(中文名交互式剖析)是阿里云自研的一站式实时数仓,这个云原生零碎交融了实时服务和剖析大数据的场景,全面兼容 PostgreSQL 协定并与大数据生态无缝买通,能用同一套数据架构同时反对实时写入实时查问以及实时离线联邦剖析。它的呈现简化了业务的架构,与此同时为业务提供实时决策的能力,让大数据施展出更大的商业价值。从阿里团体诞生到云上商业化,随着业务的倒退和技术的演进,Hologres 也在继续一直优化核心技术竞争力,为了让大家更加理解 Hologres,咱们打算继续推出 Hologers 底层技术原理揭秘系列,从高性能存储引擎到高效率查问引擎,高吞吐写入到高 QPS 查问等,全方位解读 Hologers,请大家继续关注!
往期精彩内容:
- 2020 年 VLDB 的论文《Alibaba Hologres: A cloud-Native Service for Hybrid Serving/Analytical Processing》
- Hologres 揭秘: 首次公开!阿里巴巴云原生实时数仓核心技术揭秘
- Hologres 揭秘: 首次揭秘云原生 Hologres 存储引擎
本期咱们将带来 Hologers 高效率分布式查问引擎的技术原理解析。
Hologres 作为 HSAP 服务剖析一体化的落地最佳实际,其查问引擎是一个齐全自研的执行引擎,它的外围设计指标是反对所有类型的分布式剖析和服务查问,并做到极致查问性能。为了做到这一点,咱们借鉴了各种分布式查问零碎,包含剖析型数据库,实时数仓等,汲取了各方面的劣势从零开始打造出一个全新的执行引擎。
为什么要抉择从零开始做一个新的查问引擎?开源的分布式剖析查问零碎次要有两大类:
- 一类是传统的 Massively Parallel Processing 零碎,可能反对通用的 SQL 查问,然而对实时场景反对不够好,性能不够现实。
- 一类是 Apache Druid 和 ClickHouse 这些实时数仓,是专门为实时场景设计和优化的,可能比拟好地反对一些常见的单表实时查问,然而简单查问的性能比拟差。
- 另外大数据生态圈基于 MapReduce 的引擎比拟适宜批处理 ETL,个别不太适宜在线服务和多维分析的场景,性能也差不少。
Hologres 执行引擎是在一个能反对简单查问和上述高性能实时服务查问的通用架构,先首先实现了罕用的实时数仓场景,深刻优化并用外部 Benchmark 验证了性能和稳定性超过包含专用实时数仓的其它竞品之后,再扩大到其它简单查问的反对。扩大的过程中,在不可避免地零碎变得越来越简单的同时,也用 Benchmark 帮忙放弃简略实时查问的性能没有回退。如果在已有的查问引擎上做改良,因为很多架构和设计上的抉择曾经定型,牵一发而动全身,就很难达到这样的成果。
Hologres 执行引擎从开发到落地实际面临了十分多的挑战,但也给咱们提供了机会把这个畛域的各种新进展都联合利用起来,并超过已有零碎做到对各种查问类型的高性能解决,其背地次要是基于以下特点:
- 分布式执行模型 :一个和存储计算拆散架构配合的分布式执行模型。执行打算由异步算子组成的执行图 DAG(有向无环图)示意,能够表白各种简单查问,并且完满适配 Hologres 的数据存储模型,不便对接查问优化器,利用业界各种查问优化技术。
- 全异步执行 :端到端的全异步解决框架,能够防止高并发零碎的瓶颈,充分利用资源,并且最大可能地防止存储计算拆散零碎带来的读数据提早的影响。
- 向量化和列解决 :算子外部解决数据时最大可能地应用向量化执行,和存储引擎的深度集成,通过灵便的执行模型,充分利用各种索引,并且最大化地提早向量物化和提早计算,防止不必要的读数据和计算。
- 自适应增量解决 :对常见实时数据利用查问模式的自适应增量解决。
- 特定查问深度优化 :对一些查问模式的独特优化
上面将会对各个模块一一介绍。
分布式执行模型
Hologres 是可能弹性有限程度扩大数据量和计算能力的零碎,须要可能反对高效的分布式查问。
Hologres 查问引擎执行的是由优化器生成的分布式执行打算。执行打算由算子组成。因为 Hologres 的一个表的数据会依据 Distribution Key 散布在多个 Shard 上,每个 Shard 内又能够蕴含很多 Segment,执行打算也会反映这样的构造,并散布到数据所在的节点去执行。每个 Table Shard 会被加载到一个计算节点,数据会被缓存到这个节点的内存和本地存储。因为是存储计算拆散的架构,如果一个节点出错,其服务的 Shard 能够被从新加载到任意一个计算节点,只是相当于清空了缓存。
例如一个比较简单的查问。
select key, count(value) as total from table1 group by key order by total desc limit 100。
如果是单机数据库,能够用这样的执行打算。如果数据和计算散布在多个节点上,就须要更简单的执行打算。
在分布式表上,为了更高效地执行,尽量减少数据传输,能够把执行打算分为不同片段(Fragment)散布到相应节点执行,并且把一些操作下推来缩小 Fragment 输入的数据,可能就变成这样的执行打算:
依据数据的个性,优化器可能会生成不同的打算。例如在某一个部分聚合并没有显著缩小数据量的时候,能够省略这个算子。又例如在 Key 就是 Distribution key 的时候,能够优化为:
从这些例子能够看出,Hologres 的执行打算依据数据的个性切分为不同的片段之后分布式并发执行。片段之间通过 Exchange 算子进行数据交换。更简单的比方多表关联(Join)查问,会有更多的片段和更简单的数据交换模式。
比方以下 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 中能够是这样的执行打算
如果 Join key 和 Distribution Key 统一,能够优化为如下执行打算,缩小近程数据传输。依据须要的查问正当地设置 Distribution Key,可能显著进步查问性能。
依据过滤条件和统计信息等等,优化器还可能生成不同的优化执行打算,比方蕴含动静过滤,部分聚合等等。
这样的分布式执行打算足够通用,能够表白所有的 SQL 查问和一些其它查问。执行打算和大部分 Massively Parallel Processing (MPP) 零碎也比拟相似,不便借鉴和集成业界的一些实用的优化。略微独特一些的中央是很多查问打算片段的实例是和 Hologres 的存储构造对齐的,可能进行高效的分区裁剪和文件裁剪。
同时,Hologres 实现了 PostgreSQL 的 Explain 和 Explain Analyze 系列语句,能够展现文本格式的执行打算和相应的执行信息,不便用户自助理解执行打算,并针对性做出 SQL 优化调整。
全异步执行
高并发零碎,特地是有大量 I/O 的零碎,频繁地期待或者工作切换是常见的零碎瓶颈。异步解决是一种曾经被证实卓有成效的防止这些瓶颈,并把高并发零碎性能推到极致的办法。
Hologres 的整个后端,包含执行引擎、存储引擎和其它组件,对立应用 HOS(Hologres Operation System)组件提供的异步无锁编程框架,可能最大化异步执行的成果。每个 Fragment 的实例应用 HOS 的一个 EC(逻辑调度单位),使得一个 Fragment 里的所有算子和存储引擎能够异步执行并且无锁平安拜访绝大多数资源。
算子和 Fragment 都是相似这样的接口:
future<> Open(const SeekParameters& parameters, ...)
future<RecordBatchPtr, bool> GetNext(...)
future<> Close(...)
除了个别异步解决的益处外,异步算子接口较好地躲避了存储计算拆散架构下绝对较高的读数据提早对查问性能的影响,并且对分布式查问的执行模型自身也有独特的益处。
DAG 执行引擎个别能够分为拉数据的模性(比方火山模型)和推的模型(比方很多大数据的分阶段执行模型),各有其优缺点。而 Hologres 采纳的异步的拉模型可能获得两种模型的益处并且防止其毛病(曾经申请了专利)。举一个常见的 Hash Join 来阐明:
火山模型能够简略做到先拉完 b 的数据构建 hash table,而后流式解决 a 的数据不必全放在内存里。然而当 a 或者 b 须要读数据的时候,简略的实现须要期待不能把 CPU 打满,须要通过进步 Fragment 的并发数或者引入简单的 pre-fetch 机制来充分利用资源,而这些又会引入别的性能问题。
推数据的模型,比拟容易做到并发读数据申请并在实现的时候触发上游解决,然而上述 Join 算子的实现会比较复杂。比方 a 解决完一批数据推到 Join 算子而 b 的 hash table 还没有构建实现,这批数据就须要暂存到内存里或者盘上,或者引入反压机制。在 Fragment 的边界也会有相似问题,造成一些在拉数据模型下不须要的数据缓存。
Hologres 的算子和 Fragment 的异步拉数据模型,能够像火山模型一样简略做到按需从上游获取数据,而同时又能够像推数据模型一样简略做到读数据并发,只有向上游收回多个异步 GetNext,上游解决实现时会天然触发后续解决。异步 GetNext 的数目和机会,能够看做是人造的流控机制,能够无效做到进步 CPU 利用率并且防止不必要的数据暂存。
Hologres 曾经用这个异步模型实现了一个残缺的查问引擎,能够反对所有 PostgreSQL 的查问。
列解决和向量化
按列解决和向量化执行都是剖析查问引擎罕用的优化机制,能够大幅度提高数据处理的效率。Hologres 也不例外,在能应用向量解决的时候尽量应用。
Hologres 在内存里也采纳列式存储。在内存里按列存储数据可能应用更多的向量解决。列式组织数据还有一个益处,就是对提早计算比拟敌对。比方 select … where a = 1 and b = 2 …,对一批数据(个别对应存储的一个 row group),Hologres 的 scan 算子输入的 a 和 b 能够是提早读取的 a 和 b 的信息,在解决 a = 1 的时候会读取这一批的 a。如果 a=1 对这一批的所有行都不满足,这一批的 b 这一列就基本不会被读取。
然而对某些按行解决的算子,比方 Join,按列存储的数据可能会造成更多的 CPU cache miss,带来较大的性能问题。很多查问引擎会在不同的点引入按列存储和按行存储的转换,然而频繁的转换自身会带来不小的开销,而且列转行会造成上述提早读取列被不必要地读取,还有一些其它的性能问题。
自适应增量解决
很多实时数据利用常常会对一个查问用不同的时间段重复执行。比方一个监控指标页面关上后,会定期执行 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'
。
流计算或者增量计算能够对这种查问进行十分高效的解决。然而对这种用户能够随便生成的交互式查问,通常不可能对所有组合都配置流计算或者增量计算工作。如果每次都简略执行查问,又可能有大量的反复计算造成资源节约和性能不现实。
Hologres 充分利用存储引擎和计算引擎的深度集成和列式存储大部分数据在只读文件中的个性,在能提供蕴含最新写入数据的查问后果的同时尽量避免反复计算,对这种类型的查问可能显著晋升性能和缩小资源应用。
针对特定查问模式的深度优化
Hologres 对一些特定查问模式有独特的优化。这里以 Filter Aggregate 优化为例子。
很多数据利用都有凋谢列的需要,相当于能够动静增加逻辑列而不必改 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
应用凋谢列后,这样的查问会转变为
-- 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 能够利用位图索引疾速计算过滤条件失去相干的行,然而之后从多值列外面取出相干数据操作不能应用向量解决,性能不能达到最优。通过调研,能够把查问的执行转换为
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 列的数据和过滤条件进行向量计算 SUM_IF 即可得出想要的后果。这样的问题是,每个分支都要过一遍 t1,读取 x 列以及 name 列的位图索引,带来反复计算。最初引入了一个 filter aggregate 的非凡算子来把这类罕用查问优化到极致性能,能够只过一遍 t1 并且去掉反复操作,只用向量计算即可失去后果,不须要读取 tags 列的数据。在一个几十 TB 的表上实测性能晋升 3 倍以上。
相似的优化,Hologres 的执行引擎都会尽量形象为比拟通用的算子,能够实用于更多场景。Filter Aggregate 算子也是 Hologres 申请的专利之一。
总结
Hologres 执行引擎在一个架构里集中了相干分布式查问零碎的简直所有最高效的优化形式(包含各种类型的索引)并作出了特有的改良。通过和存储引擎深度整合,能充分发挥异步模型的劣势,并高效利用各种类型的索引来减速查问。所有这些加起来,带来了超过已有零碎的性能,并在阿里巴巴双 11 的数据规模下通过了实战的考验,(2020 年双 11 顶住了 5.96 亿 / 秒的实时数据洪峰,基于万亿级数据对外提供多维分析和服务,99.99% 的查问能够在 80ms 以内返回后果),对外高并发高性能地提供分布式 HSAP 查问服务。
后续咱们将会陆续推出无关 Hologres 的技术底层原理揭秘系列,具体布局如下,敬请继续关注!
- Hologres 揭秘: 首次公开!阿里巴巴云原生实时数仓核心技术揭秘
- Hologres 揭秘: 首次揭秘云原生 Hologres 存储引擎
- Hologres 揭秘:深度解析高效率分布式查问引擎(本文)
- Hologres 揭秘:通明减速 MaxCompute 查问外围原理
- Hologres 揭秘:如何实现 MaxCompute 与 Hologres 数据同步速度快百倍
- Hologres 揭秘:如何反对高吞吐 Upsert
- Hologres 揭秘:如何反对在线服务场景的超高 QPS
- Hologres 揭秘:如何反对高并发查问
- Hologres 揭秘:如何反对高可用架构
- Hologres 揭秘:如何反对资源隔离,反对多种负载
- Hologres 揭秘:向量检索引擎 Proxima 原理与应用实际
- Hologres 揭秘:读懂执行打算,查问性能翻十倍
- Hologres 揭秘:分布式系统如何设计 Shard 与 Table Group
- Hologres 揭秘:如何反对更多 Postgres 生态扩大包
- Hologres 揭秘:高吞吐写入 Hologres 的 N 种姿态
- ……