从InfluxDB到MatrixDB -- 重新定义时序数据库

新时序,新定义

在时序数据库的世界里,InfluxDB一直是这个领域的No.1,多年在DB-Engines时序数据库分类中排名第一,可谓当之无愧的王者。然而,2020年底,InfluxDB官方宣称启动氧化铁项目,再造另一个时序数据库InfluxDB IOx,这也意味着即将战略性的放弃稳居数年的榜首产品InfluxDB。做过数据库的人都知道,从头写一个数据库是非常难且十分耗人耗时的事情,能把一个数据库做到行业内第一更是难上加难,InfluxDB做到这一点用了8年。这次行业老大自断双臂,重走长征路,是非常耐人寻味的。究其原因,随着物联网时代的到来,时序数据加速膨胀,无论数据规模还是应用场景,相比5到10年前,都发生了巨大变迁。5G普及带来千万级设备的实时监控和智能网管,互联亿级异构设备的智能家居场景需要处理频率、指标数量和质量均参差不齐的数据采集和分析,车联网、自动驾驶正在应对数千指标高频采集和实时决策,类似的场景和挑战在每个行业中都正在发生。当前所有时序数据库已经无法满足未来持续演进的趋势,从国王到民众,无一幸免。然而,国王终究是国王,比民众看的更长远。

InfluxDB深耕时序数据处理行业多年,见证了整个时序数据发展的历史。从最初的设备监控,扩展到日志采集、事件追踪、用户评论、甚至金融分析等等,无处不在。以历史的眼光看未来,InfluxDB创始人兼CTO Paul Dix描述了自己眼中的时序数据:

"all data you perform analytics on is time series data. Meaning, anytime you’re doing data analysis, you’re doing it either over time or as a snapshot in time."

可见,任何有分析需求的数据,都是时序数据,数据因时间的存在被赋予了新定义。 为了更好的分析新时代的时序数据,InfluxDB IOx列举了新一代时序数据库的设计目标: 时序13条

从上述"时序十三条",可以总结出:

  1. 时序数据库需要更好的扩展性以应对日益增长的数据总量和设备规模,同时尽量维持资源的合理开销。 PB级数据规模、亿级接入设备、单次采集上千万指标在很多场景中已经司空见惯,对时序数据库的分布式架构、存储引擎、资源管理机制提出了巨大挑战。
  2. 时序数据为分析而生。 不仅仅是过去用于仪表盘的简单聚合查询,也包括越来越多样化的复杂查询、基于历史数据的机器学习、模型训练,还会涉及到用内置高级语言进行数据分析,甚至通过开放的数据格式与生态其他数据库做联邦分析等等。从查询表达力和性能角度来看,时序数据库和分析型关系数据库的差异正在逐渐减少。
  3. 云边一体的趋势不可逆。 数据库向云原生演进,最大化边缘侧的算力,设计高效的云边数据协同,是新一代时序数据库的必选项。

InfluxDB IOx将自己定位为面向分析的列存数据库,而不仅仅是原有专用时序数据库。InfluxDB IOx为了更好满足设计目标,采用Rust语言,尽可能复用开源组件。架构上采用存储计算分离,所有状态持久化到对象存储,保证计算资源调度的灵活性。存储引擎采用Apache Arrow + Parquet的经典组合,回归关系模型,通过列式存储、稀疏索引降低存储开销。计算引擎核心采用Data Fusion,查询接口兼容标准SQL,优化器和执行器泾渭分明。由此可见,InfluxDB IOx和分析型关系数据库已经没有本质区别了。

从InfluxDB到InfluxDB IOx的演变可以看出下一代时序数据库应该是这样的:

  1. 首先,它必须是一个面向分析的数据库。原有简单的时序聚合查询已经远远无法满足越来越复杂的时序场景,需要应对大规模数据、复杂查询、高性能的数据库,这正是OLAP数据库积累数十年的精华所在。
  2. 其次,在OLAP数据库基础上,除了要征服时序数据与生俱来的数据加载、查询性能和存储成本的三座大山,还要进一步解决日益突显的海量设备规模所带来的High Cardinality问题。
  3. 最后,数据库要成熟稳定,简单易用,无需像大数据系统一样动辄雇佣一个加强排的人力去维护。

