探索云原生分布式 Data Warebase

在这个 AI 技术飞速发展的时代,我们有能力更深入地发掘数据潜在的价值,而数据处理不应当成为阻碍。云原生分布式 Data Warebase 将开启处理数据的新范式,它让数据的使用返璞归真,不论是存储还是查询,一个系统满足业务全方位数据需求。打破复杂数据架构的束缚,大大降低数据的使用门槛,释放数据潜能,让数据涌现智能

一、背景

  1. 近二十年大数据发展史

2002 年我加入 Microsoft SQL Server 引擎团队。那时的数据库市场相对简单,主要有三个厂商:Oracle、IBM(DB2)和 Microsoft(SQL Server)。数据库行业似乎已经相当成熟,发展趋于稳定,新的产品 / 厂家看起来不再有机会。我曾一度思考过继续做数据库是不是一个正确的职业选择。与数据库行业的成熟稳定相比,互联网业务蓬勃发展,对数据库能力和性能的要求与日俱增,一场解决水平扩展的战争悄然开始。 Microsoft SQL Server 等传统数据库存在一个较大的限制:作为一个单机的架构,只能通过用更大的机器向上扩张,因此性能总会受到单机性能的瓶颈制约。要将其转变为分布式架构是一项非常艰巨的任务。尽管 SQL Server 在这方面进行了一些尝试,但真正开始引领分布式革命的是谷歌发表的几篇论文。

GFS 和 MapReduce:Google 分别于 2003 和 2004 年发表了这两篇论文。GFS 描述了分布式文件系统的实现,为海量数据的存储指明了方向。MapReduce 则是进行大规模数据处理的一种架构。这两篇论文对整个行业产生了深远的影响,它使业界认识到使用普通硬件就可以实现海量数据的分布式存储和计算。

Hadoop:受到 GFS 和 MapReduce 的启发,开源框架 Hadoop 在 2006 年应运而生,此后十多年里,整个 Hadoop 大数据生态系统蓬勃发展。

Bigtable:2006 年,谷歌发表了 Bigtable 论文,介绍了这一分布式存储系统,旨在解决大规模结构化数据的存储与访问问题。Bigtable 的推出对后续的技术演进产生了重大影响,标志着 NoSQL 时代的开始,促进了包括 HBase、Cassandra 和 MongoDB 等一系列 NoSQL 系统的发展。

Hive:2008 年,Facebook 推出了 Hive,它基于 MapReduce 技术,大大简化了处理大数据的过程,用户仅需通过一条 SQL 语句即可执行复杂查询,极大提升了分析领域的工作效率。

Spanner:2012 年,谷歌发布了 Spanner 的论文,介绍了这一内部开发的真正的分布式关系型数据库的实现,业界终于看到了分布式关系型数据库的可行性。 自 2003 年起的二十年,数据行业经历了惊人的快速发展,推动了一系列的技术突破与创新。这一进程主要驱动力是解决日益增长的业务需求,尤其是在海量数据的存储和处理方面。随着数据量的激增,行业不断进化以支持更高效、更强大的数据管理和分析能力。

  1. 业务视角:以一个民宿 App 为例

这里以一个民宿 App 为例来分析应用在数据的存储和处理方面的需求。首先,需要一个系统存储每个民宿的基本信息以及各种用户数据,如一个民宿的地理位置、房间数、档期、设施、价格、用户的入住评论、还有用户使用应用的交互日志等。这些数据可以分为以下几类:

  • 结构化的数据:民宿的基本信息,如房间数量、价格等,这些可以用结构化数据来描述。
  • 半结构化数据:各类设施的款式、功能参数等,这些涉及到半结构化数据,需要更复杂的方式去存储。
  • 非结构化数据:如民宿照片和文字评论等,是典型的非结构化数据。

其次,用户可能在应用里以多种方式去使用这些数据:

  • 简单查询:用户知道民宿的名字,直接进行查询。
  • 条件检索:用户根据一些条件,比如价格、地理位置、卫生状况等,去搜索符合需求的民宿。
  • 语义搜索:用户进行一些语义层的搜索,比如寻找卫生条件好、性价比高、简约风格的民宿,这需要系统对图像和评论的语义进行理解。
  • 汇总分析:用户希望查看过去几天或一个月内某城市评价最高的民宿,这需要系统对城市内所有民宿的评价进行汇总分析。
  1. 现有数据架构的弊端

