国产开源数据库赛道又有了新玩家。近日,一体化实时 HTAP 开源数据库 StoneDB 宣布正式开源。以下内容源自 StoneDB 首席架构师、StoneDB PMC 李浩的演讲。
在 2014 年,Gartner 给出了 HTAP 的严格定义,其目的是为了打破事务型负载和分析型负载之间的壁垒,使系统能够支持更多的“数据”在两个系统之间流动,以及以这些数据为基础的 “实时业务”的决策。
回到 Gartern 所提出的问题的本源:我们来探讨一下 HTAP 此类架构的本源动力是什么?传统架构形式下,为了解决同时处理 TP 负载和 AP 负载的问题,通常采用一套 TP 系统加上一套 AP 系统的方式,TP 和 AP 之间通过 ETL 或是 binlog 等方式进行数据同步来满足业务对实时性的需求。该种方式下,我们认为存在以下几个问题:
(1)系统复杂,带来维护成本增加;
(2)涉及到众多技术栈,对技术人员要求较高;
(3)TP 数据通过 ETL 等方式同步到 AP 系统中,导致数据延时较大,数据的时效性差,难以满足业务对分析的实时性要求。
随着技术的发展,用户需求和商业需求变得越发严苛,传统的方案已无法满足,HTAP 则提供了另外一种解决方案。由此带来业务架构的简化,更少的技术栈,更好的数据的实时性等优点。
当然,任何问题都具有两面性,在给用户和业务带来便利性的同时,也需要解决一些挑战。我们认为,HTAP 需要直面如下挑战,而这也是所有 HTAP 数据库所需要面临的。其中包括:
(1) 架构的选择:one system one copy Or one system two copies, Or tow systems tow copies;
(2) 数据的高效组织,当选定系统架构后,如何高效的组织数据使得在该种模型下,数据可以满足 TP、AP 的需求;
(3) 多类型负载的处理问题以及负载间的隔离问题;
(4) 负载响应时间;
(5) TP 负载中的变化数据需及时同步到 AP 中,即:解决数据的时效性;
(6) 快速的数据加载能力;
(7) 完整而全面的生态支持。
Stone DB 作为一款开源的 MySQL HTAP 数据库,其主要以下几个特点:
(1)完全兼容 MySQL,无论是语法还是生态,MySQL 用户均可以无缝切换至 StoneDB;
(2)事务、分析一体化,无需经过 ETL,事务型数据可实时同步到分析引擎。使得用户可以实时获取业务分析结果;
(3)完全开源;
(4)相较于 MySQL,StoneDB 提供 10-100 倍的 AP 能力,亿级多表关联,急速响应,决策结果无需等待;
(5)高效导入速度,由于 AP 场景下,所分析数据量巨大、高效的导入速度将给您带来良好的用户体验;
(6)1/10TCO 成本,高效的压缩算法,无缝的业务迁移能力,简单架构,都能为您带来 TCO 的降低。
StoneDB 采用一体化架构,并采用列式存储方式进行组织数据用以支持 AP 负载,结合高效压缩算法使得 StoneDB 在获得高性能的同时也具有存储成本优势。
同时,采用基于知识网格的近似查询及并行处理等机制,使得 StoneDB 在处理海量数据以及复杂查询时候,能够最大限度的减少无关数据的 IO,并利用直方图、数据块位图等众多统计信息来进一步的加速查询处理速度;此外,StoneDB 采用带有延后重构模型的 Column-at-a-time 的面向列式存储的执行引擎又进一步提高执行引擎的效率。最后,StoneDB 提供高速的数据载入能力。
上述技术的运用使得 StoneDB 有潜力成为一款优秀的 HTAP 数据库,当然为了进一步的提升在 HTAP 方面的能力,StoneDB 在 2.0 版本中将推出基于内存的 In-Memory Column Store(IMCS)。
与 TP 引擎多采用行式存储方案不同,AP 引擎多采用列式存储方案。与行存模型不同,列存模型是将数据按列的方式进行组织。StoneDB 采用,例如:lz4,bz2, zstd, snappy, zlib 等多达 20+以上的压缩算法来对数据进行压缩,从而来进一步减少查询处理过程中所需要的 IO。
查询处理作为整个数据库的大脑,查询优化算法好坏直接影响查询效率。为了使得 StoneDB 能够高效处理海量数据。我们首先再来讨论一下数据组织结构和知识网格。
在 StoneDB 中,数据以列的方式进行组织,在每个列中,数据又按更细粒度的数据块进行划分,这种方式所带来的优点有:
(1)物理数据按固定数据块进行存储,通常称之为: Data Node(或称为 Data Pack)。这样使得系统具有基于块(Block)的高效压缩/加密算法的能力;
(2)知识网格可以为查询优化器、执行和压缩算法等提供支持。例如:基于知识网格的查询,优化器会利用知识网格来决定需要抓取哪些 Data Node 来执行数据操作。
什么是优化器呢?优化器会利用知识网格对其所需要处理的数据进行剪枝:其采取的策略为:对于满足查询条件的数据节点称之为:关联性数据节点,对其采取直接读取并返回的策略;对于无法确定节点中是否存在满足查询条件的数据,我们将其称之为:对不确定性数据节点。对其采取的策略是:先进行解压,然后在进行基于查询条件的处理,最后返回处理结果;而对与查询条件完全不相关的数据节点,则直接忽略。
举例来说,对于一个查询请求,通过 KG(知识网格)可以确定 3 个关联性 DN 和 1 个不确定性 DN。如果该查询请求中包含聚合函数,此时只需要解压不确定性 DN,并计算该节点中满足条件的数据的聚合值,再结合 3 个关联性 DN 中元数据节点(Metea Node,MD)上的统计值即可得出最终结果。如果此请求需要返回具体数据,那么无论关联性 DN 还是不确定性 DN,都需要读取数据块并解压缩,以便获得最终结果集。
随着硬件技术的发展,硬件的红利也慢慢传递到数据库领域,随着 CPU 对向量化执行的支持。如今像 SIMD 指令已经广泛的应用在数据库中,用来提升执行效率。
传统火山模型采用迭代式进行数据处理,通过调用 next()函数来获取下一条记录并进行处理。该种方式下,需要产生大量的函数调用,上下文切换等等问题。因此,越来多的数据库均提供基于 SIMD 指令的向量化执行能力,用以加速执行。除了 SIMD 指令的应用,为了发挥当前 CPU 的多核能力,并行查询也是一个查询效率的倍增器。
数据的加载对于用户的体验也至关重要,通常我们需要处理的数据量非常大。为了给用户提供急速的数据加载体验,StoneDB 在数据加载方面也做了大量的工作。StoneDB 在数据加载时,数据首先在外部完成预处理,随后直接使用二进制的模式进行导入,无需通过转换为 SQL 文本来表达数据,从而避免 SQL 解析、数据验证等操作过程对服务器造成性能冲击。
我们刚才讨论了 StoneDB ver 1.0 的架构及相关技术。虽然 StoneDB On-Disk Column Store 在 AP 场景下的表现已经非常出色,但是毕竟其是基于磁盘的解决方案。IO 和内存在数据库领域又属于极度宝贵的资源,其通常为整个数据库系统的瓶颈所在。为进一步提升 StoneDB 性能,同时也为了减少 AP 负载在执行时候对于 TP 负载的影响,而这也是我们在前面所讨论的 HTAP 所需要面临的挑战之一。
我们在 ver 2.0 中将推出了类似于 Oracle Heatwave 架构形态的基于 In-Memory Column Store 引擎的全新架构-ver 2.0,该版本将基于 mysql 8.0 构建。基于此引擎我们将实现 AP 负载的全内存计算:
(1)数据在内存中组织方式;以列存方式进行组织,同时包含元数据。元数据部分包括了:数据量,列的数量,行列的映射关系,事务信息,数据分布情况等相关元数据;
(2)数据加载的方式,由 InnoDB 并行加载至 In-Memory Column Store 中;
(3)数据的更新问题,当我们 TP 中的数据发生变化的时候,如何实时更新到 AP 中。同时,更新机制及更新时机;
(4)内存中数据持久化的问题及系统 Recovery 的问题。为了使得系统在 crash 时,能够更快速的完成 Recovery 的过程,in memory 中的数据将会被持久化到我们的 on-disk column store 中。
StoneDB 将提供导入行为的监控能力,实时感知加载进度,在加载过程中通过非阻塞,无锁机制来实现高性能数据 load 能力。
基于代价的新查询引擎也将是 ver 2.0 的重点工作。一个负载透明、且具有更加高效、准确的代价模型将是我们系统性能的保证。同时,并行查询和向量化等技术也将会得到持续的迭代。未来的分布式 AP 集群也将是我们在单节点能力构建之后,下一步的重点工作方向。
关于数据更新问题 最后,我们讨论一下数据的更新问题。当 TP 中的数据发生变化后,首先将变化数据插入到 Population buffer 中,并维护该数据的版本信息。Population buffer 中的数据最后会和 in-memory column store 中的数据进行合并,形成该数据的最新版本,更新到 in-memory column store 中。当前诸多现有的 HTAP 方案是提供一个只读的 AP 节点,通过某种机制例如:ETL、Binlog 或者 Raft 同步 Redo Log 等方式将 TP 中数据更新到 AP 节点,并由该 AP 节点对外提供 AP 处理能力,这样导致整个系统架构负载,TP 和 AP 间的数据同步无法保证实时性。
当满足如下三个条件的时候,StoneDB 会将 Population buffer 中的数据,依据版本信息依次与 in memory column store 中数据合并,构成为该数据的最新版本:
(1)当我们的 Population buffer 已经写满后,会执行一次 flush 动作,将 buffer 中的数据更新到其对于的 in-memory 数据中;
(2)到达指定的时间,例如:200ms;
(3)当 AP 负载发现其引用到的数据来自 TP 时,其会主动的检查 Population buffer 是否有最新的版本。如果有,则 StoneDB 也会进行合并动作,形成该数据的最新版本。
StoneDB GitHub 地址:https://github.com/stoneatom/stonedb
社区地址: https://stonedb.io
关于作者
李浩,StoneDB 首席架构师、StoneDB PMC。曾在华为、爱奇艺、北大方正从事数据库内核核心架构设计。超过 10 年数据库内核开发经验,擅长查询引擎、执行引擎、大规模并行处理等技术。拥有数十项数据库发明专利,著有《PostgreSQL 查询引擎源码技术探析》。
可扫码添加小助手:StoneDB_2022
加入 StoneDB 开源社区用户群
讨论交流,共同进步
本文由博客一文多发平台 OpenWrite 发布!