当前位置: 首页 > web >正文

知识扩展——探究当代分布式数据库

发展与局限:传统数据库在分布式领域的探索

从这一讲开始,我们进入实践(扩展)模块,目的是帮助你更了解现代分布式数据库,并且我会把之前学习的理论知识应用到实际案例中。

这个模块的讲解思路如下。

  1. 传统数据库分布式:传统数据库,如 Oracle、MySQL 和 PostgreSQL 没有一刻放弃在分布式领域的探索。我会介绍分布式技术如何赋能传统数据库,以及它们的局限性。
  2. 数据库中间件:虽然中间件严格来说并不包含在数据库领域内,但它是很多用户首次接触分布式数据库的切入点,故在该领域有着不可代替的作用。我会介绍数据库中间件的功能,特别是处理事务的方式,它与模块三中介绍的分布式事务还是有差别的。
  3. 当代分布式数据库:该部分重点介绍目前大家能接触到的 NewSQL、DistributedSQL 类型的数据库。重点关注它们在异地多活、容灾等方面的实践。
  4. 其他类型数据库与数据库选型:查缺补漏为你介绍其他类型的分布式数据库,扩宽你的视野。最后结合金融、电信和电商等场景,为你介绍这些行业是如何选择分布式数据库的。

传统数据库分布式化

业务应用系统可以按照交易类型分为 OLTP 场景和 OLAP 场景两大类。OLTP 是面向交易的处理过程,单笔交易的数据量小,但是要在很短的时间内给出结果,典型场景包括购物、转账等;而 OLAP 场景通常是基于大数据集的运算,典型场景包括生成各种报表等。

OLTP 与 OLAP 两种场景有很大的差异,虽然传统数据库在其早期是将两者融合在一起的。但是随着它们向分布式,特别是 Sharding(分片)领域转型,OLAP 类型的数据逐步被抛弃,它们将所有的精力集中在了 OLTP 上。

OLTP 场景通常有三个特点:

  • 写多读少,而且读操作的复杂度较低,一般不涉及大数据集的汇总计算;
  • 低延时,用户对于延时的容忍度较低,通常在 500 毫秒以内,稍微放大一些也就是秒级,超过 5 秒的延时通常是无法接受的;
  • 高并发,并发量随着业务量而增长,没有理论上限。

传统数据库,比如 MySQL 和 Oracle 这样的关系型数据库就是服务于 OLTP 场景的,但我们一般认为它们并不是分布式数据库。这是为什么呢?因为这些数据库传统都是单节点的,而我们说的分布式数据库都是多节点的。

传统关系型数据库时单机模式的,也就是主要负载运行在一台机器上。这样,数据库的并发处理能力与单机的资源配置是线性相关的,所以并发处理能力的上限也就受限于单机配置的上限。这种依靠提升单机资源配置来扩展性能的方式,被称为垂直扩展(Scale Up)。我们之前介绍过,垂直扩展是瓶颈的,因为物理机单机配置上限的提升是相对缓慢的。这意味着,在一定时期内,依赖垂直扩展的数据库总会存在性能的天花板。

那么传统数据库的单机模式可以变为分布式吗?答案是可以的。这些传统数据库在维持关系型数据库特性不变的基础上,可以通过水平扩展,也就是 Sharding 模式,增加机器数量、提供远高于单体数据库的并发量。这个并发量几乎不受单机性能限制,我们将这个级别的并发量称为“高并发”。这里说的“高并发”并没有一个具体的数字与之对应。不过,我可以给出一个经验值,这个“高并发”应该至少大于一万 TPS。

在 Sharding 之外,还需要引入可靠的复制技术,从而提高系统整体的可用度,这在金融级的容灾场景中非常重要。这些理念都是我在模块一中就强调过的,分片与同步才是分布式数据库的核心。

商业产品

商业数据库如 Oracle 通过底层存储的分布式达到数据分散的目的。其实这类数据库一直没有放弃对分布式领域的探索。现在我介绍一下 Oracle Sharding。

Oracle 数据库从 12.2 版本开始引入 Sharding 特性,集成了 NoSQL 和成熟的关系型数据库的优势,到如今已经过多个版本迭代,成为一整套成熟的分布式关系型数据库解决方案。Oracle Sharding 可以让用户将数据分布和复制到一组 Oracle 数据库集群中,集群中的数据库只需要网络连接,不需要共享软件和硬件。Oracle Sharding 可以为应用提供线性扩展能力和完全容错能力。

Oracle Sharding 主要包括下面这些组件。

  • Sharded database(SDB):逻辑上 SDB 是一个数据库,但是物理上 SDB 包括多个物理独立的数据库,SDB 类似一个数据库池(pool),数据库池中包括多个数据库(Shard)。
  • Shards:SDB 包括多个物理独立的数据库,每一个数据库都称为 shard,每个 shard 数据库位于不同的服务器。这些 Shard 被部署在独立的机器上,每个 shard 数据库中保存表的不同数据集,但是每个 Shard 中都有相同的列,也就是说这些 Shard 是按行进行分片的。
  • Shard catalog:是一个 Oracle 数据库,用于集中存储管理 SDB 配置信息,是 SDB 的核心。SDB 配置变化,比如添加/删除 shard 等,都记录在 Shard catalog。如果应用查询多个 shard 中的数据,那么由 Shard catalog 统一协调分配。Shard catalog 需要进行 HA,也就是高可用部署。因为里面的数据非常重要,一旦丢失,会造成整个数据库不可用。
  • Shard directors:Global Data Service(GDS)实现对 Sharding 的集中部署和管理。GSM 是 GDS 的核心组件,GSM 作为 Shard director。GSM 类似监听器,将客户端对 SDB 的请求路由到对应的 shard,负载均衡客户端的访问。

Oracle Sharding 优点如下。

  • 线性扩展:因为每个 shard 是一个独立的数据库,通过增加新的 Shard 节点,来线性扩展性能,自动 rebalance 数据。
  • 失败隔离:由于 Shard 是一种 shared-nothing 技术,每个 shard 使用独立的硬件,因此一个 shard 节点出现故障,只会影响到这个 shard 存放的数据,而不会影响到其他 shard。
  • 按照地理位置分布数据:可以选择根据地理位置不同,将数据存储在不同的 shard。

除了以上的优点,其缺点也非常明显。

  • 用户设计复杂:不同于传统的 RAC 模式,Sharding 需要用户对表进行严格设计,从而才能发挥该模式扩展性与可用性方面的优势。同时,对于老系统迁移,这往往意味着要修改现有代码。
  • 跨分片性能低:跨分片事务,聚合查询的性能很低。一般比单分片低 10%。

最后一个缺点就是商业数据库的老问题,性价比低。这个我在后面会进一步阐述。

那么商业方案看起来很好,但是如果你更喜欢开源的解决方案,下面我会介绍开源传统数据库对这个问题的思考。

开源定制

单体开源数据要向分布式数据库演进,就要解决写入性能不足的问题。

最简单直接的办法就是分库分表。分库分表方案就是在多个单体数据库之前增加代理节点,本质上是增加了 SQL 路由功能。这样,代理节点首先解析客户端请求,再根据数据的分布情况,将请求转发到对应的单体数据库。代理节点分为“客户端 + 单体数据库”和“中间件 + 单体数据库”两个模式。

