数据库 频道

老乡,你是在使用分布式数据库!

最近很多客户在考虑将Oracle迁移到国产平台,数据库选型与迁移方案设计是其中最受关注的。很多客户在做这件事之前,对分布式数据库并不了解,只是听厂商宣传过分布式数据库相比集中式数据库更优越的地方。我们的分布式数据库厂商在做售前宣传的时候肯定会强调分布式数据库优于集中式数据库的地方,比如性能卓越,可横向扩展,高可用防单点故障等。而对于分布式数据库的一些缺点,或者说使用分布式数据库需要用户与开发厂商对应用做相关优化的地方,一般是不会提及的。只有当用户在使用过程中遇到问题了,才会拿出一大堆资料来告诉用户,分布式数据库该怎么使用。

正是基于此,很多用户对于分布式数据库的理解完全是片面的。前几天几个朋友小聚,有个用户就问我他们的数据库一般来说2-3个TB,不过业务比较复杂,应用里经常有通过十多张表关联查询才能完成的SQL。他们想把数据库从Oracle换成国产数据库,目前初步想选分布式数据库,问我有什么推荐没有。我想了想说这种业务系统,其实选个PG类的国产数据库就够用了,并不是一定要选择分布式数据库,因为你们的应用开发与运维能力并不强,也不太希望在这里额外做较大的投入。

我没有给他推荐分布式数据库的主要原因首先是他们的数据库规模并不大,集中式数据库能解决他们大多数的问题。而分布式数据库是十分复杂的,如果他们的应用开发能力不强,可能不一定能用得好分布式数据库。因为和传统的集中式数据库相比,分布式数据库是完全不同的。

分布式数据库的不同首先体现在全局事务与本地事务的区别上。根据分布式系统的CAP原理,我们知道分布式系统在关系型模型上永远不可能达到集中式系统的完美一致性。而全局事务与本地事务的实现方式是存在级差的,本地事务是全局事务的子集。早些年玩过XA和基于DBLINK的分布式事务的朋友可能还会有分布式事务锁表,导致业务长期无法恢复的经历。二十年前,我靠着处理ORA-1591的经验,帮助很多客户做过全局事务故障处理。一旦出现分布式事务故障,重启数据库实例都无法解锁,必须在本地强制回滚或者强制提交出故障分布式事务中的本地事务,才能解开相关的锁。目前分布式数据库的全局事务的实现方式虽然和当年XA有所不同,但是其基本原理是类似的,全局事务在每个分布式分片上都会有本地事务。比如Gaussdb在全局事务启动的时候,会通过GTM生成全局的XID,在事务提交时会生成CSN,然后通过CSNLOG将XID和CSN的MAP记录下来。对于Gaussdb这样的分布式数据库,GTM是十分关键的部件。全局事务因为涉及到集群内多个节点之间的协同,因此也是要有开销的,分布式数据库的节点越多,这种开销也越大。虽然数据库厂商会通过优化数据库事务管理方面的代码来优化这方面的性能,不过这种开销是存在的,而且不低。Gaussdb使用GTM-LITE将事务进行前置分类,本地事务并不由GTM管理,而由本地的LTM来管理,从而减轻GTM的负担,同时降低本地事务的延时。甚至在某些场景下,通过启用GTM-FREE,让数据库的所有事务都变成本地事务,GTM不参与所有事务的管理。GTM-FREE模式放弃了全局事务的读一致性,让所有的业务都变成了最终结果一致性,从而大大提升了系统的处理能力,提高了每个交易的性能,这实际上也是符合CAP的。

现在很多金融机构选择分布式数据库,其实在应用研发时,还是要充分考虑全局事务带来的交易延时的,特别是现在网联监控十分严格的今天,如果现在使用Oracle就经常出现网联交易延时告警,那么在应用迁移的时候,一定要充分考虑较高并发时全局事务带来的延时开销问题,否则等应用上线时再去优化可能就晚了。这类应用在使用分布式数据库的时候,在有可能的情况下,尽可能把一些分布式事务尽可能降级为本地事务,也是一种常规的设计方法。不过要把一个应用中的各类核心业务表、参照表等都做了十分清晰的分析,才能做出此类设计,这对应用开发厂商的能力也提出了新的要求。