这款民宿应用必须能有效存储结构化、半结构化和非结构化数据,还需具备多种查询和分析的能力。作为一个互联网级的应用,其水平扩展能力也是必须。然而,市场上尚无一款产品能够很好地满足所有的需求,因此业界通常需要将多种数据产品组合起来,比如将结构化数据存储在 MySQL/PostgreSQL 等关系型数据库中,将半结构化数据存储在 MongoDB 里,将需要搜索的数据存储在 ElasticSearch 中等等。这种复杂的业务架构可能带来一系列问题:

  • 开发门槛

在这样一个复杂的业务架构下,任何新业务功能的开发都可能涉及使用多个数据产品,这就意味着业务开发需要去学习多个数据产品,理解它们各自适用的场景和利弊,以及如何把这些产品组合起来解决业务问题,这大大提高了开发的门槛。特别是在中小企业,因为数据人才的稀缺,往往会导致很多数据的业务价值没有充分发挥出来。

  • 开发效率

即使一个企业幸运地拥有一些能够驾驭各种数据产品的专家,他们也不得不花很多时间在实现复杂的数据架构上,从而影响了业务的迭代效率。他们本可以把这些宝贵的时间用在业务的开发上,更好地支持业务的增长。

  • 运维复杂/系统稳定性

每个数据产品都存在不足之处,都有各自潜在的问题。因此,运维需要与每个产品逐一磨合,深入理解并学会如何规避这些问题。任何一个产品出现问题都可能影响系统的稳定性。除了单个产品的稳定性问题,这种架构往往需要数据同步,这会进一步影响系统的稳定性:如果存储某一份数据的产品(比如说 HBase)恰巧不能高效地支持某种查询需求(比如说关键词搜索或语义搜索),就需要通过同步任务把数据从一个产品同步到另一个产品,然后使用目标产品完成相应的查询。数据同步往往是整个数据系统中最脆弱的环节之一,很容易影响系统的稳定性,一旦出现问题可能导致不同系统看到的数据不一致。

  • 数据延迟

即便在数据同步没有故障的情况下,也会存在同步延迟。即使通过各种优化让延迟减少到平均仅一两秒,但延迟可能会因为同步作业的热点以及 failover 等原因出现不可控的毛刺。想象一下一个房东修改了自己民宿的属性,然后立刻以新的属性去搜索自己的民宿却因为偶发的延迟毛刺搜不到,这无疑给用户带来了不好的体验。而要彻底解决这个问题,确保延迟永远保持在很短的时间内几乎是不可能的,业务上往往只能通过各种方式去减少其发生的概率。依赖大量数据同步的架构在交互式增删改的场景很难提供好的体验。

  • 成本

业务的用量往往有波峰波谷,增长难以准确预测,除了按波峰提前购买所需硬件,为了应对突发流量,还需要额外预留一部分硬件,这些硬件的闲置带来了一定的浪费。同时硬件资源分存储、计算等多个维度,因为某个维度资源不够增加机器可能会导致另外一个维度的资源浪费。

二、云原生分布式 Data Warebase:数据库与大数据的融合

那是否可能集众产品之长,开发出一款能够同时满足上述需求的数据产品呢?我认为答案是肯定的,过去二十年技术的发展已经探索和解决了各个子问题,现在是综合解决这些问题,大大降低数据使用门槛的时候了。

这样一个产品具有以下几个特征:

  • 云原生

部署和运维是数据产品很重要的一环,容器化能够确保在不同的计算环境中有一致的运行行为,大大简化产品在不同环境的部署和运维。通过 Kubernetes 调度这些容器,系统能够根据流量的变化方便地扩缩容。通过使用存储计算分离的架构,让各个维度资源的扩缩容更加灵活,进一步优化资源利用,降低成本。

  • 分布式