客户端组件 + 单体数据库通过独立的逻辑层建立数据分片和路由规则,实现单体数据库的初步管理,使应用能够对接多个单体数据库,实现并发、存储能力的扩展。其作为应用系统的一部分,对业务侵入比较深。这种客户端组件的典型产品是 Apache ShardingShpere 的 JDBC 客户端模式,下图就是该模式的架构图。
在这里插入图片描述
代理中间件 + 单体数据库以独立中间件的方式,管理数据规则和路由规则,以独立进程存在,与业务应用层和单体数据库相隔离,减少了对应用的影响。随着代理中间件的发展,还会衍生出部分分布式事务处理能力。这种中间件的典型产品是 MyCat、Apache ShardingShpere 的 Proxy 模式。
在这里插入图片描述
代理节点需要实现三个主要功能,它们分别是客户端接入、简单的查询处理器和进程管理中的访问控制。另外,分库分表方案还有一个重要的功能,那就是分片信息管理,分片信息就是数据分布情况。不过考虑分片信息也存在多副本的一致性的问题,大多数情况下它会独立出来。显然,如果把每一次的事务写入都限制在一个单体数据库内,业务场景就会很受局限。

因此,跨库事务成为必不可少的功能,但是单体数据库是不感知这个事情的,所以我们就要在代理节点增加分布式事务组件。同时,简单的分库分表不能满足全局性的查询需求,因为每个数据节点只能看到一部分数据,有些查询运算是无法处理的,比如排序、多表关联等。所以,代理节点要增强查询计算能力,支持跨多个单体数据库的查询。更多相关内容我会在下一讲介绍。

这时离分布式数据库还差重要的一步,那就是逻辑时钟。我们在分布式系统模块已经介绍了逻辑时钟的意义,它是实现数据一致性的必要条件。加上这最后一块拼图,这类分布式数据库区别于单体数据库的功能也就介绍完整了,它们是分片、分布式事务、跨节点查询和逻辑时钟。

这类数据库一般以 MySQL 或 PostgreSQL 为基础进行开发。MySQL 类的解决方案有 TDSQL、Vitess 和具有 JDTX 的 ShardingShpere。PGXC(PostgreSQL-XC)的本意是指一种以 PostgreSQL 为内核的开源分布式数据库。因为 PostgreSQL 的开放软件版权协议,很多厂商在 PGXC 上二次开发,推出自己的产品。不过,这些改动都没有变更主体架构风格,所以我把这类产品统称为 PGXC 风格,其中包括 TBase、GuassDB 和 AntDB 等。

以上我们讨论了开源领域中传统数据库在分布式领域中的尝试。但是,此类方案是有一些局限的,看看都有哪些。

局限

目前传统数据库在分布式领域内的探索,我们可以总结为“商业靠实力而开源靠合作”,它们分别打开了自己的一片天地。但是,它们长久的技术积累不仅带来了功能的丰富,同时一些局限也是其无法克服的。

  1. 性价比。以 Oracle Sharding 为代表的商业解决方案,虽然功能很完善,同时能满足多种场景,对传统 Oracle 用户有极强的吸引力。但是其费用与收益其实是不成正比的,其对分片事务支持有限,同时跨分片查询性能很低。这些重要功能的缺失与其高昂的售价相比是极不相称的。故商业的 Sharding 方案一直没有成为主流。
  2. 事务。由于传统数据库都需要复用原有的存储节点,故事务方案大多都是我们介绍过的两阶段提交这类原子提交协议。学习过模块三中分布式事务的同学都清楚,传统两阶段在性能和规模上都有很大的限制,必须采用新的事务模式才能突破这层天花板。而传统数据库的底层被锁死,很难在这个领域有更好的表现。
  3. OLAP。传统数据库在转为分布式之前能很好地支持 OLAP。但其 Sharding 后,该过程变得越来越困难。同时随着大数据技术的崛起,它们有主动放弃该领域的趋势。而新一代的 HTAP 架构无一例外都是 NewSQL 和云原生数据库的天下,这个领域是从传统数据库发展而来的分布式数据库无法企及的。

以上我们谈的传统数据库在分布式领域的局限其实总结为一点就是,它们的底层存储引擎限制了其上层分布式功能的拓展。只有如 NewSQL 类数据库一般,使用创新的存储引擎,才能在整体上打造出功能与性能匹配的现代分布式数据库。但是,此类数据库由于发展多年,在稳定性、维护性上有不可动摇的优势,即使存在一些局限性,但其对单机版本的用户依然有很强的吸引力。

总结

传统单机数据库向分布式数据库的转型尝试,它们一般经过分片、复制、分布式事务和物理时钟等过程的改造,从而打造以单体数据库为数据节点的分布式数据库。

同时我们也讨论了此类数据库的天花板,因此应该从底层去构建分布式数据库,就像 NewSQL 类数据库,才是分布式数据库发展的正途。

数据库中间件:传统数据库向分布式数据库的过渡

关系型数据库本身比较容易成为系统性能瓶颈,单机存储容量、连接数、处理能力等都很有限,数据库本身的“有状态性”导致了它并不像 Web 和应用服务器那么容易扩展。在互联网行业海量数据和高并发访问的考验下,应用服务技术人员提出了分片技术(或称为 Sharding、分库分表)。同时,流行的分布式系统数据库,特别是我们上一讲介绍的从传统数据库过渡而来的分布式数据库,本身都友好地支持 Sharding,其原理和思想都是大同小异的。

成功的数据库中间件除了支持分片外,还需要全局唯一主键、跨分片查询、分布式事务等功能的支持,才能在分片场景下保障数据是可用的。下面我就为你一一介绍这些技术。

全局唯一主键

分库分表的环境中,数据分布在不同的分片上,不能再借助数据库自增长特性直接生成,否则会造成不同分片上的数据表主键重复。

下面我简单介绍下使用和了解过的几种 ID 生成算法:

  1. Twitter 的 Snowflake(又名“雪花算法”)
  2. UUID/GUID(一般应用程序和数据库均支持)
  3. MongoDB ObjectID(类似 UUID 的方式)

其中,Twitter 的 Snowflake 算法是我近几年在分布式系统项目中使用最多的,未发现重复或并发的问题。该算法生成的是 64 位唯一 ID(由 41 位的 timestamp + 10 位自定义的机器码 + 13 位累加计数器组成)。

那么解决了全局唯一主键,我们就可以对数据进行分片了。下面为你介绍常用的分片策略。

分片策略

介绍过的分片模式有:范围分片和哈希分片。

当需要使用分片字段进行范围查找时,范围分片可以快速定位分片进行高效查询,大多数情况下可以有效避免跨分片查询的问题。后期如果想对整个分片集群扩容时,只需要添加节点即可,无须对其他分片的数据进行迁移。

但是,范围分片也有可能存在数据热点的问题,有些节点可能会被频繁查询,压力较大,热数据节点就成了整个集群的瓶颈。而有些节点可能存的是历史数据,很少需要被查询到。

哈希分片我们采用 Hash 函数取模的方式进行分片拆分。哈希分片的数据相对比较均匀,不容易出现热点和并发访问的瓶颈。

但是,后期分片集群扩容起来需要迁移旧的数据。使用一致性 Hash 算法能够很大程度地避免这个问题,所以很多中间件的分片集群都会采用一致性 Hash 算法。离散分片也很容易面临跨分片查询的复杂问题。

很少有项目会在初期就开始考虑分片设计的,一般都是在业务高速发展面临性能和存储的瓶颈时才会提前准备。因此,不可避免地就需要考虑历史数据迁移的问题。一般做法就是通过程序先读出历史数据,然后按照指定的分片规则再将数据写入到各个分片节点中。我们介绍过 ShardingShpere 的弹性伸缩正是解决这个问题的有力武器。

此外,我们需要根据当前的数据量和 QPS 等进行容量规划,综合成本因素,推算出大概需要多少分片(一般建议单个分片上的单表数据量不要超过 1000W)。

数据分散到不同的数据库、不同的数据表上,此时如果查询跨越多个分片,必然会带来一些麻烦。下面我将介绍几种针对分片查询不同的策略。

跨分片查询

中间件跨分片查询,本质上讲原本由数据库承担的数据聚合过程转变到了中间件层。而下面介绍的几种方案,其原理都来源于存储引擎层面。