无独有偶,MatrixDB,作为超融合时序数据库的开创者,从诞生之初就秉承一切数据都为分析服务的目标,在关系数据库的基础上,通过更好的支持时序数据,以做加法的方式立足新一代时序数据库。这与原有时序数据库或大部分NoSQL,通过在关系数据库上做减法,单独为时序数据而定制优化的思路有本质不同。InfluxDB IOx用实际行动和MatrixDB走到同一条道路上。但是,与InfluxDB IOx从头开始写一个更好的支持时序数据的分析型数据库所不同的是,MatrixDB选择站在巨人的肩膀上,基于PostgreSQL在关系数据库上几十年的积累和沉淀,通过其优秀的扩展机制增强分布式架构、存储引擎和计算引擎的能力,将时序数据处理面临的问题在关系数据库核心引擎里完美解决。

重温经典,站在巨人的肩膀上

自上世纪70年代起,关系数据库诞生,一直到2000年互联网兴起前,都是解决所有数据处理问题的瑞士军刀,精致而简洁。互联网的繁荣使得数据量加速膨胀,关系数据库扩展性差的缺点被显著放大。为了解决扩展性问题,一部分选择了保留关系数据库核心能力,采用分库分表结合中间件的方案做替代。另一部分选择放弃制约关系数据库扩展性的关系模型和事务支持,将数据间原本固有的约束和关联关系从数据库转移给应用,这样即无需再支持标准SQL、Schema、ACID、优化器这些关系数据库的核心要素,通过极简设计换取最大的扩展性和性能,即所谓的NoSQL。NoSQL无疑是成功的,因为它满足了当时大数据最迫切的海量数据写入性能和存储问题,在包括时序在内的各个场景遍地开花,OpenTSDB、InfluxDB等优秀的时序数据库都是典型的NoSQL。然而,数据终将是需要通过分析体现价值的,尤其是数据量逐渐增大,更是需要复杂的分析来挖掘大数据中潜在的关联价值。分析能力的弱化是所有NoSQL的通病,这是放弃关系模型所必须付出的代价。

时代向前,技术进步,关系数据库也在分布式的道路上探索前行。MPP架构的OLAP数据库是大数据分析的标配,NewSQL的提出将关系模型的扩展性问题得以解决,所有这些在关系数据库能力边界的技术拓展都成为了构建下一代时序数据库的基石。

MatrixDB以关系数据库经典理论为基础,在实践中并没有重新造轮子,而是采用PostgreSQL,世界上最高级的开源数据库为核心引擎。之所以选择PostgreSQL,主要是因为其功能完备、稳定可靠、组件化、扩展能力强。MatrixDB基于PostgreSQL提供的扩展机制,针对时序场景数据的特征,对分布式架构,存储引擎,计算引擎和资源管理进行全方位的时序化。

分布式架构

分布式架构

MatrixDB的分布式架构起源于Greenplum,一款基于PostgreSQL的面向分析型场景的MPP(Massively Parallel Processing)数据库。MatrixDB采用Share Nothing的主从架构,每个节点均是一个完整的PostgreSQL数据库实例,主节点Master负责集群元信息管理,接收客户端请求,进行查询解析和查询计划生成。从节点Segment负责数据的分布式存储和查询执行,查询执行过程中数据交换由高速网络组件Interconnect负责。MatrixDB除了具有大数据存储和分析能力外,还包括如下特性:

  1. 高性能。高速数据加载,分布式并行查询执行,对于数据读写均提供极致性能
  2. 高可用。系统每个节点均有备份节点,任一节点失效后自动恢复,对业务透明
  3. 线性扩展。秒级在线动态扩容,数据自动平衡,无需人工干预
  4. 分布式事务。应对强一致性场景,保证数据不重不错不丢,减少应用负担
  5. 安全可靠。支持多种安全认证、访问控制机制,以及丰富的数据加密算法
  6. 数据联邦。无缝对接关系数据库、NoSQL、大数据生态主流产品,无需移动数据进行联邦查询分析
  7. 生态完善。覆盖数据迁移,备份恢复,BI分析等上下游工具链

MatrixGate组件用于时序场景下流式数据并行加载,提供HTTP接口,可接收上万客户端同时并发写入,既保证毫秒级延迟,又保证数据加载过程中事务的强一致性。