过去二十年数据产品的发展几乎都在围绕着解决一个问题,就是系统的水平扩展能力。只有分布式的系统才能彻底移除性能的天花板,满足任何业务的性能需求。

  • Data Warebase

数据产品大体上可分为关系型数据库、NoSQL 数据库、搜索引擎、向量搜索和数据仓库等几类。“Data Warebase”这一术语融合了“数据仓库(Data Warehouse)”和“数据库(Database)”两词,用以概述一种集合了上述多类产品功能的产品。这类产品能同时满足业务对不同数据存储和计算能力的需求。

此时一个疑问自然浮现:这是否同时也意味着性能上的折衷?该系统是否在任一场景中都无法提供最优解?这是一个很好的问题,其核心在于这些功能之间是否存在根本的、不可调和的冲突,以及它们的组合是否产生协同效应,从而实现效能的叠加,使得整体的效果超过其部分的总和,实现 1 + 1 > 2。

  • 以麦克斯韦方程组为例

麦克斯韦是最伟大的理论物理学家之一,他将前人发现的电学和磁学的四个方程放到一起,形成了著名的麦克斯韦方程组。通过求解这个方程组,麦克斯韦发现了电磁波,于是便有了光!这一合并过程虽看似简单,却促成了质的飞跃,孕育了超乎预期的新现象,这就是典型的 1 + 1 > 2 的场景。

(麦克斯韦方程组)

通过把起源于不同场景的互补的数据技术融合在一起,不但能够服务好这些场景本身,还能自然解决单个技术没法很好解决的跨场景问题。这种融合的体验将极大地降低业务使用数据的门槛,提升业务开发的效率,彻底解决数据延迟和不一致的问题,为数据产生业务价值提速!同时简洁的业务数据架构将大大简化运维,提升系统的稳定性。

三、构建云原生分布式 Data Warebase 的要素

为什么要把 Database 和 Data Warehouse 放在一起呢?我们先考虑一下反过来的问题:为什么要把数据库、搜索、和数仓分开?从上面民宿 APP 的例子看到业务并没有要求我们将这些系统分开,大家把它分为不同的产品实际上是受技术的限制。我们接下来先解释一下技术上遇到的挑战以及解决它们的方式。

  1. 水平扩展能力
  • 1.1 NoSQL 数据库的优势

要在关系型数据库实现水平扩展是一个充满技术挑战的事情。但业务却不能停滞发展,不会等待完美的技术方案出现,所以大家快速发展出了一系列能够水平扩展的产品。NoSQL 数据库就是当中的一类,它比较好地解决了水平扩展的问题,当然也对问题做了一些简化和妥协。

接下来我们以 NoSQL 中使用广泛的文档型数据库为例分析其背后的一些思考。从单机走向分布式一个巨大的挑战是分布式的事务,但是在一个特殊情况下事务的实现会得到极大的简化,这就是单机事务的场景,也就是一个事务所有读写的记录都恰好在一台机器的情况。我们可以在这种情况下采用类似单机数据库的做法。但是在关系模型里,业务上相关的数据会按照关系模型设计的三个范式分开存储在多张表中,这就导致了业务的一次修改往往需要更新分布在多个表里的多条数据,这些数据很可能分布在不同的机器上,因此关系模型限制了单机事务优化的适用场景。文档型数据库的优势这时候就发挥出来了,由于文档模型会把相关的数据组织成单个文档,很多业务场景只需更新单个文档,从而避免了多机事务的额外开销。这种简化使得文档型数据库能够较简单地通过数据分片来实现水平扩展,从而满足互联网业务高速增长的性能需求,得到了较广泛的应用。

(SQL VS NoSQL)

文档型数据库另外一个优势是存储半结构化数据的能力,不同文档不必完全同构。比如说在描述民宿的设施时,冰箱可能有个字段是容积,但是吹风机没有这个字段。这种灵活性使开发人员不再需要去找 DBA 修改表结构,进而提升了开发效率,成为敏捷开发一个很好的选择。

  • 1.2 关系型数据库的优势