分页查询

一般来讲,分页时需要按照指定字段进行排序。当排序字段就是分片字段的时候,我们通过分片规则可以比较容易定位到指定的分片,而当排序字段非分片字段的时候,情况就会变得比较复杂了。为了最终结果的准确性,我们需要在不同的分片节点中将数据进行排序并返回,并将不同分片返回的结果集进行汇总和再次排序,最后再返回给用户。

在分布式的场景中,将“LIMIT 10000000,10”改写为“LIMIT 0,10000010”,才能保证其数据的正确性。为什么这样呢?你可以仔细想想。结果就是此种模式会将大量无用数据加载到内存中,从而给内存带来极大的压力。一般解决的手段是避免使用 LIMIT 关键字,而是直接用如下的模式。

SELECT * FROM t_order WHERE id > 100000 AND id <= 100010 ORDER By id;

而在翻页时,通过记录上一页最后一条数据的位置,从而减少数据的加载量。

聚合函数

在使用 Max、Min、Sum、Count 和 Avg 之类的函数进行统计和计算的时候,需要先在每个分片数据源上执行相应的函数处理,然后再将各个结果集进行二次处理,最终再将处理结果返回。这里要注意 Avg 函数的实现比较特殊,需要借助 Sum 和 Count 两个函数的实现逻辑进行配合。

跨分片Join

Join 是关系型数据库中最常用的特性,但是在分片集群中,Join 也变得非常复杂,我们应该尽量避免跨分片的 Join查询(这种场景比上面的跨分片分页更加复杂,而且对性能的影响很大)。

通常有以下两种方式来对其进行优化。

  1. 全局表。全局表的基本思想就是把一些类似数据字典又可能会产生 Join 查询的表信息放到各分片中,从而避免跨分片的 Join。
  2. ER分片。在关系型数据库中,表之间往往存在一些关联的关系。如果我们可以先确定好关联关系,并将那些存在关联关系的表记录存放在同一个分片上,那么就能很好地避免跨分片 Join 问题。在一对多关系的情况下,我们通常会选择按照数据较多的那一方进行拆分。

分布式事务

此处的分布式事务与上一讲的传统数据库发展而来的分布式数据库面临的困难是类似的。那就是,中间件只能与数据库节点进行交互,而无法影响底层数据结构。从而只能从比较高的层次去解决问题,所以下面要介绍的众多方案都有各自的缺点。

客户端一阶段

这是通过客户端发起的一种事务方案,它去掉了两阶段中的 Prepare 过程。典型的实现为:在一个业务线程中,遍历所有的数据库连接,依次做 Commit 或者 Rollback。这种方案对数据库有一种假设,那就是底层数据库事务是做“前向检测”(模块二事务)的,也就是 SQL 执行阶段就可以发现冲突。在客户端进行 Commit 时,失败的概率是非常低的,从而可以推断事务整体失败概率很低。阅文集团早期采用该方案,SLA 可达两个 9。

这种方案相比下面介绍的其他方案来说,性能损耗低,但在事务提交的执行过程中,若出现网络故障、数据库宕机等预期之外的异常现象,将会造成数据不一致,且无法进行回滚。

XA两阶段

二阶段提交是 XA 的标准实现。让我们复习一下两阶段提交。它将分布式事务的提交拆分为两个阶段:Prepare 和 Commit/Rollback。

开启 XA 全局事务后,所有子事务会按照本地默认的隔离级别锁定资源,并记录 undo 和 redo 日志,然后由 TM 发起 Prepare 投票,询问所有的子事务是否可以进行提交。当所有子事务反馈的结果为“Yes”时,TM 再发起 Commit;若其中任何一个子事务反馈的结果为“No”,TM 则发起 Rollback;如果在 Prepare 阶段的反馈结果为 Yes,而 Commit 的过程中出现宕机等异常时,则在节点服务重启后,可根据 XA Recover 再次进行 Commit 补偿,以保证数据的一致性。

2PC 模型中,在 Prepare 阶段需要等待所有参与子事务的反馈,因此可能造成数据库资源锁定时间过长,不适合并发高以及子事务生命周期较长的业务场景。

ShardingSphere 支持基于 XA 的强一致性事务解决方案,可以通过 SPI 注入不同的第三方组件作为事务管理器实现 XA 协议,如 Atomikos。

最大努力送达

最大努力送达,是针对客户端一阶段的一种补偿策略。它采用事务表记录所有的事务操作 SQL,如果子事务提交成功,将会删除事务日志;如果执行失败,则会按照配置的重试次数,尝试再次提交,即最大努力地进行提交,尽量保证数据的一致性。这里可以根据不同的业务场景,平衡 C 和 A,采用同步重试或异步重试。这与 TiDB 实现 Percolator 事务中重试的思路有相似之处。

这种策略的优点是无锁定资源时间,性能损耗小。缺点是尝试多次提交失败后,无法回滚,它仅适用于事务最终一定能够成功的业务场景。因此最大努力送达是通过对事务回滚功能上的妥协,来换取性能的提升。

TCC

TCC 模型是把锁的粒度完全交给业务处理,它需要每个子事务业务都实现 Try-Confirm/Cancel 接口。

  • Try:尝试执行业务。完成所有业务检查,并预留必需业务资源。
  • Confirm: 确认执行业务。真正执行业务,不做任何业务检查。只使用 Try 阶段预留的业务资源。Confirm 操作满足幂等性。
  • Cancel:取消执行业务。释放 Try 阶段预留的业务资源。Cancel 操作满足幂等性。

这三个阶段都会按本地事务的方式执行,不同于 XA 的 Prepare,TCC 无须将 XA 投票期间的所有资源挂起,因此极大地提高了吞吐量。但是它的缺点是需要实现 Cancel 操作,这不仅给实现带来了很多麻烦,同时有一些操作是无法 Cancel 的。

Saga

Saga 模型把一个分布式事务拆分为多个本地事务,每个本地事务都有相应的执行模块和补偿模块(TCC 中的 Confirm 和 Cancel)。当 Saga 事务中任意一个本地事务出错时,可以通过调用相关的补偿方法恢复之前的事务,达到事务最终的一致性。

它与 TCC 的差别是,Saga 是以数据库事务维度进行操作的,而 TCC 是以服务维度操作的。

当每个 Saga 子事务“T1,T2,…,Tn”都有对应的补偿定义“C1,C2,…,Cn-1”,那么 Saga 系统可以保证子事务序列“T1,T2,…,Tn”得以完成(最佳情况)或者序列“T1,T2,…,Tj,Cj,…,C2,C1”得以完成,也就是取消了所有的事务操作。

由于 Saga 模型中没有 Prepare 阶段,因此事务间不能保证隔离性,当多个 Saga 事务操作同一资源时,就会产生更新丢失、脏数据读取等问题,这时需要在业务层控制并发,例如:在应用层面加锁、应用层面预先冻结资源。

Saga 支持向前和向后恢复。

  • 向后恢复:如果任一子事务失败,补偿所有已完成的事务。
  • 向前恢复:假设每个子事务最终都会成功,重试失败的事务。

显然,向前恢复没有必要提供补偿事务,如果你的业务中,子事务最终总会成功,或补偿事务难以定义或不可能,向前恢复会更符合你的需求。理论上补偿事务永不失败,然而,在分布式世界中,服务器可能会宕机、网络可能会失败,甚至数据中心也可能会停电,这时需要提供故障恢复后回退的机制,比如人工干预。

总的来说,TCC 是以应用服务的层次进行分布式事务的处理,而 XA、Bed、Saga 则是以数据库为层次进行分布式处理,故中间件一般倾向于采用后者来实现更细粒度的控制。

Apache ShardingShpere 的分布式事务变迁