存储引擎

存储引擎

存储引擎是数据库的底层基础组件,决定了查询引擎如何高效访问数据。时序数据是设备在不同时间点产生的数据,从存储的角度来看,尽可能保证时序数据在时间(Time)维度和设备(Tag)维度的局部性(Data Locality),将有利于时序数据的查询。MatrixDB的分布式存储引擎,提供多种机制来优化数据的局部性,尽可能让同一设备连续时间的数据,在同一机器、同一数据库表、以及表内连续存储。

分布式环境下,数据分片(Sharding)是解决单机存储空间和资源限制的主要策略。MatrixDB通过对一个表定义分布策略(Distribution Policy)来进行数据分片,分布策略包括:哈希分布、随机分布、复制分布。在时序场景中,通常按设备标识对时序表做哈希分布,哈希分布的好处是将相同设备的数据存储到同一个Segment节点上。数据分布策略是在节点级别保证设备数据的局部性。

在数据分片的基础上,对时序表进行更细粒度的数据分区(Partitioning),有利于在查询执行中进行分区裁剪(Partition Pruning),降低扫描的数据量。MatrixDB支持的数据分区策略(Partition Policy)包括:范围分区,列表分区,哈希分区。在时序场景中,按时间范围进行数据分区,一方面可以在时间维度上保证数据的局部性, 另一方面,时序数据通常具有冷热特征,按时间分区更适于对数据做生命周期管理。另外,MatrixDB支持多级分区以提供更极致的数据局部性。 例如,按时间做一级分区、设备做二级分区,极端情况下,每一个时间段一个设备一张分区子表,达到设备和时间两个维度上最佳的数据局部性,代价是创建更多的分区表,进而对表管理带来负担。

确定数据分片和分区策略后,接下来是设计每一个分区子表的存储策略,参考依据包括

  • 数据组织方式:行存、列存,还是行列混存
  • 存储格式:面向行存的HEAP,还是面向列存的存储格式,或是PAX格式如Parquet、ORC等
  • 索引类型:选择BTREE索引、范围稀疏索引,还是倒排索引,甚至自定义索引
  • 编码压缩方式:不同数据类型如何确定最佳编码,压缩算法选择压缩比优先还是速度优先

MatrixDB具有多态存储特性,支持为分区表的每个子表定制不同的存储策略。时序场景中,冷热数据由于访问模式不同,对存储策略的需求也不同。

热数据对应时间较近的数据,用分区表中时间段最新的分区存储,对存储策略的需求是

  • 写入性能一定要好,优先保证时序数据的加载能力
  • 热数据价值密度高,分析需求强,查询类型包括最新值点查、时间范围明细查询,以及按时间段和设备聚合查询等
  • 热数据占数据总量比重小,压缩需求不强烈,但可能伴随潜在的修改删除,以及乱序写入情况

因此采用行存HEAP表+BTREE索引更适合。HEAP表提供高速数据加载性能,且不对数据写入顺序做要求,同时对修改删除友好。BTREE索引与数据分离存储,一方面可以加速加载性能,因为时序数据顺序写入HEAP表,索引仅为数据引用,维护代价小。另一方面分离带来灵活性的优势,为不同访问需求的列创建不同索引,如创建设备+时间的组合索引,相当于利用索引精确组织每个设备逻辑上的数据局部性, 进而加速相应查询性能。

冷数据对应历史数据,用分区表中除最新分区外的其他分区存储,对存储策略的需求是

  • 历史数据占数据总量比重高,且随时间持续增长,对存储空间敏感
  • 查询主要为聚合分析查询,几乎无点查需求
  • 历史数据无修改更新需求,某一时间点后统一进行生命周期管理

MatrixDB针对时序历史数据特征设计了全新的MARS(Matrix Append-optimized Resilient Storage)存储引擎,存储格式为行列混存,每一个行列分组单元为一个RowGroup,包括一个设备一个时间段按时间排序的全部数据,RowGroup是在分区表基础上保证每个设备时序数据的物理局部性。 RowGroup内设备数据按列组织,一个列组为一个Chunk,Chunk在分组内保证具有相同数据类型的单列数据的局部性。