既然文档模型有这么多好处,我们是不是应该放弃关系模型而使用文档模型呢?在数据库发展早期,类文档模型和关系模型曾经有过较量,结果是关系模型几乎一统江湖。关系模型胜出的一个重要原因是它能较好地维持数据的一致性。

上文提到了关系模型设计的三个范式,它们从数据依赖的角度阐明了高效地组织数据并且避免重复的方式。开发者可以根据实体间的关系(一对一,一对多,或者多对多)设计表结构。文档模型可以嵌入一对一和一对多关系的实体,但对于多对多关系缺乏有效解决方案,可能导致数据重复存储。而数据一旦重复存储保证它们的一致性就会成为一个挑战,业务代码在做修改时需要同时修改多份数据才能维持这种一致性,业务代码将变得更复杂。更糟糕的是,需同时修改的数据可能分布于不同机器上,使单机事务优化不再适用。为了在这种场景做到数据的一致性,分布式事务是一个任何系统都绕不过去的坎。文档数据库只在某些场景解决了数据组织的问题,而关系模型完整地解决这个问题。

文档模型因为没有确定的表结构而能较容易地表达半结构化数据,但是这也是一把双刃剑。这种情况类似于动态类型语言(如 JavaScript)与静态类型语言(如 C++)之间的比较。动态类型语言不需预定义变量类型,易于上手,但在大型项目中可能挑战维护性。TypeScript 应运而生,并且在大型项目中得到广泛应用充分说明了这点。一些文档型数据库也意识到了这个问题,通过让用户定义文档的模式(Schema),给文档内部的一致性提供了一定的保障。

除了文档内部的约束外,不同的数据实体间也可能存在一些约束。比如说关系型数据库能够通过外键来维护实体间的一致性,这种功能在文档型数据库中一般是缺失的,所以它们维持多文档间的数据一致性很困难。另外一个例子是唯一性二级索引,因为不支持分布式事务,跨节点的唯一性很难保证,所以这类系统往往要求唯一性二级索引包含分区键,这限制了它的适用场景。所以相比关系型数据库,文档型数据库对约束的支持比较弱,因此提供的数据完整性和一致性的保障也有差距。

除数据一致性优势外,关系模型的另一强项是对 SQL 的支持,它允许将查询的实现交由优化器处理,从而显著提高开发效率。文档型数据库因为不支持完整的 SQL,在查询方面也面临着一些挑战。这类产品一般 Join 的能力都比较差或者不支持 Join。所以它们在涉及多个文档内容关联的场景往往需要在业务端实现一些查询逻辑。

  • 1.3 NoSQL 和关系型数据库的融合

NoSQL 数据库因为率先解决了水平扩展的问题,以及其对敏捷开发模式的支持曾经红极一时,甚至有人认为 NoSQL 才是数据库的未来。但后续开发者也逐渐意识到了刚才提到的这些问题,所以 NoSQL 产品也开始吸收关系型数据库的一些能力。这些发展甚至表现在 NoSQL 这个名字的解释上。NoSQL 的首次提出在 1998 年,它最初的含义确实是“无 SQL”的意思,也就是 SQL 的反义词。NoSQL 运动真正开始获得关注是在 2009 年左右。在 2009 年一个讨论非关系型数据库的会议上这个名字被重新解释为“Not Only SQL”,这个会议的原意是加倍下注,是想强调不仅不采用 SQL 作为查询语言,也不采用关系模型的设计理念,彻底搞一套新的数据架构。NoSQL 也一度成为可以水平扩展和敏捷开发的代名词。但是近年来一些 NoSQL 系统也开始实现分布式的事务(虽然并不建议在生产使用),同时也实现了部分 SQL 查询语言。随着关系型数据库的这些能力被 NoSQL 产品吸收,NoSQL 又被大家解释为“不仅仅是 SQL”,不再是 SQL 的反义词,而是作为 SQL 的扩展。