ShardingShpere 在 3.0 之前实现了客户端一阶段(弱 XA),最大努力送达和 TCC。其中最大努力送达需要配合调度任务异步的执行。而弱 XA 作为默认的实现模式,此种组合是实用性与实现难度之间的平衡,但是在分布式失败模型描述的场景下会产生不一致的问题。

在 3.0 后,团队梳理了事务模型。实现了 XA 两阶段和 Saga。这两种事务都是面向数据库层面的,同时有完整的理论支撑,更加符合现代分布式数据库的设计风格。同时事务模块也如其他模块一样支持 SPI,也就是可以实现第三方的事务模型。而京东 JDTX 事务引擎就是通过 SPI 集成到 ShardingShpere 的。下一讲我会介绍 JDTX 的相关内容。

总结

实现数据库中间件的几种技术,包括全局唯一主键、分片策略和跨分片查询。其中最重要的就是分布式事务。

不同于分布式数据库,中间件的分布式事务多了很多应用服务的特色,比如客户单一阶段、TCC。它们更偏向于服务层面,从而揭示了中间件大部分是由应用研发或应用架构团队开发迭代的产物。而随着中间件的发展,它们不可避免地向分布式数据演进,如阿里云的 DRDS 和 PolarDB-X 就是由中间件 TDDL 演化而成。

数据库中间件是一个过渡产品,随着近几年技术的发展,越来越多原生 NewSQL 出现在我们面前。

现状解读:分布式数据库的最新发展情况

对于 NewSQL 的定义和适用范围一直存在争议。有人认为 Vertica、Greenplum 等面向 OLAP 且具有分布式特点的数据库也应该归到 NewSQL 里面。但是,业界更加广泛接受的 NewSQL 标准包括:

  1. 执行短的读写事务,也就是不能出现阻塞的事务操作;
  2. 使用索引去查询一部分数据集,不存在加载数据表中的全部数据进行分析;
  3. 采用 Sharded-Nothing 架构;
  4. 无锁的高并发事务。

根据以上这些特点,我总结为:一个 NewSQL 数据库是采用创新架构,透明支持 Sharding,具有高并事务的 SQL 关系型数据库。

请注意 DistributedSQL 是一类特殊的 NewSQL,它们可以进行全球部署。

创新的架构

使用创新的数据库架构是 NewSQL 数据库非常引人注目的特性。这种新架构一般不会依靠任何遗留的代码,我们以 TiDB 这个典型的 NewSQL 数据库为例。
在这里插入图片描述
可以看到其中的创新点有以下几个。

  1. 存储引擎没有使用传统数据库。而使用的是新型基于 LSM 的 KV 分布式存储引擎,有些数据库使用了完全内存形式的存储引擎,比如 NuoDB。
  2. Sharded-Nothing 架构。底层存储到上层工作负载都是独立部署的。
  3. 高性能并发事务。TiDB 实现了基于 Percolator 算法的高性能乐观事务。
  4. 透明分片。TiDB 实现了自动的范围分片,可以弹性地增减节点。
  5. 基于复制技术的自动容灾。使用 Raft 算法实现高可用的数据复制,自动进行故障转移。

可以说,NewSQL 与传统关系型数据库之间的交集在于 SQL 与 ACID 事务,从而保证用户的使用习惯得以延续。

以上描述的创新点我在前两个模块都有详细的说明。这里不知道你是否注意到一个问题:与使用传统数据库构建分布式数据库相比,NewSQL 最为明显的差异来自存储引擎。特别是以 Spanner 为首的一众 NewSQL 数据库,如 YugaByte DB、CockroachDB 和 TiDB 都是使用 LSM 树作为存储引擎,并且都是 KV 结构。如此选择的原理是什么呢?

我在介绍 LSM 的时候,提到其可以高性能地写入与读取,但是牺牲了空间。可能你就据此得出结论,NewSQL 数据库面对 OLTP 场景,希望得到吞吐量的提升,故选择 LSM 树存储引擎,而不选择 B 树类的存储引擎。但是,我也介绍过有很多方法可以改进 B 树的吞吐量。所以这一点并不是关键点。

我曾经也会困惑于这个问题,经过大量研究,并与项目组人员交流。从而得到了一个“结论”:开源的 NewSQL 选择的并不是 LSM 树,而是 RocksDB。选择 RocksDB 难道不是因为它是 LSM 结构的?答案是否定的。大部分以 RocksDB 为存储引擎的开源 NewSQL 数据库看中的是 RocksDB 的性能与功能。可以有一个合理的推论,如果有一款在性能和功能上碾压 RocksDB 的 B 树存储引擎,那么当代开源 NewSQL 数据库的存储引擎版图又会是另一番景象了。

你不用诧异,这种发展趋势其实代表了 IT 技术的一种实用特性。从 TCP/IP 协议的普及,到 Java 企业领域 Spring 替代 EJB,都体现了这种实用性。那就是真正胜利的技术是一定有实用价值的,这种实用价值要胜过任何完美的理论。这也启发我们在观察一个分布式数据库时,不要着急给它分类,因为今天我要介绍的评判 NewSQL 的标准,是基于现有数据库特性的总结,并不能代表未来的发展。我们要学会掌握每种数据库核心特性。

到这里,我还要提一个比较特别的数据库,那就是 OceanBase。OceanBase 的读写跟传统数据库有很大的一点不同就是:OceanBase 的写并不是直接在数据块上修改,而是新开辟一块增量内存用于存放数据的变化。同一笔记录多次变化后,增量块会以链表形式组织在一起,这些增量修改会一直在内存里不落盘。OceanBase 读则是要把最早读入内存的数据块加上后续相关的增量块内容合并读出。这种特点其实与 LSM 树的内存表和数据表有类似之处,只是 OceanBase 在更高维度上。

总结完架构上的创新,下面我将介绍 NewSQL 中关于分片的管理。

透明的 Sharding

我们上文介绍过数据库中间件是如何进行 Sharding 的,那就是使用逻辑的分片键来进行分片计算,将不同的行写入到不同的目标数据库。其中,需要用户深度地参与。比如,需要用户去指定哪个键为分片键,逻辑表与物理表的映射规则,必要的时候还需要进行 SQL 改造,等等。故中间件模式的 Sharding 我们一般称作显示 Sharding,与之相对的就是 NewSQL 数据库提供的透明 Sharding。

透明 Sharding 顾名思义,用户不需要去指定任何的规则,数据就能分散到整个集群中,并自动做了备份处理。那么 NewSQL 是怎么确定分片键的呢?我们以 TiDB 为例。

一个表中的数据是按照 Region 来进行 Sharding 的。每个 Region 有多个副本,从而保障了数据的高可用。不同的表将会有不同的 Region,而不是如传统分库那样每个库里的表都是相同的。 那么一个表下,每一行数据存储在哪个 Region 下是如何确定的呢?

首先要确定的是行是怎么映射到 KV 结构的: key 由 table_id 表 id+rowid 主键组成。如:

t[table_id]_r[row_id]

而 value 保存的就是一整行的数据。那么我们就使用这个 key 来计算这行数据应该落在哪个 Region 里面。

TiDB 是使用范围策略来划分数据。有索引情况下,负责索引的 Region 会根据索引字段范围来划分。基于 key 经过一个转换,将会得出一个数字,然后按范围划分多个区间,每个区间由一个 Region 管理。范围分片的好处我们之前介绍过,就是存储平衡和访问压力的平衡。其原因是,范围分片有机会做更好的动态调度,只有动态了,才能实时自动适应各种动态的场景。

虽然透明 Sharding 为用户带来了使用的便利。但聪明的你可以注意到了,这种隐式的分片方案相比上一讲介绍的方案,从功能上讲是存在缺失的。最明显的是它缺少跨分片 Join 的功能。可以想到,此种 NewSQL 与具有 ER 分片的数据库中间件在性能上是存在差异的。针对此种情况,TiDB 引入了 Placement Rules 来制定将相关联的数据表放在同一个 KV 存储中,从而达到 ER 分片的效果。

