本文的撰写思路是在研读《PolarDB IMCI助力聚水潭数据中台极致体验,实现百亿级订单实时分析》的过程中产生的想法,作为一个对数据库基础概念与技术原理一窍不通的新人小白,该如何去学习了解数据库PolarDB的核心功能之一——IMCI列存引擎呢?
从一个客户案例入手是最快能够理解一个客户定位、客户需求、产品功能、使用场景乃至底层原理的方式。阿里是从电商起家的,相信网购大家都有体感,类似于雅诗兰黛、欧莱雅这样的零售大品牌,他们的线上线下运营的APP、电商平台有很大一部分都是由零售的SaaS服务商去提供技术服务的,聚水潭就是其中之一。
聚水潭客户案例
【聚水潭是聚石塔零售SaaS服务商的头部客户之一,聚水潭对接300+线上平台渠道,服务商家超80万,2020双11季全网处理订单总量达8.52亿,现在,全国电商每发出5-6个包裹中就有1个来自聚水潭系统。
当前,聚水潭使用的阿里云数据库实例超2000个,这些实例用于以SaaS ERP为核心的胜算、聚货通、云会计、淘跟单、聚工单等聚水潭全系列业务中,产品包括OLTP的PolarDB MySQL、RDS MySQL、SQL Server等,用于OLAP分析的ADB MySQL和ADB PG,通过产品和方案组合来满足聚水潭在电商SaaS ERP业务下的各种需求。】引自案例
至于什么是聚石塔?聚石塔本质上是为淘系SaaS类的商家后台系统的ISV提供一个稳定、安全、可监管的运行环境PaaS平台。具体请参考文章《聚石塔之涅槃重生——从1.0到2.0到3.0的演进~》,这篇文章已经非常详细地介绍了JST的演进和变化。
什么是数据中台?
数据中台是一套可持续“让企业的数据用起来”的机制,一种战略选择和组织形式,是依据企业特有的业务模式和组织机构,通过成熟的产品和实施方法论支撑,构建的一套持续不断把数据变成资产并服务于业务的机制。其底层逻辑是以数字化的手段,将数据抽像成服务,响应前端业务的快速变化。
数据中台一般会具备4个能力:数据采集整合、数据提纯加工、数据服务可视化、数据价值变现。
-
数据采集整合:创建企业数据中台第一步,打破企业内部各个业务系统的数据隔阂,形成统一的数据中心,为后续数据价值的挖掘提供基础。主要通过数据采集和数据交换实现。
-
数据提纯加工:主要是对数据统一标准、补充属性,然后根据维度汇总成数据表、最后汇总出所需要的报表,满足企业对数据的需求。
-
数据服务可视化:对数据进行计算逻辑的封装,生成API服务,上层数据应用可以对接数据服务API,让数据快速应用到业务场景中。数据服务API对接的3种常见数据应用包括数据大屏、数据报表、智能应用。
-
数据价值变现:通过打通企业数据,提供以前单个部门或者单个业务部门无法提供的数据服务能力,为赋能前端应用、数据价值变现提供基础。
什么是业务中台?
业务中台是以业务领域划分边界,形成高内聚、低耦合的面向业务领域的能力中心,打造持续演进的企业级业务能力共享服务平台。
业务中台的直观呈现就是各能力中心,以互联网电商为例,常见的有交易中心、商品中心、库存中心等。它不仅提供丰富的共享服务,还包含体系化建设企业能力域的方法和机制。业务中台不仅是生产上层应用的开发设计平台,也是配置、编排和扩展业务对象、业务能力、业务规则及业务流程,完成企业资源运营管理的平台。它为上层应用系统的稳定运行提供了高并发、高可用的执行环境。
为什么需要业务中台?
在信息化时代的早期,由于业务较为单一,企业IT系统建设的问题并未暴露。但到了中后期,随着企业规模和业务的快速扩张,为了快速支撑业务的管理和运营,各业务部门只能并行开发各自的业务系统。这种做法虽然在当时解决了企业的燃眉之急,但从长远来看,企业的数字能力资源就被隔离在多个独立的IT系统内。这些数字能力资源既无法跨系统、跨业务赋能,也无法让所有业务数据实现实时共享和调用。
业务中台不是前台应用?
前台应用包含两大部分:前台交互界面和前台应用服务。前台应用服务是指为前台交互界面提供后端服务接口的功能单元集合。业务中台一般不直接面向前台界面,而是面向前台应用服务,为其提供共享的服务接口。前台应用服务提供的功能具有应用局限性和特殊性,它一般是完成某一个特定业务场景所需的功能。相比而言,业务中台完成的则是多个业务场景的通用部分,以及挂载和执行面向特定前台业务的扩展功能。通常来说,前台应用服务会根据前台业务场景的特殊需要,将中台能力进行编排、转换后再提供给前台界面使用。
PolarDB如何帮助聚水潭实现数据中台?
数据大屏
可视化实时查看今日销售数据、销售金额、销售排行、各个省市销售情况、实时发货速度等等,直观、全面的了解到每天的销售、发货情况,同时可以更快、更精准地发现问题,防控风险,提高管理的时效性
发货预警
查看整体的发货进度和不同发货仓今日、昨日支付未发货的订单情况,点击【更多发货分析】后可以进一步跳转进入【物流实时预警】模块。【物流实时预警】功能,快速定位发货和揽收快超时、物流信息未更新等或有赔付风险的订单,内外部及时沟通协调,以保障好峰值几十万订单的顺利发出,预防资损。商家反馈依靠这个功能,减少了不少的平台的延迟发货处罚。
IMCI列存引擎
IMCI(In-Memory Column Index)列存引擎,是在已有MySQL行存表Btree索引的基础上,扩展列存形式的索引,从其名称中也不难看出,行列索引共享了基础表的数据,从而让普通的MySQL表具备了同时支持行列场景的查询需求,可以称得上是行列共存表,列存索引特性在PolarDB MySQL引擎中的功能架构图如下:
PolarDB在存储引擎、执行算子、优化器三个层面设计了列存索引的特性:
-
存储引擎: 支持实时事务级别一致性的行列混合存储;
-
执行算子: 面向列存的向量化并行执行算子,支持极速的单表和多表查询;
-
SQL Parser/优化器: 面向行列混合存储的CBO优化器,可以根据代价自动选择行存或者列存执行查询请求
Q1:按行存储与行存索引有什么区别?
A1:从概念上理解两个名词是不一样,一个是数据存储的方式,一个是数据的索引结构,但是本质是按照行在数据库表中去存储数据,当调取数据的时候用的是行存索引。
-
行存索引是指数据库表中对每一行数据都建立一个索引,以便快速查找和访问该行数据。这种索引通常是基于B树或哈希表实现的。
-
按行存储是指数据库表中的数据按照行的方式存储,每个行都是一个完整的数据单元,包括该行的所有列。这种存储方式相对于按列存储来说,更适合于事务处理型的应用场景,因为在事务处理中通常需要操作整个行的数据。
拓展:Hash索引和B+Tree索引有什么区别?
-
存储结构不同:Hash索引使用哈希表来存储索引信息,而BTree索引使用B树来存储索引信息。哈希表是一种快速查找的数据结构,通过将关键字映射到索引位置进行查找,速度非常快。而B树是一种平衡树,它能够快速定位关键字所在的位置。
-
查询方式不同:Hash索引使用等值查询,只能够用于精确查找。而BTree索引可以进行范围查询、排序等多种查询方式。
-
内存占用不同:Hash索引需要占用大量的内存空间,因为所有的索引信息都需要存储在内存中。而BTree索引可以在内存中存储部分索引信息,其余部分可以存储在磁盘上。
-
处理冲突方式不同:Hash索引在处理哈希冲突时,采用的是链表方式。而BTree索引在处理索引冲突时,采用的是分裂节点的方式。
Q2:行存和列存的索引结构是存在计算节点的缓存还是存在本地盘、云盘?
A2:行存和列存的索引结构都可以存在计算节点的缓存、本地盘、云盘等不同的存储介质中,具体取决于数据库系统的实现方式以及应用场景的需求。一般OLTP行存数据库通常会将索引结构存储在计算节点的内存中,以保证查询速度的快速响应;对于大规模数据仓库和数据分析OLAP场景,列存数据库通常会将索引结构存储在本地或者云盘中,以支持海量数据的高效查询和分析。
对于PolarDB MySQL引擎来说,索引是存储在存储物理层。PolarDB主要是以行存为主,为了HTAP能力支持在计算节点内添加列存引擎,在底层存储用Redo Log物理日志同步一份数据。
Q3:行存和列存是否是一份数据存了两份,按照不同的存储结构存在磁盘?
A3:3+3(行存3份列存3份——三副本)HTAP数据库中,行存索引和列存索引并不是简单地将同一份数据存储在不同的存储结构中。相反,它们采用了不同的数据组织方式来适应不同的数据查询和分析需求。
具体来说,行存索引是针对传统的OLTP(在线事务处理)场景而设计的,它使用基于B+树或哈希等结构来组织数据,以支持高效的数据添加、修改和删除操作,并且通常只关注少量的列,查询速度相对较快。而列存索引则是为了应对大规模的数据分析场景而设计的,它使用基于列的存储方式来组织数据,以支持高效的数据扫描和聚合操作,并且通常涵盖更多的列,查询速度相对较慢但可处理更大规模的数据。
因此,行存索引和列存索引之间并不是简单的数据复制关系,而是采用了不同的数据组织方式来适应不同的查询和分析需求。同时,在实际应用中,数据可能会同时存在行存和列存中,以便同时满足OLTP和OLAP(在线分析处理)等多种需求。
PolarDB如何助力聚水潭搭建实时数仓?
聚水潭的实时数仓用的是Flink+PolarDB的实时数仓的架构。
优势:
增加组合索引的方式可以满足基本统计需求,但是对于复杂多维度统计要枚举支持各类型的查询条件,初步预估都需要不小于10个索引,况且这里还提供了类似<、>、like等谓词,此场景下,传统的MySQL Btree索引就无法支持了。PolarDB利用IMCI做到单表模式支持HTAP混合负载。
解释:数据仓库分层
HTAP数据库解决方案演进
v1.0 MySQL+专用AP数据库的搭积木方案
架构:使用两套系统来分别满足OLTP和OLAP型需求,在两套系统中间通过数据同步工具进行数据实时同步。用户甚至可以增加一层proxy,自动将TP型负载路由至MySQL数据库,而将分析型负载路由至OLAP数据库
优点:TP/AP数据库可以分开选择选择最好的方案,实现了TP/AP负载的完全隔离,具有灵活性
缺点:维护两套不同技术体系的数据库系统,由于两套系统处理机制的差异,维护上下游的数据实时一致性非常具有挑战,数据同步DTS有延时,下游AP系统存储的经常是过时的数据,导致无法满足用户实时分析数据的需求
v2.0 基于多副本的Divergent Design方法
新型分布式数据库成为替代MySQL,大部分采用的是分布式Share Nothing的方案。核心特点是使用分布式一致性协议来保障单个partition多副本之间的数据一致性。由于一份数据在多个副本之间完全独立,因此在不同副本上使用不同格式进行存储,来服务不同的查询负载是一个易于实施的方案。例如,TiDB从TiDB4.0开始,在Raft Group的其中一个副本上使用列式存储(TiFlash)来响应AP型负载,并通过TiDB的智能路由功能来自动选取数据来源。实现了一套数据库系统同时服务OLTP型负载和OLAP型负载。该方法在诸多Research及Industry领域的工作中都被借鉴并使用,并日益成为分布式数据领域一体化HTAP的事实标准方案。但是应用这个方案的前提是用户需要迁移到对应的NewSQL数据库系统,而这会出现各种兼容性适配问题。
v3.0 一体化的行列混合存储方案(行列混合存储结合内存计算)
较多副本Divergent Design方法更进一步的方案,是在同一个数据库实例中采用行列混合存储,同时响应TP型和AP型负载。这是传统商用数据库Oracle、SQL Server或DB2等不约而同采用的方案。
列式存储中索引稀疏导致的索引精准度问题决定它不可能成为TP场景的存储格式,但在行列混合存储架构中,行存索引和列存索引在处理随机更新时存在性能鸿沟,必须借助DRAM的低读写延时来弥补列式存储更新效率低的问题。因此在低延时在线事务处理和高性能实时数据分析两大前提下,行列混合存储结合内存计算是唯一方案。
动态随机存取存储器(Dynamic Random Access Memory,DRAM)是一种半导体存储器,主要的作用原理是利用内电容存储电荷的多寡来代表一个二进制比特(bit)是1还是0。由于在现实中晶体管会有漏电电流的现象,导致电容上所存储的电荷数量并不足以正确的判别数据,而导致数据毁损。因此对于DRAM来说,周期性地充电是一个无可避免的要件。由于这种需要定时刷新的特性,因此被称为“动态”存储器。相对来说,静态存储器(SRAM)只要存入数据后,纵使不刷新也不会丢失记忆。
PolarDB上如何优化MySQL引擎
MySQL的架构在AP场景的存在的问题
MySQL的实现架构在执行复杂查询时,性能差存在诸多原因。对比专用的OLAP系统,其性能瓶颈体如下:
-
MySQL的SQL执行引擎基于流式迭代器模型(Volcano Iterator),而这个模型在工程实现上依赖大量 深层次的函数嵌套及虚函数调用 ,当处理海量数据时,会影响CPU流水线的Pipeline效率,导致CPU Cache效率低下。同时Iterator执行模型也不能使用CPU提供的SIMD指令来做执行加速
-
执行引擎只能 串行执行 ,不能发挥多核CPU的并行执行能力,复杂SQL的并行执行能力不够
-
在按列进行海量数据分析时,按行存储在读数据存在非常大的IO带宽浪费,其次会大量拷贝不必要的列数据,对内存读写效率也存在冲击
拓展:
关系型数据库通常使用以下三种迭代器模型:
-
元组迭代器模型(Tuple Iterator Model):这是最基本的迭代器模型,它对关系中的每个元组进行迭代。该模型适用于简单的查询,并且可以被其他迭代器模型所使用。
-
关系迭代器模型(Relation Iterator Model):这个迭代器模型基于元组迭代器模型,它对关系进行迭代,并针对关系的属性进行处理。该模型适用于处理关系之间的连接、过滤和投影等操作。
-
流式迭代器模型(Volcano Iterator):这是一种高级迭代器模型,它将查询分解为一个个小的操作元素,并通过迭代器进行流式处理。每个操作元素都是可重用的,可以被多次使用,这样可以降低系统开销,并提高查询执行的效率。流式迭代器模型的优点在于它的扩展性和灵活性,但也需要较高水平 的技术支持。
Volcano Iterator:
流式迭代器模型是一种用于查询执行的迭代器模型。它是由David Maier于1989年提出的,被广泛应用于关系型数据库管理系统和其他数据处理系统中。
在流式迭代器模型中,查询被分解成一个个小的操作元素,并通过迭代器进行流式处理。每个操作元素都是可重用的,可以被多次使用,这样可以降低系统开销,并提高查询执行的效率。
流式迭代器模型的优点在于它的扩展性和灵活性。由于每个操作元素都是可重用的,系统可以根据实际的需求来动态地构建查询执行计划,从而适应不同的查询场景。此外,流式迭代器模型还可以支持多个查询并发执行,提高系统的吞吐量。然而,流式迭代器模型也存在一些缺点。由于每个操作元素都是可重用的,因此系统需要额外的开销来维护这些元素的状态。此外,流式迭代器模型对查询优化器和执行引擎的设计和实现要求比较高,需要较高水平的技术支持。
流式迭代器模型(Volcano Iterator)可能存在以下问题:
-
内存占用:流式迭代器需要缓存中间结果,可能会占用大量内存空间,特别是在处理大数据集时。
-
性能问题:流式迭代器的中间结果需要在内存中缓存,这可能会导致频繁的磁盘读写或内存交换,从而影响性能。
-
可扩展性问题:流式迭代器模型只适用于单机场景,无法很好地扩展到分布式环境中。
-
代码复杂度:实现流式迭代器需要编写复杂的代码,包括处理迭代器状态、缓存中间结果、处理异常等。
-
维护难度:由于流式迭代器的状态需要在迭代的不同阶段中维护,因此代码的维护和调试可能会比较困难。
PolarDB如何解决这些问题
并行查询:并行查询框架(Parallel Query),在查询数据量到达一定阈值时,会自动启动并行执行。在存储层将数据分片至不同的线程,多个线程并行计算。并将结果流水线汇总到总线程。最后,总线程做些简单归并返回给用户。
——突破了CPU扩展能力的限制,但是受限于行式存储及行式执行器的效率限制,单核执行性能存在天花板,其峰值性能依然与专用的OLAP系统存在差距。
列式存储:按列存储(Column-Store),在分析场景会需要频繁访问某个列的大量记录,列存可以避免读取不需要的列;列存由于把相同属性的列连续保存,压缩效率更高,通常可以达到10倍以上;列存中的大块存储结构可以结合MIN、MAX等粗糙索引信息,实现大范围的数据过滤。
——极大的提升了IO的效率。在存储计算分离架构下,减少网络读取的数据量,可以缩短对查询处理的响应时间
列式存储同样能提高CPU在处理数据时的执行效率。首先,列存的紧凑排列方式可提升CPU访问内存效率,减少L1/L2 Cache miss导致的执行停顿。其次,在列式存储上可以使用SIMD技术进一步提升单核吞吐能力,这也是现代高性能分析执行引擎的通用技术路线(Oracle/SQL Server/ClickHouse)。
PolarDB IMCI 技术架构
技术创新
-
列存索引:在InnoDB的基础上,新增列式索引(Columnar Index),通过DDL将一张表的全部/部分列创建为列索引,列索引采用列压缩存储,其存储空间消耗会远小于行存格式。默认列索引会全部常驻内存以实现最大化分析性能,当内存不够时,也支持将其持久化至共享存储。
-
并行执行 :S QL执行器层一套面向列存的执行器引擎框架(Column-oriented),使用SIMD指令提升CPU单核处理数据的吞吐量,所有关键算子均支持并行执行。ePQ——弹性多机并行
-
SIMD 的全称是 Single Instruction Multiple Data,中文名“单指令多数据”,顾名思义,一条指令处理多个数据
-
-
S QL Parser: 根据下发的SQL是否能在列索引上执行覆盖查询,并且其所依赖的函数及算子能被列式执行器所支持,来决定是否启动列式执行。优化器会同时对行存执行计划和列存执行计划做代价估算,并选中代价较低的执行计划
-
多主多写:用户可以使用PolarDB集群中的一个RO节点作为分析型节点,在该RO节点上配置生成列存索引。复杂查询运行在列存索引上并使用所有可用的CPU的计算能力,在获得最大执行性能的同时,不影响该集群上TP型负载的可用内存和CPU资源。
如何实现?
行列混合的优化器:如何解析Query到行存还是列存执行?白名单机制+执行代价计算框架。
-
如何实现100%的MySQL兼容性? 通过白 名单机制,及时将列存查询Query切换回行存执行。
-
不是所有的数据都具有列存索引,没有列存索引的列数据查询无法在列存上执行(内存资源有限)。
-
列存SQL执行引擎 物理执行算子和表达式有限,面对超出范围的算子片段等等无法执行。
-
-
查询计划转换:通过遍历 执行计划树,将MySQL的原生逻辑执行计划表示方式AST转换/优化为IMCI的Logical Plan(以关系操作符为节点的树状结构)
-
兼顾行列混合执行的优化:优化器的执行有行存串行执行、行存Parallel Query和IMCI三种,从执行性能比较,IMCI优于行存并行执行PQ,PQ优于行存串行执行;从SQL兼容性比较,行存串行执行优于PQ,PQ优于IMCI。
-
执行SQL的Parse过程,并生成LogicalPlan,然后再调用MySQL原生优化器。同时该阶段获得的逻辑执行计划转给IMCI的执行计划编译模块后,会尝试生成一个列存的执行计划(此处可能会被白名单拦截并fallback回行存)
-
PolarDB的Optimizer会根据行存的Plan,计算得出一个面向行存的执行Cost。如果此Cost超过一定阈值,则会尝试下推到IMCI执行器并使用IMCI_Plan执行。
-
如果IMCI无法执行此SQL,则PolarDB会尝试编译出一个Parallel Query的执行计划并执行。如果无法生成PQ的执行计划,则说明IMCI和PQ均无法支持此SQL,fallback回行存执行。
-
-