过去的十来年,关系型数据库产品也意识到了半结构化数据的重要性,开始引入 JSON 或者 JSONB 类型去表达半结构化数据,比如 PostgreSQL 有着非常完善的 JSON 支持。用户可以在任何一张表里引入 JSON 列,一个 JSON 列对应于文档型数据库里的一个文档。关系型数据库突然有了文档数据库灵活表达半结构化数据的能力。除了简单的字段提取外,还引入了 JSON Query(包含 JSON PATH QUERY)这种强大的查询语言,能够非常方便查询和操作 JSON 数据。有了这些扩展后关系型数据库在数据模型和查询能力上已经是 NoSQL 数据库的超集,有着更灵活高效的数据组织和查询能力。我们看到关系模型和文档模型并不是一个互斥的关系,通过引入 JSON 类型的增强版关系模型,我们能够在一个产品里同时得到这两种模型的好处。

(水平扩展)

解决了数据模型融合的问题后,剩下的就是水平扩展的问题了。上文已经解释了除了使用数据分片技术外,分布式事务是任何一个想完全保证数据一致性的分布式产品都绕不过去的坎,实现它的挑战也是巨大的,我们只能直面它解决它。好在 Spanner 的论文很好地展示了如何在一个关系型数据库实现外部一致性的分布式事务。有了分布式事务后就能提供关系型数据库完整的功能了。这些功能包含了外键、全局唯一性二级索引等,给数据一致性和完整性提供全面的保证。Spanner 虽然是一个非常复杂的分布式数据库,但它把复杂留给了自己,用户使用时如同使用单机关系型数据库一样简单,甚至更强大。这种易用性使得 Spanner 在 Google 内部取得了极大的成功。

无论是 NoSQL 数据库还是关系型数据库在实现分布式事务上遇到的挑战是类似的。同时引入了 JSON 类型的关系型数据产品也能够和 NoSQL 数据库一样地支持好可以被优化为单机事务的场景,所以这种新型的分布式关系型数据产品完全包含了 NoSQL 数据库的优点。

  1. 搜索

最简单的查询模式是根据某个键值去找到相应的记录(点查),这是传统的关系型数据库非常擅长且高效的场景。为了提升这类查询的性能,关系型数据库引入了二级索引的功能,使用二级索引可以根据索引键值直接定位到相关记录,从而大大加速查询。比如我们可以为民宿表建立一个民宿名字的索引,这样就能够快速地从名字找到相应的民宿。

稍微复杂一点的查询需要根据多个字段做过滤(搜索)。二级索引在这类场景有一定的局限性。因为只有当查询条件是索引键的前缀时二级索引才能较好地发挥作用,所以针对不同的查询模式可能需要创建不同的二级索引。在查询模式固定并且较少情况,可以通过一个或者多个二级索引加速这些查询。但是在一些业务场景查询模式很灵活甚至事先不能完全确定。比如说除了按照名字查找民宿外,用户可能需要按照房间的价格,设施等多种条件的组合去查找民宿。这些搜索条件的组合会随着可能检索字段的个数增加而指数级增加。如果我们为每种可能的查询模式创建一个二级索引,所需创建的二级索引数量也会指数级增加。这些二级索引除了占用存储空间外,还会增加每一次数据增删改操作所带来的维护索引的成本,创建大量的二级索引会变得不可行。

(倒排索引)

搜索引擎使用了倒排索引的技术来解决这个问题,这种索引把字段映射到包含它的文档列表(倒排链)。这些倒排链可以高效地做集合操作(比如求交集,并集等)。倒排索引的技术在全文搜索领域应用比较广泛,但是其原理对结构化 / 半结构化数据的查询一样适用。我们只需对可能检索的字段创建单个字段的倒排索引,就可以通过多个倒排链的集合操作去加速这些字段的联合过滤。

在分布式系统中,索引分区方式对查询性能会有较大的影响。常见有两种可能的方式:一是按照索引字段的值去分区,好处是给定一个要查找的字段值能够定位到确定的分区,所以单字段的查询非常高效,但是多个字段的联合查询就需要对分布在多台机器的倒排链进行集合操作了,这对性能会产生比较大的影响。第二种方式是把数据和其对应的索引放在同一个分区。这种方式下即使单字段的检索也会需要查找多个分区,所以单字段的检索效率没有第一种方式高。但是好处是多字段的联合检索能够在分区内高效地完成倒排链的集合操作。所以为点查优化的二级索引往往采取第一种方式,而为灵活搜索优化的倒排索引通常采用第二种方式。

