最近和科技同行交流,经常被问到分库分表和分布式数据库如何选择。网上也有很多关于中间件+传统关系型数据库(分库分表)和NewSQL分布式数据库的文章,但是一些观点和判断在我看来是偏激的,评价好坏其实是不公平的计划脱离环境。本文对两种模式的关键特性原理进行对比,希望尽可能客观中立地阐明它们真正的优缺点和适用场景。1、NewSQL数据库先进在哪里?首先,关于“中间件+关系型数据库分库分表”是否算NewSQL分布式数据库,有一篇国外论文pavlo-newsql-sigmodrec。按照本文的分类,Spanner、TiDB、OB是第一类新架构,Sharding-Sphere、Mycat、DRDS等中间件解决方案是第二类(本文还有第三类云数据库)文章,本文不再详细介绍)。基于中间件(包括SDK和Proxy)+传统关系数据库(分库分表)模式的模型是分布式架构吗?我是这么认为的,因为存储确实是分布式的,也可以实现横向扩展。但它不就是一个“伪”分布式数据库吗?从高级架构的角度来说,这样说是有道理的。“伪”主要体现在中间件层和底层DB之间重复的SQL解析和执行计划生成,存储引擎是基于B+Tree等,这在分布式数据库架构中实际上是冗余和低效的。为了避免因分布式数据库的真实性而引起的口水战,本文中的NewSQL数据库特指这种新架构的NewSQL数据库。与中间件+分库分表相比,NewSQL数据库先进在哪里?画一个简单的架构对比图:传统数据库是为磁盘设计的,基于内存的存储管理和并发控制效率不如NewSQL数据库;中间件模式SQL解析、执行计划优化等在中间件和数据库重复进行,效率比较低;NewSQL数据库的分布式事务相比XA进行了优化,性能更高;新架构NewSQL数据库存储设计基于paxos(或Raft)协议,相对于传统数据库主从模式(半同步转异步后同样存在数据丢失问题),实现了真正的高可用和高可靠性(RTO<30s,RPO=0);NewSQL数据库天然支持数据分片,数据迁移和扩容自动化,大大减轻了DBA的工作量。同时对应用透明,无需在SQL中指定分库分表键。这些大部分也是NewSQL数据库产品的主要宣传点,但是这些看似美好的功能真的如此吗?下面我就以上几点我的理解进行阐述。二、分布式事务这是一把双刃剑。1、CAP限制想想为什么早先出现的NoSQL数据库不支持分布式事务(最新版的MongoDB等也开始支持了),是不是缺乏理论和实践支持?不会,原因是CAP定理还是分布式数据库头上的魔咒,在保证强一致性的同时,必然会牺牲可用性A或者分区容错性P。为什么大多数NoSQL不提供分布式事务?那么NewSQL数据库是否突破了CAP定理的限制呢?不是,NewSQL数据库的鼻祖GoogleSpanner(目前大部分分布式数据库都是按照Spanner架构设计的),提供了超过5个9的一致性和可用性。它自称是“实际CA”,其真正含义是系统处于CA状态的概率非常高,因为网络分区导致服务中断的概率非常小。真正的原因是它构建了一个私有的全局网络,保证不会出现网络中断导致的网络分区,其高效的运行,这也是cloudspanner的卖点。详见CAP提议者EricBrewer撰写的《Spanner, TrueTime和CAP理论》。2.完整性。两阶段提交协议是否严格支持ACID,能否覆盖所有异常场景?2PC在提交阶段发送异常。其实和best-effortone-phasecommit类似,也会有一些看得见的问题。严格来说,一段时间内A的原子性和C的一致性是无法保证的(恢复机制可以保证故障恢复后最终的A和C)。完整的分布式事务支持不是一件简单的事情。需要能够处理网络和各种硬件的各种异常,包括网卡、磁盘、CPU、内存、电源等,并通过严格的测试。之前和一个朋友交流过,他们甚至说目前已知的NewSQL在分布式事务支持方面是不完善的,都有逃不掉的情况。圈内人都这么肯定,这也说明了分布式事务支持的完备性。事实上,这是不平衡的。但是分布式事务是这些NewSQL数据库非常重要的底层机制。跨资源DML和DDL依赖于它的实现。如果该块的性能和完整性受到损害,将影响上层跨分片SQL执行的正确性。大的影响。3、性能传统关系型数据库也支持分布式事务XA,但为什么很少在高并发场景下使用?由于XA的基本两阶段提交协议存在网络开销大、阻塞时间长、死锁等问题,这也导致在基于传统关系型数据库的OLTP系统中实际上很少大规模使用。NewSQL数据库的分布式事务实现仍然主要基于两阶段提交协议。比如googlepercolator分布式事务模型就是采用原子钟+MVCC+SnapshotIsolation(SI)。此方法通过TSO(TimestampOracle)确保全局一致性。MVCC避免了锁,通过primarylock和secondarylock将部分提交转换为异步,相对于XA确实提高了分布式事务的性能。SI是乐观锁。在热点数据场景下,可能会出现大量提交失败的情况。另外,SI的隔离级别和RR的隔离级别也不完全一样。它不会有幻读,但会有写偏斜。但无论怎么优化,相比1PC,2PC额外的GID获取、网络开销、prepare日志持久化等,还是会带来不小的性能损耗,尤其是在跨节点数量比较多的情况下,比如银行场景。批量扣款,W账号可以上传一个文件。这样的场景,无论怎么做,吞吐量都不会很高。▲Spanner给出的分布式事务测试数据虽然NewSQL分布式数据库产品标榜全面支持分布式事务,但这并不代表应用完全不需要关心数据拆分。这些数据库的优秀实践还是会写的。应用在大多数场景下,尽量避免分布式事务。既然强一致性事务的性能成本太高,我们可以反思一下,我们是否真的需要这样的强一致性分布式事务?尤其是微服务拆分后,不太可能会有很多系统放在一个统一的数据库中。尽量弱化一致性要求,即灵活事务,摒弃ACID(Atomicity,Consistency,Isolation,Durability)转为BASE(BasicallyAvailable,Softstate,Eventuallyconsistent),如Saga,TCC,可靠消息保证最终一致性和其他模型一样,对于大规模高并发的OLTP场景,我个人更推荐使用灵活事务而不是强一致性分布式事务。关于flexible事务,笔者之前也写过一个技术组件,这几年也出现了一些新的模型和框架(比如Fescar,刚刚被阿里开源),限于篇幅不再赘述。只能用两阶段提交协议来解决分布式事务吗?OceanBase1.0中通过updateserver避免分布式事务的思路很有启发,但是2.0版本之后也变成了2PC。业界的分布式事务并不是两阶段提交的唯一解决方案。3.HA和远程多活主从模式不是最好的方式。即使是半同步复制,在极端情况下(半同步转异步),依然存在数据丢失的问题。目前业界普遍认为基于Paxos分布的更好的解决方案。GoogleSpanner、TiDB、CockcoachDB、OB都采用这种方式。基于Paxos协议的多副本存储,遵循多半写入原则,支持自动选主,解决数据量大的问题。可靠,缩短故障转移时间,提高易用性,尤其是减少运维工作量。该方案技术成熟,也是底层NewSQL数据库的标准配置。当然,这种方法也可以用在传统的关系型数据库中。阿里和微信团队也改造了MySQL存储,支持paxos的多副本。MySQL也推出了正式版的MySQLGroupCluster。预计主从模式或将成为历史。分布式共识算法本身并不难,但是在工程实践中,需要考虑很多异常情况,需要做很多优化。实现生产级可靠成熟的共识协议并不容易。比如在实际使用中,必须转化为multi-paxos或者multi-raft,需要通过批处理和异步的方式来减少网络、磁盘IO等开销。需要注意的是,很多NewSQL数据库厂商都标榜基于Paxos或者Raft协议,可以实现【异地多活】。这其实有一个前提,就是异地之间的网络延迟不能太高。以银行“两地三中心”为例。异地之间的距离通常是几千里,延迟可达几十毫秒。没有OLTP系统是可以接受的。在数据库层面做异地多活是一个美好的愿景,但是对于距离带来的延迟目前还没有很好的解决方案。之前和Ant团队交流过,Ant异地多活的解决方案是在应用层通过MQ同步双写事务信息,远程DC将事务信息存储在分布式缓存中。一旦发生异地切换,数据库同步中间件会通知数据延迟时间,应用程序从缓存中读取交易信息,将这段时间涉及的业务对象,如用户、账户等列入黑名单,并将这些业务对象从中移除数据同步后的黑名单。由于双写的不是所有的数据库操作日志,只是事务信息,所以数据延迟只影响一定时间段内的数据。这是目前我认为比较靠谱的远程多活方案。此外,一些系统进行了单元改造,这也是选择Paxos的master时要考虑的因素。这也是目前很多NewSQL数据库所欠缺的功能。4.Scale水平扩展和sharding机制paxos算法解决了高可用和高可靠的问题,但是没有解决Scale水平扩展的问题,所以必须支持sharding。NewSQL数据库天生内置分片机制,会根据每个分片的数据负载(磁盘使用率、写入速度等)自动识别热点,进行分片、数据迁移、合并分片。这些过程应用起来是潜移默化的,节省了DBA大量的运维工作量。以TiDB为例,它将数据切分成region,当region达到64M时,会自动迁移数据。分库分表模式下,需要指定拆分键、拆分方式(范围、取模、一致性哈希或自定义路由表)、路由规则、拆分数据库表数、扩容方式等。比较对于NewSQL数据库,这种模式给应用带来了很大的侵入性和复杂性,这对大多数系统来说也是一个很大的挑战。分库分表模式也可以实现在线扩展。基本思路是先通过异步复制添加数据,然后设置只读完成路由切换,最后释放写操作。当然,这些都需要中间件和数据库端的配合才能完成。这里的问题是,NewSQL数据库内置的统一分片策略(比如TiDB是基于range的)可能不是最高效的,因为它与领域模型中的分片元素不一致。因此,很多事务都会产生分布式事务。比如银行的核心业务系统以客户为维度,也就是说客户表、客户账户表、流水表在大多数场景下是写在一起的,但是如果按照每个表的主键范围,这个事务不能在一个shard上完成,在高频OLTP系统中会造成性能问题。5、分布式SQL支持普通的单分片SQL,两者都可以很好的支持。由于NewSQL数据库的定位和目标是通用型数据库,所以它支持的SQL更加完备,包括跨分片join、聚合等复杂SQL。中间件模式多为应用需求而设计,但大多也支持带分键的SQL、数据库表遍历、单库join、聚合、排序、分页等,但对跨库join和聚合的支持不够.NewSQL数据库一般不支持存储过程、视图、外键等功能,而中间件模型的底层是传统的关系型数据库。如果这些功能只涉及一个单一的数据库,那么支持它们就更容易了。NewSQL数据库往往选择兼容MySQL或PostgreSQL协议,因此SQL支持仅限于这两者。驱动模型等中间件往往只需要做简单的SQL解析、计算路由、SQL重写,因此可以支持更多类型的数据库SQL。SQL支持的不同主要在于分布式SQL执行计划生成器。由于NewSQL数据库具有底层数据的分布和统计信息,可以作为CBO使用,生成的执行计划更加高效。可以基于基于规则的RBO(Rule-Based-Opimization),这也是为什么中间件模式一般不支持跨库join的原因,因为实现效率往往不高,留给应用。从这里也可以看出,中间件+分库分表模式的架构风格体现了一种折衷和平衡,是一种面向应用的设计;而NewSQL数据库要求更高,“大包大包”。它是一种通用的底层技术软件,因此后者的复杂度和技术门槛要高得多。6、存储引擎传统关系型数据库的存储引擎设计都是面向磁盘的,大部分都是基于B+树的。B+树通过降低树的高度来减少随机读,从而减少磁盘寻道次数,提高读性能。但是大量的随机写会导致树分裂,造成随机写,导致写性能下降。NewSQL底层存储引擎多采用LSM。与B+树LSM相比,将磁盘的随机写入改为顺序写入,大大提高了写入性能。但是由于需要合并数据,LSM的读取性能比B+树差。一般来说,LSM更适合写大于读的场景。当然,这只是从纯数据结构的角度进行比较。在数据库的实际实现中,会通过SSD、buffer、bloomfilter等手段优化读写性能,所以读性能基本不会下降太多。由于多副本和分布式事务的开销,NewSQL数据的响应时间并不优于单机关系数据库SQL。但由于集群弹性扩容,整体QPS提升还是比较明显的。这就是NewSQL数据库厂商对分布式数据库的说法。更重要的是吞吐量,而不是单个SQL响应时间的原因。7.成熟度与生态分布式数据库是一种新型的通用底层软件。精准的测评需要多维度的测试模型,需要包括开发状态、使用情况、社区生态、监控运维、周边配套工具、功能满意度、DBA人才、SQL兼容性、性能测试、高可用测试、在线扩展、分布式事务、隔离级别、在线DDL等。NewSQL数据库的开发虽然经过了一定时间的考验,但多集中在互联网和非核心传统企业的交易系统中,还处于快速迭代和规模使用不断优化提升的阶段。相比之下,传统的关系数据库已经发展了很多年。通过完整评估,它们在成熟度、功能、性能、周边生态、风险控制、相关人才积累等方面具有明显优势。系统兼容性也更好。对于互联网公司来说,数据量压力越来越大,追求新技术的基因,会更倾向于尝试NewSQL数据库,无需考虑数据库分表、应用改造、扩容、事务一致性等问题。它是一个非常有吸引力的解决方案。.对于银行等传统企业、风险意识较高的行业,未来一段时间,NewSQL数据库可能仍处于探索和审慎试点阶段。基于中间件+分库分表模式,架构简单,技术门槛较低。虽然不如NewSQL数据库全面,但大部分场景的核心需求是拆分后SQL的正确路由。这个功能的中间件模式还是绰绰有余的,可以说在大部分的OLTP场景下都够用了。限于篇幅,在线DDL、数据迁移、运维工具等其他特性本文不再对比。8.小结如果看完以上内容,你还是不知道选择哪种模式,那么结合下面的问题,先想想NewSQL数据库解决的点是不是自己真正的痛点:强一致性事务是否必须在数据库层解决?数据的增长速度是否不可预测?扩容的频率是否超出了自身的运维能力?吞吐量比响应时间更重要吗?是否有必要对应用程序完全透明?有熟悉NewSQL数据库的DBA团队吗?以上两三个是肯定的,那么可以考虑使用NewSQL数据库。虽然前期可能需要一定的学习成本,但是是数据库的发展方向,未来收益会更高,尤其是在互联网行业。随着数据量的飞速发展,分库分表带来的痛苦会与日俱增。当然,如果选择NewSQL数据库,就要做好承担一定风险的准备。如果你还没有做出决定,请思考以下问题:最终一致性能否满足实际场景?能否预估未来几年的数据总量?扩容、DDL等操作是否有系统维护窗口?是响应时间是否比吞吐量更敏感?它是否需要与现有的关系数据库系统兼容?是否有传统数据库DBA人才积累?分库分表的入侵能容忍吗?如果这些问题大部分都是肯定的,那我们就分库分表吧。软件领域几乎没有完美的解决方案,NewSQL数据库也不是数据分布式架构的灵丹妙药。相比之下,分库分表是一种成本更低、风险更小的方案。最大程度的复用了传统的关系型数据库生态。通过中间件,也可以满足分库分表后的大部分功能。定制能力更强。在NewSQL数据库尚未完全成熟的现阶段,分库分表可以说是一种上限低下限高的解决方案,尤其是对于传统行业的核心系统。如果您仍然打算将数据库用作黑盒产品,请确保Practical分库分表将被认为是一个安全的选择。笔者介绍了在中国民生银行信息科技部工作的温伟斌。目前负责分布式技术平台的设计与开发,专注于分布式数据相关领域。