当然,随着 NewSQL 的逐步发展,哈希分片也逐步被引入 NewSQL 中。我们知道范围分片有热点问题,虽然可以通过动态拆分合并分片来缓解,但终究不是从根本上解决该问题。特别是对于具有强顺序的数据,比如时间序列,该问题就会变得很突出。而哈希分片就是应对该问题的有效手段。基于这个原因,Cockroach DB 引入哈希分片索引来实现针对序列化数据的扩展能力。

我们小结一下,透明的 Sharding 针对的往往是主键,一般会选择行 ID 作为主键。而如果要实现功能完善的 Sharding,一些用户参与的配置操作还是有必要的。

分布式的 SQL

NewSQL 数据库相对于 NoSQL 最强大的优势还是对 SQL 的支持。我曾经在模块一中与你讨论过,SQL 是成功的分布式数据库一个必要的功能。SQL 的重要性我们已经讨论过了,但实现 SQL 一直是被认为很困难的,究其原因主要来源于以下两个方面。

  1. SQL 的非标准性。虽然我们有 SQL99 这种事实标准,但是在工业界,没有一种流行的数据库完全使用标准去构建 SQL。每家都有自己的方言、自己独有的特性,故我们看到的 NewSQL 数据库大部分都会按照已经存在的数据库方言去实现 SQL 语义,比如 TiDB 实现了 MySQL 的语法,而 CockroachDB 实现了 PostgreSQL。
  2. 声明式语言。SQL 语言是一种更高级的语言,比我们熟悉的 Java、Go 等都要高级。主要体现为它表述了希望得到什么结果,而没有指示数据库怎么做。这就引出了所谓的执行计划优化等概念,为实现高效的查询引擎带来了挑战。

以上是传统数据库实现 SQL 的挑战,而对于分布式数据库来说还需要将数据分散带来的问题考虑进去,同时在查询优化方面要将网络延迟作为一个重要因素来考量。

对于 NewSQL 而言,如果使用了上面所描述的创新架构,特别是底层使用 KV 存储,那么就需要考虑数据与索引如何映射到底层 KV 上。我在前面已经说明了数据是如何映射到 KV 上的,那就是 key 由 table_id 表 id+rowid 主键组成,value 存放行数据:

t[table_id]_r[row_id] => row_data

而对于索引,我们就要区分唯一索引和非唯一索引。

对于唯一索引,我们将 table_id、index_id 和 index_value 组成 key,value 为上面的 row_id。

t[table_id]_i[index_id][index_value] => row_id

对于非唯一索引,就需要将 row_id 放到 key 中,而 value 是空的。

t[table_id]_i[index_id][index_value]_r[row_id] => null

底层映射问题解决后,就需要进入执行层面了。这里面牵扯大量的技术细节,我不会深入其中,而是为你展示一些 NewSQL 数据库会面临的挑战。

首先是正确性问题。是的,要实现正确的 SQL 语法本身就是挑战。因为 SQL 可以接受用户自定义表和索引,查询使用名字,而执行使用的是 ID,这之间的映射关系会给正确性带来挑战。而其中最不好处理的就是 Null,不仅仅是 NewSQL,传统数据库在处理 Null 的时候也经过了长时间的“折磨”。这也是为什么一个 SQL 类数据库需要经过长时间的迭代才能达到稳定状态的原因。

然后就是性能了。性能问题不仅仅是数据库开发人员,DBA 和最终用户也对它非常关注。如果你经常与数据库打交道,一定对 SQL 优化有一定了解。这背后的原因其实就是 SQL 声明式语言导致的。

大部分 NewSQL 数据库都需要实现传统数据库的优化手段,这一般分为两类:基于规则和基于代价。前者是根据 SQL 语义与数据库特点进行的静态分析,也称为逻辑优化,常见有列裁剪、子查询优化为连接、谓词下推、TopN 下推,等等;而基于代价的优化,需要数据库实时产生统计信息,根据这些信息来决定 SQL 是否查询索引、执行的先后顺序,等等。

而具有分布式数据库特色的优化包括并行执行、流式聚合,基于代价的优化需要考虑网络因素等。故实现分布式数据库的 SQL 优化要更为复杂。

从上文可以看到,NewSQL 的数据库实现 SQL 层所面临的挑战要远远大于传统数据库。但由于 SQL 执行与优化技术经过多年的积累,现在已经形成了完整的体系。故新一代 NewSQL 数据库可以在此基础上去构建,它们站在巨人的肩膀上,实现完整的 SQL 功能将会事半功倍。

高性能事务

NewSQL 的事务是其能够得到广泛应用的关键。在上一个模块中我们讨论的 Spanner 与 Calvin,就是典型的创新事务之争。这一讲我将总结几种 NewSQL 数据库处理事务的常见模式,并结合一定的案例来为你说明。

首先的一种分类方式就是集中化事务管理与去中心化事务管理。前者的优势是很容易实现事务的隔离,特别是实现序列化隔离,代价就是其吞吐量往往偏低;而后者适合构建高并发事务,但是需要逻辑时钟来进行授时服务,并保证操作竞争资源的正确性。

以上是比较常规的认识,但是我们介绍过 Calvin 事务模型。它其实是一种集中化的事务处理模式,但却在高竞争环境下具有非常明显的吞吐量的优势。其关键就是通过重新调度事务的执行,消除了竞争,从而提高了吞吐量。采用该模式的除了 Calvin 外,还有 VoltDB。其原理和 Calvin 类似,感兴趣的话你可以自行学习。

而采用去中心化事务的方案一般需要结合:MVCC、2PC 和 PaxosGroup。将它们结合,可以实现序列化的快照隔离,并保证执行过程中各个组件的高可用。采用 PaxosGroup 除了提供高可用性外,一个重要的功能就是将数据进行分区,从而降低获取锁的竞争,达到提高并发事务效率的目的。这种模式首先被 Spanner 所引入,故我们一般称其为 Spanner 类事务模型。

而上一讲我们介绍了京东为 ShardingShpere 打造的 JDTX 又是另一番景象,数据库中间件由于无法操作数据库底层,所以事务方案就被锁死。而 JDTX 采用类似 OceanBase 的模式,首先在数据库节点之外构建了一个独立的 MVCC 引擎,查询最新的数据需要结合数据库节点与 MVCC 引擎中修改的记录,从而获得最新数据。而 MVCC 中的数据会异步落盘,从而保证数据被释放。JDTX 的模式打破了中间件无法实现高性能事务模型的诅咒,为我们打开了思路。

可以看到,目前 NewSQL 的并发事务处理技术往往使用多种经过广泛验证的方案。可以将它比喻为当代的航空母舰,虽然每个部件都没有创新点,但是将它们结合起来却实现了前人无法企及的成就。

总结

这一讲,介绍了 NewSQL 数据库的定义,并为你详细分析了一个 NewSQL 数据库的关键点,即以下四个。

  1. 创新的架构:分布式系统与存储引擎都需要创新。
  2. 透明的 Sharding:自动的控制,解放用户,贴合云原生。
  3. 分布式 SQL:打造商业可用分布式数据库的关键。
  4. 高性能事务:NewSQL 创新基地,是区别不同种类 NewSQL 的关键。

NewSQL 和具有全球部署能力的 DistributedSQL 是当代分布式数据库的发展方向,可以说我们介绍过的所有知识都是围绕在 NewSQL 体系内的。

概念解析:云原生、HTAP、图与内存数据库

云原生数据库

云原生数据库从名字看是从云原生概念发展而来的。而云原生一般包含两个概念:一个是应用以服务化或云化的方式提供给用户;另一个就是应用可以依托云原生架构在本地部署与 Cloud 之间自由切换。