这种倒排索引和分区技术在 Elastic 等产品中实现并且得到了广泛的应用,这些技术很容易被分布式关系型数据库吸收,使其具备高效的全文检索和对结构化 / 半结构化数据搜索的能力。

  1. 向量搜索

在过去的两年中,基于 Transformer 架构的大语言模型取得了突飞猛进的发展,极大地推动了自然语言处理、图像识别以及音视频内容的理解和生成。如何有效地利用这些模型的能力,特别是在私域数据上的应用,已经成为了一个极其关键的议题。检索增强型生成模型(RAG)提供了一种创新的解决方案,它巧妙地将数据库或搜索引擎的查询能力与生成式人工智能技术结合起来。例如,要回答一个自然语言问题,我们首先使用数据库或搜索引擎查找与之相关的记录。这些初步筛选的结果随后输入到大模型,让大模型在理解了这些记录的基础上给出高质量的回答。

除了可以利用前文提到的全文检索和结构化检索能力,还发展出了一种基于嵌入(Embedding)的检索模式。Embedding 检索通过为每条记录计算出一个高维嵌入向量,并利用这些向量的距离或内积来衡量它们在语义上的关联度或相似度,从而实现了一种基于向量的检索方法。在使用自然语言查询的时候,我们可以为问题本身计算出一个高维嵌入向量,然后寻找与这个向量相似向量对应的文档。

(向量搜索)

为了便于在系统中存储和处理这些高维向量,我们可以引入向量数据类型,这样便可以轻松地保留下这些记录的嵌入表示。然而,当记录数量极大时,从数亿条记录中快速寻找到与特定向量相似度高的向量将会是一个性能挑战。为了高性能地实现这一点,索引这些向量就显得尤为重要。目前常见的向量索引类型包括 IVFFlat 和 HNSW。那些集成了高维向量类型和索引功能的关系型数据库,是针对这一挑战很好的解决方案。相比专业的向量数据库,引入了向量类型的关系型数据产品门槛更低,还能够同时使用基于关键词的全文检索,结构化 / 半结构化数据的检索,以及基于语义的向量检索进行联合查询,这是分开的任何单一产品都不具有的能力。

  1. 分析

传统的数仓设计用于复杂的查询和分析,其存储的数据是相对静态的,往往通过每天一次的方式导入,不用考虑并发事务的问题,所以在数据写入的事务处理上可以大大简化,比如可以通过锁表的方式来实现。因为在白天没有数据导入,所以查询也不用担心被写入事务卡住。但是随着业务对数据实时性要求的提高,出现了实时数仓的需求。数据需要持续不断地实时导入系统,同时我们希望查询在这个过程中不会被阻塞。简单粗暴地以锁表方式去导入数据显然不再能满足这个需求。多版本控制(MVCC)是解决这类读写冲突的一个有效的办法。每条写入的数据都会带上写入的时间戳,一条数据的多个版本在一段时间内会在系统共存。读的时候可以选择一个不再会有新写入的时间戳,这样就可以获得对应于该时间戳的完整的快照。在这个快照上做各种复杂的分析查询就不会被写入阻塞。这种多版本控制的技术已经被很多数据库产品所使用,比如说上文提到的 Spanner,同样的技术也可以用在实时数仓里。

因为数仓场景的数据量巨大,如果这些海量的数据需要实时写入,就会需要海量的事务。高吞吐的分布式事务是个有挑战的问题,可能给系统带来一定的额外开销,这也是大家(包括我自己)曾经一度认为数据库和数仓必须分开的原因之一。我们在此深度剖析一下数仓场景的写入问题。数仓场景的写入模式主要有两种:一种是批量导入大量数据,如完全替换表中数据;另一种是逐条实时写入,尽管可能通过批处理实现更新,但本质上每条记录都是独立事务。幸运的是这两种写入模式都有优化的空间。第一类写入模式虽然数据量巨大,但是事务数很少,所以基本不用担心分布式事务所带来的额外开销,因为它和写入这么多数据带来的计算量相比可以忽略不计。而第二类写入模式每条数据可以当作一个独立的事务,这让前面提到的单机事务优化成为可能,因此也不需要承担分布式事务带来的额外成本。只要能为这两类场景做针对性的优化,就能在一个产品中支持好数仓的海量数据写入。