MARS存储引擎极致的保证时序数据局部性有很多好处。首先,Chunk内列数据的局部性有助于编码压缩,同一列数据类型相同压缩比高。MARS针对不同时序类型选择最适合的编码方式,time列采用delta编码,浮点数采用Gorilla编码,压缩算法支持ZSTD、LZ4等,对于典型时序数据,压缩比可达1:10。 其次,RowGroup根据设备数据局部性,可以预先计算好RowGroup内每个列的常见聚集信息,如COUNT、MIN/MAX、FIRST/LAST、SUM等,对于聚合查询,智能的根据查询条件直接获取预聚集结果,避免直接遍历计算每一个原始数据点,大幅提升查询性能。最后,预聚集信息中MIN/MAX可以做为稀疏索引,替代空间占比高的BTREE索引。在带过滤条件的查询中,快速过滤不在(MIN,MAX)范围内的RowGroup,进而大幅降低IO开销。在可能的候选RowGroup中,因为设备数据已经排好序,通过二分查找可以快速定位到具体的行,如果是范围型查询,后续根据有序性来进行顺序扫描即可。MARS存储引擎的稀疏索引,在点查、范围型查询的性能上接近BTREE,但空间开销仅为BTREE的百分之一甚至千分之一。

对于时序数据的生命周期管理,MatrixDB提供自动分区管理机制,包括自动创建热数据分区,自动冷热分区转换,历史数据过期自动删除(Data Retention)等,全程无需任何人工参与,应用只需将数据写入数据库即可。

计算引擎

计算引擎

计算引擎由优化器和执行器组成,MatrixDB优化器基于代价模型,在Master节点生成分布式查询计划,分发给所有Segment并行执行。分布式查询计划进行最大粒度的拆分,每个拆分的查询计划片段均可以在Segment上由一组独立的QE(Query Executor)进程执行,查询计划片段之间通过网络进行数据传输,最终将并行执行结果汇总到QD(Query Dispatcher)进程并返回给用户。MatrixDB MPP查询引擎的优势是在最大化切分查询计划的基础上,充分调用所有集群资源,以达到最佳的查询性能。

针对时序场景, MatrixDB计算引擎充分感知存储引擎的数据局部性,提供多种优化策略。对于典型的时序查询,常规优化器和面向时序优化的查询计划分别为: 查询优化

常规查询计划的执行流程为,通过时间过滤条件确定时序数据表的子分区表集合,依次遍历每个子分区表,收集每一个符合过滤条件的元组,执行分组排序,最终返回结果。其中,过滤条件可通过为time列建立BTREE索引加速访问。这种查询执行方式有如下问题:

  • 资源开销大。大量执行时间在扫描和分组排序操作上,扫描导致IO资源开销,分组排序导致CPU和内存资源开销,如果数据量过多,会导致外排序引起的额外IO。
  • 索引空间大。为了快速定位符合时间过滤条件的元组,需要在时间列建立BTREE索引,空间开销大,如果不用BTREE索引,则需要进行全表扫描,IO代价大。
  • 时序场景中,此类查询通常反复执行,唯一变化的是时间过滤条件,反复执行时,相同分组的聚集计算导致大量重复操作,造成资源浪费。

针对以上问题,MatrixDB查询优化器会充分感知数据分布特征和数据局部性,对于涉及MARS存储引擎的分区表,自动应用聚集下推优化。执行流程为,在每一个符合时间过滤条件的子分区表,通过MARS稀疏索引快速定位查询涉及的分块列表,对于块内元素都符合条件的分块,直接获取分块预聚集结果作为该分组的聚集结果,对于块内元素部分符合条件的分块,通过二分查找确定条件边界,然后顺序扫描完成分组计算。整个执行过程最大化节约了CPU、IO和内存资源,保证系统更大的扩展性和并发能力。

MARS存储配合聚集下推在时序冷数据的查询性能和资源开销均达到了最优效果。然而,聚集下推并不能在全部场景发挥效果,例如:

  • 时序热数据采用HEAP存储,数据的局部性是通过BTREE索引间接维护的,没有物理分块策略,因此无法直接计算预聚集信息
  • 当涉及非常见的聚集类型,如每个分组的DISTINCT值,或业务变更导致分组规则改变,如时间分组单位不是预定义分组单位的整数倍,则无法直接利用现有预聚集信息