第一种概念是目前广泛介绍的。此类云原生数据库是在云基础架构之上进行构建的,数据库组件在云基础设施之上构建、部署和分发。这种云原生属性是它相比于其他类型数据库最大的特点。作为一种云平台,云原生数据库以 PaaS(平台即服务,Platform-as-a-Service)的形式进行分发,也经常被称作 DBaaS(数据库即服务,DataBase-as-a-Service)。用户可以将该平台用于多种目的,例如存储、管理和提取数据。

使用此类云原生数据库一般会获得这样几个好处。

快速恢复

也就是数据库在无须事先通知的情况下,即时处理崩溃或启动进程的能力。尽管现在有先进的技术,但是像磁盘故障、网络隔离故障,以及虚拟机异常等,仍然不可避免。对于传统数据库,这些故障非常棘手。因为用单个机器运行整个数据库,即便一个很小的问题都可能影响所有功能。

而云原生数据库的设计具有显著的快速恢复能力,也就是说可以立即重启或重新调度数据库工作负载。实际上,易处置性已从单个虚拟机扩展到了整个数据中心。随着我们的环境持续朝着更加稳定的方向发展,云原生数据库将发展到对此类故障无感知的状态。

安全性

DBaaS 运行在高度监控和安全的环境里,受到反恶意软件、反病毒软件和防火墙的保护。除了全天候监控和定期的软件升级以外,云环境还提供了额外的安全性。相反,传统数据库容易遭受数据丢失和被不受限制的访问。基于服务提供商通过即时快照副本提供的数据能力,用户可以达成很小的 RPO 和 RTO。

弹性扩展性

能够在运行时进行按需扩展的能力是任何企业成长的先决条件。因为这种能力让企业可以专注于追求商业目标,而不用担心存储空间大小的限制。传统数据库将所有文件和资源都存储在同一主机中,而云原生数据库则不同,它不仅允许你以不同的方式存储,而且不受各种存储故障的影响。

节省成本

建立一个数据中心是一项独立而完备的工程,需要大量的硬件投资,还需要能可靠管理和维护数据中心的训练有素的运维人员。此外,持续地运维会给你的财务带来相当大的压力。而使用云原生的 DBaaS 平台,你可以用较低的前期成本,获得一个可扩展的数据库,这可以让你腾出双手,实现更优化的资源分配。

以上描述的云原生数据库一般都是采用全新架构的 NewSQL 数据库。最典型的代表就是亚马逊的 Aurora。它使用了日志存储实现了 InnoDB 的功能,从而实现了分布式条件下的 MySQL。目前各个主要云厂商的 RDS 数据库都有这方面的优势,如阿里云 PolarX,等等。

而第二种云原生数据库理论上可以部署在企业内部(私有云)和云服务商(公有云),而许多企业尝试使用混合模式来进行部署。面向这种场景的云原生数据库并不会自己维护基础设施,而是使自己的产品能运行在多种云平台上,ClearDB 就是这类数据库典型代表。这种跨云部署提高了数据库整体的稳定性,并可以改善服务全球应用的数据响应能力。

当然,云原生数据库并不仅限于关系型,目前我们发现 Redis、MongoDB 和 Elasticsearch 等数据库都在各个主要云厂商提供的服务中占有重要的地位。可以说广义上的云原生数据库含义是非常宽泛的。

HTAP

OLTP 是面向交易的处理过程,单笔交易的数据量很小,但是要在很短的时间内给出结果;而 OLAP 场景通常是基于大数据集的运算。它们两个在大数据时代就已经分裂为两条发展路线了。

但是 OLAP 的数据往往来自 OLTP 系统,两者一般通过 ETL 进行衔接。为了提升 OLAP 的性能,我们需要在 ETL 过程中进行大量的预计算,包括数据结构的调整和业务逻辑处理。这样的好处是可以控制 OLAP 的访问延迟,提升用户体验。但是,因为要避免抽取数据对 OLTP 系统造成影响,所以必须在系统访问的低峰期才能启动 ETL 过程,例如对于电商系统,一般都是午夜进行。

这样一来, OLAP 与 OLTP 的数据延迟通常就在一天左右,大家习惯把这种时效性表述为 N+1。其中,N 就是指 OLTP 系统产生数据的日期,N+1 是 OLAP 中数据可用的日期,两者间隔为 1 天。你可能已经发现了,这个体系的主要问题就是 OLAP 系统的数据时效性,24 个小时的延迟太长了。是的,进入大数据时代后,商业决策更加注重数据的支撑,而且数据分析也不断向一线操作渗透,这都要求 OLAP 系统更快速地反映业务的变化。

此时就出现了将两种融合的 HTAP。HTAP(Hybrid Transaction/Analytical Processing)就是混合事务分析处理,它最早出现在 2014 年 Gartner 的一份报告中。Gartner 用 HTAP 来描述一种新型数据库,它打破了 OLTP 和 OLAP 之间的隔阂,在一个数据库系统中同时支持事务型数据库场景和分析型数据库场景。这个构想非常美妙,HTAP 可以省去烦琐的 ETL 操作,避免批量处理造成的滞后,更快地对最新数据进行分析。

由于数据产生的源头在 OLTP 系统,所以 HTAP 概念很快成为 OLTP 数据库,尤其是 NewSQL 风格的分布式数据库和云原生数据库。通过实现 HTAP,它们试图向 OLAP 领域进军。这里面比较典型代表是 TiDB,TiDB 4.0 加上 TiFlash 这个架构能够符合 HTAP 的架构模式。

TiDB 是计算和存储分离的架构,底层的存储是多副本机制,可以把其中一些副本转换成列式存储的副本。OLAP 的请求可以直接打到列式的副本上,也就是 TiFlash 的副本来提供高性能列式的分析服务,做到了同一份数据既可以做实时的交易又做实时的分析,这是 TiDB 在架构层面的巨大创新和突破。

内存数据库

传统的数据库通常是采用基于磁盘的设计,原因在于早期数据库管理系统设计时受到了硬件资源如单 CPU、单核、可用内存小等条件的限制,把整个数据库放到内存里是不现实的,只能放在磁盘上。可以说内存数据库是在存储引擎层面上进行全新架构的 NewSQL 数据库。

伴随着技术的发展,内存已经越来越便宜,容量也越来越大。单台计算机的内存可以配置到几百 GB 甚至 TB 级别。对于一个数据库应用来说,这样的内存配置已经足够将所有的业务数据加载到内存中进行使用。通常来讲,结构化数据的规模并不会特别大,例如一个银行 10 年到 20 年的交易数据加在一起可能只有几十 TB。这样规模的结构化数据如果放在基于磁盘的 DBMS 中,在面对大规模 SQL 查询和交易处理时,受限于磁盘的 I/O 性能,很多时候数据库系统会成为整个应用系统的性能瓶颈。

如果我们为数据库服务器配置足够大的内存,是否仍然可以采用原来的架构,通过把所有的结构化数据加载到内存缓冲区中,就可以解决数据库系统的性能问题呢?这种方式虽然能够在一定程度上提高数据库系统的性能,但在日志机制和更新数据落盘等方面仍然受限于磁盘的读写速度,远没有发挥出大内存系统的优势。内存数据库管理系统和传统基于磁盘的数据库管理系统在架构设计和内存使用方式上还是有着明显的区别。

一个典型的内存数据库需要从下面几个方面进行优化。

  1. 去掉写缓冲:传统的缓冲区机制在内存数据库中并不适用,锁和数据不需要再分两个地方存储,但仍然需要并发控制,需要采用与传统基于锁的悲观并发控制不同的并发控制策略。
  2. 尽量减少运行时的开销:磁盘 I/O 不再是瓶颈,新的瓶颈在于计算性能和功能调用等方面,需要提高运行时性能。
  3. 可扩展的高性能索引构建:虽然内存数据库不从磁盘读数据,但日志依然要写进磁盘,需要考虑日志写速度跟不上的问题。可以减少写日志的内容,例如把 undo 信息去掉,只写 redo 信息;只写数据但不写索引更新。如果数据库系统崩溃,从磁盘上加载数据后,可以采用并发的方式重新建立索引。只要基础表在,索引就可以重建,在内存中重建索引的速度也比较快。