分布式数据库的第二个不同体现在数据分布差异性上。集中式数据库上我们其实也要关注数据的分布,数据库表的高水位,碎片等也是会引发某些业务性能问题的主要问题。因此集中式数据库中也出现了shrink,move,redefine等功能,用于处理这些数据分布的问题。到了分布式数据库上,数据分布问题就更为复杂了。首先我们在使用分布式数据库的时候,需要一些比使用集中式数据库更加复杂的设计。哪些表是可以单节点本地存储的,哪些是要分布式存储的。哪些表是要采用复制存储的。

分布式存储的表往往是业务的核心表,数据量较大,读写都比较频繁,可以通过某个键值或者键值组打散分布在分布式数据库的多个节点上,充分利用分布式数据库的可扩展能力来不断扩展。

单节点存储的表往往是修改比较频繁,但是和其他表关联关系不大的表,大多数业务都是单表操作。此类表被设计为均匀的分布在分布式数据库的多个节点上。

复制存储的往往是一些参数表或者参照表,这些表比较小,修改不频繁。不过经常被用在与分布式存储的表的关联查询上。这些表如果在分布式存储的标的各个数据库节点上都存有副本,那么在做表关联查询的时候就可以通过算子下推在本地完成大量的计算,从而提升分布式执行计划的性能。

在分布式数据库上设计好表的数据分布方式并不容易,因为业务的复杂性决定了不同的表的分区键可能会有所不同,业务相关性较强的表也不一定能够把需要JOIN的所有数据都采用一样的分区键值存储在一起。像Oceanbase这样的数据库还提供了TABLE GROUP这样的概念,如果有一组表经常在SQL中做JOIN,而且分区键相同,那么通过设置TABLE GROUP可以让这些表的键值相同的数据都存储在同一个OBSERVER上,从而避免JOIN时的读放大问题。这些比较亲民的数据库特性可以简化一些此类设计的问题。不过如果开发人员不掌握这些技能,就无法充分利用到分布式数据库提供的特性。不幸的是,不同的分布式数据库中,这些贴心的优化功能是不同的,我们需要分别去学习这些,这对于应用开发者来说,也是一种灾难。

分布式数据库的第三个不同体现在高可用架构上。现在大多数分布式数据库都采用多副本机制来避免单点故障导致的整体故障。为了提高性能,一般的设计模式都是一个主副本带一两个备副本。而主副本与备副本之间是采用半同步模式的,也是就是说当REDO/WAL被多数派副本接受后,选举算法就认为数据提交完成了。而副本的数据与MASTER之间是可以存在一定的延时的。这就导致了一旦MASTER故障后,SLAVER虽然可以很快通过共识算法选举出新的MASTER,但是Master并不是马上就能开始工作的,而是需要新的Master完全追平后,才能真正接管。而业务彻底恢复之前还有很多事情要做,那就是全局事务的回滚处理以及锁的清理工作。因此分布式数据库的高可用并不像我们想象那么丝滑。很多分布式数据库宣称故障切换时间是30秒以内,而实际上在一些复杂的应用环境中,30秒是最理想的状态,实际情况要更长一些。有些时候甚至会出现故障切换后数分钟业务都无法完全恢复的情况。而且当系统处于这种情况的时候,大多数情况下,运维是无法干预的,只能静待系统自动完成这些处置。

虽然对于大多数业务系统而言,一两分钟的故障切换是可以忍受的,不过对于证券这样的业务来说,依然十分致命。因此我们需要在两个方面来解决这个问题。第一个方面是增强硬件底层的可靠性,尽可能减少此类故障切换,如果只是服务器宕机才会出现此类切换,那么以当前服务器的可靠性来看,此类故障切换就会降低到很低的限度。其次是如果我们的交易十分关键,那么尽可能降低核心交易系统的复杂性,减小事务的大小,同时降低IO、网络等硬件的延时,从而让此类故障切换的时间尽可能的降低。

本文到这里其实还没写完,分布式数据库太复杂了,仅仅讨论三个问题就写了这么多了。今天就这样吧,如果大家对分布式数据库的使用还需要了解更多的内容。那么我们下回再写吧。需要了解一些什么方面的内容,可以给我留言,如果我对此有些心得,我会和大家分享的。

0
相关文章