MatrixDB针对此类场景,设计了持续聚集功能,用户可以在时序表上定义感兴趣的持续聚集视图,视图中包括用户指定的聚集函数。当数据持续加载到表的过程中,聚集查询在后台持续运行,当用户想获取时序表的对应聚集结果时,直接查询持续聚集视图即可,最大程度避免了重复计算。当聚集需求在某个时间点消失时,直接删除持续聚集视图,对原始数据无任何影响。

除时序聚合查询外,还可能会涉及到一些为了模型训练而进行的复杂分析,如与其他数据表进行关联操作,与其他外部数据源数据,如HDFS、Hive、PostgreSQL进行联合查询,查询中还可能涉及大量文本搜索、地理数据处理等。MatrixDB对于复杂查询提供丰富的功能和组件:

  • 支持现代SQL从SQL-1992到SQL-2016标准的各种高级特性,如嵌套子查询、递归CTE、窗口函数等。
  • 丰富的类型系统和索引能力,如文本类型、JSON类型、ARRAY类型,GIS类型,以及类型对应的高效索引方式,如倒排索引、通用搜索树索引等
  • 以半结构化数据类型为主的时序场景定制的KV类型,无需预先定义Schema,列数无上限,且压缩比和查询性能大幅优于JSON和JSONB类型
  • 支持与多种外部数据源进行联邦查询,如Hadoop生态HDFS、Hive、HBase等,关系型数据库PostgreSQL、MySQL、Oracle等,以及NoSQL数据库如MongoDB、Redis等

同时,对于复杂查询,通常涉及大量数据的复杂运算,MatrixDB除了提供丰富的功能支持外,还提供自适应并行计算引擎,充分利用多核等硬件资源来加速查询。MatrixDB优化器根据查询特征智能的决定查询执行的并行度,如查询涉及的数据量、进程间通信代价等。确定并行度后对数据进行动态分片,通过每一个算子的并行执行,最大化资源使用,从而进一步提升查询性能。并行查询执行在涉及关联、聚集等计算密集型操作时效果尤其明显。复杂查询和并行计算的支持,使得MatrixDB可以在典型时序场景之外,更好的胜任OLAP分析型场景。

资源管理

针对时序场景,通过对存储引擎和计算引擎的精细化设计,使得资源开销得以最大化节约。

  • 存储资源方面,通过类型定制的编码压缩,整体数据压缩比1:10,索引压缩比1:100。多态存储机制更是支持将存档类历史时序数据从数据库转移到更廉价的存储系统,如HDFS、S3等,进一步降低数据库存储开销而不影响任何业务查询。
  • 内存资源方面,无论是数据加载还是查询执行,内存开销均不与设备规模有关,系统根据查询计划和可用资源自动为每个算子分配合适的内存,在达到查询性能最优的同时,很好的解决了当前主流时序数据库面临的High Cardinality难题。
  • CPU和IO资源方面,极致的压缩比降低了查询时的IO开销,聚集下推和持续聚集通过减少重复计算节约CPU和IO资源,提升系统查询性能和扩展能力。
  • 网络资源方面,在数据加载过程中,对数据传输时进行压缩,进一步提升网络资源利用率。

对资源管理全方位细粒度控制和优化,使得MatrixDB除了获得更好的扩展性和并发能力,也可以满足大部分OLTP场景的需求。

不忘初心,砥砺前行

站在巨人的肩膀上,通过精巧的设计,MatrixDB可以优雅的解决时序数据库面临的全新挑战。然而,这仅仅是开始,不断提升应用开发效率,简化运维负担,持续满足不同场景对数据处理的需求,不再需要用复杂技术栈解决通用大数据问题,让大数据处理回归简洁高效,是MatrixDB一直追求的目标,也是超融合数据库理念创立的初衷。

最后,也许是某种巧合,Influx表示流入,是数据随时间单向传递。Matrix表示矩阵、是汇聚,更看重数据随时间不断融合到一起,来分析数据之间纵横交错的关联。时序数据库终将是数据处理通道中的一个节点,还是终点,是一个开放性的问题,但我们更愿意相信是后者,即使这条路走起来很坎坷,很漫长。