综上可以看到,构建内存数据库并不是简单地将磁盘去掉,而是需要从多个方面去优化,才能发挥出内存数据库的优势。

图数据库

图数据库(graph database)是一个使用图结构进行语义查询的数据库,它使用节点、边和属性来表示和存储数据。该系统的关键概念是图,它直接将存储中的数据项,与数据节点和节点间表示关系的边的集合相关联。这些关系允许直接将存储区中的数据连接在一起,并且在许多情况下,可以通过一个操作进行检索。图数据库将数据之间的关系作为优先级。查询图数据库中的关系很快,因为它们永久存储在数据库本身中。可以使用图数据库直观地显示关系,使其对于高度互联的数据非常有用。

如果内存数据库是在底层存储上进行的创新,那么图数据库就是在数据模型上进行了改造。构造图数据库时,底层存储既可以使用 LSM 树等 KV 存储,也可以使用上一讲介绍的内存存储,当然一些图数据库也可以使用自创的存储结构。

由于图数据所依赖的算法本质上没有考虑分布式场景,故在分布式系统处理层面形成了两个流派。

以节点为中心

这是传统分布式理论作用在图数据库中的一种形式。此类数据库以节点为中心,使相邻的节点就近交换数据。图算法采用了比较直接的模式,其好处是并发程度较好,但是效率很低。适合于批量并行执行简单的图计算。典型代表是就是 Apache Spark。故此种数据库又被称为图计算引擎。

以算法为中心

这是针对图计算算法特别设计的数据库。其底层数据格式满足了算法的特性,从而可以使用较低的资源处理较多的图数据。但是此类数据库是很难进行大范围扩展的。其典型代表有 Neo4j。

当然我们一般可以同时使用上面两种处理模式。使用第一种来进行大规模数据的预处理和数据集成工作;使用第二种模式来进行图算法实现和与图应用的对接工作。

总之,图数据库领域目前方兴未艾,其在社交网络、反欺诈和人工智能等领域都有非常大的潜力。特别是针对最近的新冠疫情,有很多团队利用图数据库分析流行病学,从而使人们看到了该领域数据库的优势。

图数据库与文档型数据库、时间序列数据库等都是面向特殊数据模型的数据库。此类数据库之所以能越来越火热,除了它们所在领域被重视以外,最重要的底层原因还是存储引擎和分布式系统理论、工具的日趋成熟。可以预见,今后一些热门领域会相继产出具有领域特色的数据库。

总结

其中云原生与 HTAP 都是 NewSQL 数据库的发展分支。云原生是从交付领域入手,提供给用户一个开箱即用的数据库。而 HTAP 拓展了 NewSQL 的边界,引入了 OLAP,从而抢占了部分传统大数据和数据分析领域的市场。

而内存数据库是针对数据库底层的创新,除了内存数据库外,2021 年随着 S3 存储带宽的增加和其单位存储价格持续走低,越来越多的数据库开始支持对象存储。今后,随着越来越多的创新硬件的加入,我们还可能看到更多软硬结合方案数据库的涌现。

最后我介绍了图数据库,它作为特殊领域数据库在领域内取得成就,是通用关系型数据无法企及的。而随着存储引擎和分布式理论的发展,此类数据库将会越来越多。

数据库选型:我们该用什么分布式数据库?

电商:从中间件到 NewSQL

分布式数据库,特别是分布式中间这一概念就是从电商,尤其是阿里巴巴集团催生出来的。阿里集团也是最早涉及该领域的企业。这里我们以其 B2B 平台部产生的 Cobar 为例介绍。

2008 年,阿里巴巴 B2B 成立了平台技术部,为各个业务部门的产品提供底层的基础平台。这些平台涵盖 Web 框架、消息通信、分布式服务、数据库中间件等多个领域的产品。它们有的源于各个产品线在长期开发过程中沉淀出来的公共框架和系统,有的源于对现有产品和运维过程中新需求的发现。

数据库相关的平台就是其中之一,主要解决以下三方面的问题:

  1. 为海量前台数据提供高性能、大容量、高可用性的访问;
  2. 为数据变更的消费提供准实时的保障;
  3. 高效的异地数据同步。

如下面的架构图所示,应用层通过 Cobar 访问数据库。
在这里插入图片描述
其对数据库的访问分为读操作(select)和写操作(update、insert和delete)。写操作会在数据库上产生变更记录,MySQL 的变更记录叫 binlog,Oracle 的变更记录叫 redolog。Erosa 产品解析这些变更记录,并以统一的格式缓存至 Eromanga 中,后者负责管理变更数据的生产者、Erosa 和消费者之间的关系,负责跨机房数据库同步的 Otter 是这些变更数据的消费者之一。

Cobar 可谓 OLTP 分布式数据库解决方案的先驱,至今其中的思想还可以从现在的中间件,甚至 NewSQL 数据库中看到。但在阿里集团服役三年后,由于人员变动而逐步停止维护。这个时候 MyCAT 开源社区接过了该项目的衣钵,在其上增加了诸多功能并进行 bug 修改,最终使其在多个行业中占用自己的位置。

但是就像我曾经介绍的那样,中间件产品并不是真正的分布式数据库,它有自己的局限。比如 SQL 支持、查询性能、分布式事务、运维能力,等等,都有不可逾越的天花板。而有一些中间件产品幸运地得以继续进阶,最终演化为 NewSQL,甚至是云原生产品。阿里云的 PolarDB 就是这种类型的代表,它的前身是阿里云的分库分表中间件产品 DRDS,而 DRDS 来源于淘宝系的 TDDL 中间件。

PolarDB 相比于传统的中间件差别是采用了共享存储架构。率先采用这种架构的恰好也是一家电商到云计算的巨头:亚马逊。而这个数据库产品就是 Aurora。

Aurora 采用了这样一种架构。它将分片的分界线下移到事务及索引系统的下层。这个时候由于存储引擎保留了完整的事务系统,已经不是无状态的,通常会保留单独的节点来处理服务。这样存储引擎主要保留了计算相关逻辑,而底层存储负责了存储相关的像 redo、刷脏以及故障恢复。因此这种结构也就是我们常说的计算存储分离架构,也被称为共享盘架构。

PolarDB 在 Aurora 的基础上采用了另外一条路径。RDMA 的出现和普及,大大加快了网络间的网络传输速率,PolarDB 认为未来网络的速度会接近总线速度,也就是瓶颈不再是网络,而是软件栈。因此 PolarDB 采用新硬件结合 Bypass Kernel 的方式来实现高效的共享盘实现,进而支撑高效的数据库服务。由于 PolarDB 的分片层次更低,从而做到更好的生态兼容,这也就是为什么 PolarDB 能够很快做到社区版本的全覆盖。副本件 PoalrDB 采用了 ParalleRaft 来允许一定范围内的乱序确认、乱序 Commit 以及乱序 Apply。但是 PolarDB 由于修改了 MySQL 的源码和数据格式,故不能与 MySQL 混合部署,它更适合作为云原生被部署在云端提供 DBaaS 服务。

以 Spanner 为代表的“无共享”类型的 NewSQL 由于有较高的分片层次,可以获得接近传统分库分表的扩展性,因此容易在 TPCC 这样的场景下取得好成绩,但其需要做业务改造也是一个大的限制。以 Aurora 及 PolarDB 为代表的“共享存储”的 NewSQL 则更倾向于良好的生态兼容,几乎为零的业务改造,来交换了一定程度的可扩展性。