(行式存储 VS 列式存储)

现代数仓的一个秘诀是采用了列存储,搜索引擎通过建立倒排索引解决了多个字段联合过滤的问题,在分析类查询中,我们可能还需要对某些列做快速的聚合。如果数据以传统的行式存储,这意味着单个列的聚合就需要把所有数据都读取一遍,系统会因为读取很多不必要的数据导致查询变得很慢。而如果我们以列的方式去组织存储,把同一列所有行的数据存在一起,无需读取额外数据就能高效地实现这种聚合。同时有了高效读取单列数据的能力后,还可以在没有倒排索引的情况下实现高效的过滤。此外因为同一列的不同行数据有较高的相似性,这使得高效的编码和压缩成为可能,从而进一步减少读取数据所需的 IO 量进而提升查询的性能。除了存储外,要完全发挥列存的优势还依赖于向量化(vectorized)的查询引擎。当然列存和向量化查询并非在所有场景都最优,在需要读取少量整行数据的场景,行存和行处理可能是更好的选择。但是我们也可以把行存和列存结合使用,让优化器在查询时根据具体的场景选择使用最合适的存储和处理方式。

(预聚合)

预计算也是数仓的一个常见优化,这类预计算包含总和、平均值、计数、最大值 / 最小值等一系列指标,这些聚合好的数据存储在系统中,以便快速访问和分析,减少查询的计算量,从而加快查询响应时间。这些单表的预计算可以很好地用索引去抽象和实现。更加复杂一些的涉及到多个表的预计算逻辑也可以通过物化视图去抽象。这些物化视图可以通过手工或者系统自动去刷新。

四、开启创新之门

现在我们理解了各个技术创新点,构建一个全新的技术就水到渠成了。

  1. 技术融合

我们可以看到各种产品都采用了一系列技术去优化相应的场景,这些优化包括:

  • NoSQL 通过数据分片实现了水平扩展。还引入了文档模型,减少分布式事务的需求,同时能够较好地支持半结构化数据;
  • 搜索引擎引入了倒排索引,以及不同的索引分片策略,能够高效地支持各种搜索条件的组合;
  • 向量引擎引入了向量索引,帮助在海量向量中快速寻找和一个向量相似度高的向量;
  • 数仓为海量数据写入做了大量优化。数仓还引入了列存储,能够更好地压缩数据,支持高效地聚合和过滤。同时可以通过预计算减少查询的计算量提升查询性能。

如同电学和磁学的方程一样,虽然它们起源于不同的场景,但是这些技术并不冲突,完全可以在一个产品里同时采用:

  • 引入分布式架构,通过数据分片的方式实现水平扩展;
  • 实现分布式事务,保证数据的完整性、一致性和持久性;
  • 扩展关系模型,引入 JSON 类型,把文档模型的优点结合进来;
  • 引入倒排索引以及新的索引分片策略,支持高效的文本搜索和结构化多维搜索;
  • 引入向量类型和相应的向量索引,支持高效的语义搜索;
  • 引入 MVCC 机制,保证查询不被写入阻塞;
  • 针对数仓场景海量数据的写入模式做相应的优化;
  • 引入列存,提升数据的压缩率,引入高效的向量化执行引擎,提供高效地过滤和聚合的能力。同时提供行列并存的能力。优化器根据查询选择使用合适的存储和执行模式;
  • 引入预聚合和物化视图,优化器合理使用这些预计算的数据,减少查询时的计算量,大大提升查询性能。
  1. 体验

刚才在麦克斯韦的例子里我省略了一个重要的细节:他不是简单地把四个兼容的方程放在一起形成一个方程组。他注意到了电磁感应没有相对应的磁效应,缺乏对称性而不够优美,就顺手在方程组里做了一个“小”修改,给最后一个方程加了一项位移电流。正是这个修改,解决了方程组和电荷守恒定律冲突的问题。也正是因为这个修改,才产生了电磁波!