可以说从 Cobar 到现在的 PolarDB,我们看到了分布式数据库在电商与云计算领域的成长。其他典型代表如京东数科的 ShardingShpere 也有类似的发展脉络。可以说电商领域,乃至互联网行业,都进入了以自主知识产权研发的模式,对技术的掌控力较高,从而打造了良好的生态环境。

电信:去 IOE

电信作为重要的 IT 应用行业,过去 20 年一直引领着技术发展的潮流。但电信却又是关系到国计民生的重要行业,故技术路线相比于电商、互联网来说更为保守。其中 Oracle 数据库常年“霸占”着该领域,而分布式计算场景被众多子系统所承担着。以中国联通为例,在 2010 年前后,联通集团的各个省系统就有数百个之多,它们之间的数据是通过 ETL 工具进行同步,也就是从应用层保证了数据一致性。故从当时的情况看,其并没有对分布式数据库有很强的需求。

但在 2012 年前后,也就是距今大概 10 年前。中国联通开始尝试引入阿里集团的技术,其中上文提到的 Cobar 就在其中。为什么三大运营商中联通首先发力呢?原因是联通当年刚完成对老网通的合并,急需将移动网业务与固网业务进行整合。其次是联通集团总部倾向于打造全国集中系统,而这就需要阿里集团提供帮助。

根据当年参与该项目的人回忆,现场近千人一起参与,众多厂商系统工作,最终在距离承诺上线日期没几天的时候才完成了主要功能的验证。按现在的技术评估标准,当年这个项目并不是十分成功。但是这个项目把阿里的“去 IOE”理念深深地写入了电信领域内所有参与者的基因里面,从运营商到供应商,所有人都觉得分布式数据库的解决方案是未来的趋势。

而后 Cobar 衍生的 MyCAT 在联通与电信多个产品线开始落地,而各个供应商也开始模仿 Cobar 制作了自己的中间件产品。可以说,正是上面描述的背景,使数据库中间件模式逐步在电信领域内被广泛接受,其底色就是去“IOE”。

2016 年之后,电信行业没有放弃演化的步伐,各个主要供应商开始尝试去构建 NewSQL 数据库,其中特别是以 PGXC 架构为核心的 NewSQL 数据库引人瞩目。PGXC(PostgreSQL-XC)的本意是指一种以 PostgreSQL 为内核的开源分布式数据库。因为 PostgreSQL 的影响力和开放的软件版权协议(类似 BSD),很多厂商在 PGXC 上二次开发,推出自己的产品。不过,这些改动都没有变更主体架构风格,所以我把这类产品统称为 PGXC 风格,如亚信的 AntDB、人大金仓的 KingbaseDB 都是这类数据库的典型代表。此类数据库开始在行业内部快速落地。

近些年,电信行业内部也逐步接触了最具创新性的 NewSQL,但是此类数据库选择范围很小。电信运营商更倾向于与国内厂商合作,如 TiDB 和 OceanBase 已经有在三大运营商和铁搭公司上线的案例。不过,我们可以发现,目前新一代 NewSQL 接管的系统不是属于创新领域,就是属于边缘业务,还未触及核心系统。但是我们可以认为,未来将会有更多的场景使用到创新性的 NewSQL 数据库。

银行:稳中前进

银行与电信是非常类似的行业,但是银行的策略会更保守。银行并没有在内部推动轰轰烈烈的去“IOE”运动,故其在 OLTP 领域一直使用传统数据库,如 Oracle 和 DB2。

一直到近 5 年开始,银行的 IT 架构才发生重大调整。比如行业标杆的工商银行的架构改造在 2018 年大规模落地,而调研和试点工作则在更早的 2016~2017 年。这个时点上,商用 NewSQL 数据库刚刚推出不久,而金融场景的种种严苛要求,注定了银行不会做第一个吃螃蟹的人,那么这种可能性就被排除了。同样,另一种 PGXC 风格的分布式数据库也正待破茧而出,反而是它的前身,“分布式中间件 + 开源单体数据库”的组合更加普及。

后来的结果是工行选择了爱可生开源的 DBLE + MySQL 的组合,选择 MySQL 是因为它的普及程度足够高;而选择 DBLE 则因为它是在 MyCat 的基础上研发,号称“增强版 MyCat”,由于 MyCat 已经有较多的应用案例,所以这一点给 DBLE 带来不少加分。这一模式在工行内部推行得很好,最终使 MySQL 集群规模达到上千节点。虽然表面看起来还是非常保守,因为同期的电信行业已经开始推进 PGXC 架构落地了。但是工行,乃至真个银行行业,也走上了“去 IOE”的道路,可以想到,整个行业也是朝着 NewSQL 数据库的方向前进的。而且目前工商银行已经宣布与 OceanBase 进行合作,这预示着行业中 NewSQL 化的浪潮即将来临。

相对于 OLTP 技术应用上的平淡,工行在 OLAP 方面的技术创新则令人瞩目。基本是在同期,工行联合华为成功研发了 GaussDB 200,并在生产环境中投入使用。这款数据库对标了 Teradata 和 Greenplum 等国外 OLAP 数据库。在工行案例的加持下,目前不少银行计划或者正在使用这款产品替换 Teradata 数据库。

总结

我们可以从中看到一些共同点:

  1. 发展脉络都是单机数据库、中间件到 NewSQL,甚至电商领域开始做云计算;
  2. 各个行业依据自己的特点进行发展,虽然基本都经过了这些阶段,但是它们之间是有技术滞后性的;
  3. 先发展的行业带动了其他行业,特别是电商领域的技术被其他行业引用,达到了协同发展的效果;
  4. 国产数据库崛起,近年采购的全新架构的 NewSQL 数据库,我们都可以看到国产厂家的身影,一方面得力于国有电信、银行等企业的政策支持,另一方面国产数据库的进步也是大家有目共睹的。

这三个具有典型性的行业,为我们勾画来整个分布式数据库在中国的发展。希望你能从它们的发展轨迹中汲取养分,从而能使用分布式数据库为自己的工作、学习助力。

http://www.xdnf.cn/news/20589.html

相关文章:

  • Jakarta EE课程扩展阅读(二)
  • webpack和vite优化方案都有哪些
  • 【Beetle RP2350】雷达模块 CEM5861G-M11 开发使用指南
  • Mia for Gmail for Mac 邮件管理软件
  • 从全栈工程师视角解析Java与前端技术在电商场景中的应用
  • 【C++题解】DP入门-LISLCS
  • UE4/UE5反射系统动态注册机制解析
  • 线程间通信
  • 使用Terraform管理阿里云基础设施
  • 319章:使用Scrapy框架构建分布式爬虫
  • 还在重启应用改 Topic?Spring Boot 动态 Kafka 消费的“终极形态”
  • 企业级 Django 日志配置示例
  • 【三维生成】Matrix-3D:全向可探索的三维世界生成
  • 基于脚手架微服务的视频点播系统-播放控制部分
  • 算法题(201):传球游戏
  • 低代码开发平台.技术
  • Github操作
  • 训练+评估流程
  • java设计模式二、工厂
  • 5-2EFCore性能优化
  • FLINK:水位线的介绍
  • C/C++数据结构之栈基础
  • FastAPI + LangChain 和 Spring AI + LangChain4j
  • qt creator新手入门以及结合sql server数据库开发
  • Spring Cloud Gateway 进行集群化部署
  • Vscode中开发VUE项目的调试方案
  • Android开发-Activity传递信息
  • [论文阅读] 人工智能 + 软件工程 | 首个仓库级多任务调试数据集!RepoDebug揭秘LLM真实调试水平
  • Objective-C方法参数标签怎么设置
  • 华为基于IPD的产品质量计划模板