(位移电流)

简单地把这一系列技术都在一个产品中实现是不够的,如果用户需要为不同的场景做大量的调参,产品还是会给用户带来割裂的体验。为了去掉这些参数,系统必须做好自适应。上面提到了几个优化的例子:优化器根据查询决定使用行存还是列存,决定是不是可以使用预计算数据;系统根据是不是单机事务去做一阶段提交的优化。但是真正要把体验做好,这些还远远不够,从存储、内存管理、到并发控制等系统的方方面面都需要为自适应而设计,而不是把自适应当作一种事后的优化。这种能力如麦克斯韦的同位移电流,它将各个数据产品中的点状的能力融合在一起,打破了场景的边界,提供了一个全新的产品体验。

当各种场景都在使用同一个产品的时候,不同工作负载间的隔离就变得尤为重要。隔离的实现可以通过软件层次的软隔离,感兴趣的读者可以参考 HSAP 的文章。隔离也可以通过资源层的硬隔离去实现,也就是把需要隔离的不同请求用不同的计算节点去完成。但有时候在同一份数据上有不同的工作负载需要隔离,存储计算分离的架构能够允许不同的计算节点读取同一份存储而方便地实现这种隔离。当然除了隔离外,存储计算分离的架构也为高效利用资源快速扩缩容带来了很多好处。

我们正见证着数据产品一场深刻的变革。过去二十年间,整个行业都在致力于提高性能,以满足业务不断增长的需求。然而,现在性能的提升已不再是主导变革的力量。随着性能问题的逐渐解决,它已转变为一项基本的、必备的要求,不再构成业务发展的主要阻碍。随着这一基础需求的广泛满足,用户对产品的更深层次需求开始显现,那就是对体验的追求。未来,数据产品的成功将越来越依赖于提供卓越的用户体验 —— 这将成为区分各类产品的决定性标准

五、数据开发的新范式

这时候,我们终于拥有了一种全新的数据产品 – 云原生分布式 Data Warebase。这类新产品的问世标志着数据管理的返璞归真,它的设计理念是以满足业务需求为核心,无论是数据存储还是检索,单一的产品就能全面覆盖。这正本着业务驱动的原则,使用户能够真正地使用数据、享受产品,而不再受困于和众多数据产品的博弈。

这种新范式将极大地简化业务数据架构,用户无需把自己的业务切割为数据库场景、NoSQL 场景、搜索场景和数仓场景。使用分布式 Data Warebase 时,数据的使用门槛大大降低。用户将体验到系统自适应性带来的极致简化的产品体验,让数据的潜能得以更简单、更直接地释放,从而极大地提升业务的灵活性。

采纳新范式并不意味着要求用户去学习全新的技术。这类数据产品可以设计为与成熟的关系型数据库(例如 PostgreSQL)兼容,借此利用其强大的生态。这种做法让用户几乎不需要学习就能使用新技术,既能享受到新技术带来的优势,又无需离开他们已经熟悉和信赖的技术环境。

让我们回顾一下文章开头提到的民宿 APP,业务从未要求过应使用多种数据产品,那为何开发者的第一直觉是把数据的需求分解成多种场景,然后为每个场景选择相应的数据产品呢?这是因为过去二十年间出现的各类数据产品都有其局限性,这些局限性不断向用户灌输一个理念:不同的场景必须用不同的产品来解决。

我记得曾看过一个视频,一个小女孩第一次看到纸质杂志时,她尝试用双指放大内容。几次失败后,她终于意识到:杂志不过是一部坏掉的 iPad!也许,终有一天我们会认识到:现行的数仓或数据库实际上都是能力不完整的 Data Warebase!

data.name

蒋晓伟

曾任阿里巴巴研究员,创建了阿里云 Flink 和 Hologres 团队和产品;曾任 Facebook 调度系统,时间轴和 Messenger 的技术主管;曾任微软 SQL Server 引擎架构师;美国西北大学理论物理硕士学位,中国科学技术大学理论物理学士学位。