分库分表 vs NewSQL数据库

最近与同行科技交流,常常被问到分库分表与分布式数据库如何选择,网上也有不少关于中间件+传统关系数据库(分库分表)与NewSQL分布式数据库的文章,但有些观点与判断是我以为是偏激的,脱离环境去评价方案好坏其实有失公允。html

本文经过对两种模式关键特性实现原理对比,但愿能够尽量客观、中立的阐明各自真实的优缺点以及适用场景。算法

NewSQL数据库先进在哪儿?

首先关于“中间件+关系数据库分库分表”算不算NewSQL分布式数据库问题,国外有篇论文pavlo-newsql-sigmodrec,若是根据该文中的分类,Spanner、TiDB、OB算是第一种新架构型,Sharding-Sphere、Mycat、DRDS等中间件方案算是第二种(文中还有第三种云数据库,本文暂不详细介绍)。
基于中间件(包括SDK和Proxy两种形式)+传统关系数据库(分库分表)模式是否是分布式架构?我以为是的,由于存储确实也分布式了,也能实现横向扩展。可是不是"伪"分布式数据库?从架构先进性来看,这么说也有必定道理。"伪"主要体如今中间件层与底层DB重复的SQL解析与执行计划生成、存储引擎基于B+Tree等,这在分布式数据库架构中实际上冗余低效的。为了不引发真伪分布式数据库的口水战,本文中NewSQL数据库特指这种新架构NewSQL数据库。sql

NewSQL数据库相比中间件+分库分表的先进在哪儿?画一个简单的架构对比图:数据库

 
 
 
  1. 传统数据库面向磁盘设计,基于内存的存储管理及并发控制,不如NewSQL数据库那般高效利用。
  2. 中间件模式SQL解析、执行计划优化等在中间件与数据库中重复工做,效率相比较低;
  3. NewSQL数据库的分布式事务相比于XA进行了优化,性能更高;
  4. 新架构NewSQL数据库存储设计即为基于paxos(或Raft)协议的多副本,相比于传统数据库主从模式(半同步转异步后也存在丢数问题),在实现了真正的高可用、高可靠(RTO<30s,RPO=0)
  5. NewSQL数据库天生支持数据分片,数据的迁移、扩容都是自动化的,大大减轻了DBA的工做,同时对应用透明,无需在SQL指定分库分表键。

这些大多也是NewSQL数据库产品主要宣传的点,不过这些看起来很美好的功能是否真的如此?接下来针对以上几点分别阐述下的个人理解。缓存

分布式事务

这是把双刃剑。微信

CAP限制

想一想更早些出现的NoSQL数据库为什么不支持分布式事务(最新版的mongoDB等也开始支持了),是缺少理论与实践支撑吗?并非,缘由是CAP定理依然是分布式数据库头上的颈箍咒,在保证强一致的同时必然会牺牲可用性A或分区容忍性P。为何大部分NoSQL不提供分布式事务?网络

那么NewSQL数据库突破CAP定理限制了吗?并无。NewSQL数据库的鼻主Google Spanner(目前绝大部分分布式数据库都是按照Spanner架构设计的)提供了一致性和大于5个9的可用性,宣称是一个“其实是CA”的,其真正的含义是系统处于 CA 状态的几率很是高,因为网络分区致使的服务停用的几率很是小,究其真正缘由是其打造私有全球网保证了不会出现网络中断引起的网络分区,另外就是其高效的运维队伍,这也是cloud spanner的卖点。详细可见CAP提出者Eric Brewer写的《Spanner, TrueTime 和CAP理论》数据结构

推荐一篇关于分布式系统有趣的文章,站在巨人的分布式肩膀上,其中提到:分布式系统中,您能够知道工做在哪里,或者您能够知道工做什么时候完成,但您没法同时了解二者;两阶段协议本质上是反可用性协议。架构

完备性:

两阶段提交协议是否严格支持ACID,各类异常场景是否是均可以覆盖?
2PC在commit阶段发送异常,其实跟最大努力一阶段提交相似也会有部分可见问题,严格讲一段时间内并不能保证A原子性和C一致性(待故障恢复后recovery机制能够保证最终的A和C)。完备的分布式事务支持并非一件简单的事情,须要能够应对网络以及各类硬件包括网卡、磁盘、CPU、内存、电源等各种异常,经过严格的测试。以前跟某友商交流,他们甚至说目前已知的NewSQL在分布式事务支持上都是不完整的,他们都有案例跑不过,圈内人士这么笃定,也说明了分布式事务的支持完整程度实际上是层次不齐的。并发

但分布式事务又是这些NewSQL数据库的一个很是重要的底层机制,跨资源的DML、DDL等都依赖其实现,若是这块的性能、完备性打折扣,上层跨分片SQL执行的正确性会受到很大影响。

性能

传统关系数据库也支持分布式事务XA,但为什么不多有高并发场景下用呢? 由于XA的基础两阶段提交协议存在网络开销大,阻塞时间长、死锁等问题,这也致使了其实际上不多大规模用在基于传统关系数据库的OLTP系统中。
NewSQL数据库的分布式事务实现也仍然多基于两阶段提交协议,例如google percolator分布式事务模型,
采用原子钟+MVCC+ Snapshot Isolation(SI),这种方式经过TSO(Timestamp Oracle)保证了全局一致性,经过MVCC避免了锁,另外经过primary lock和secondary lock将提交的一部分转为异步,相比XA确实提升了分布式事务的性能。

SI是乐观锁,在热点数据场景,可能会大量的提交失败。另外SI的隔离级别与RR并不是彻底相同,它不会有幻想读,但会有写倾斜。

但无论如何优化,相比于1PC,2PC多出来的GID获取、网络开销、prepare日志持久化仍是会带来很大的性能损失,尤为是跨节点的数量比较多时会更加显著,例如在银行场景作个批量扣款,一个文件可能上W个帐户,这样的场景不管怎么作仍是吞吐都不会很高。

Spanner给出的分布式事务测试数据

虽然NewSQL分布式数据库产品都宣传完备支持分布式事务,但这并非说应用能够彻底不用关心数据拆分,这些数据库的最佳实践中仍然会写到,应用的大部分场景尽量避免分布式事务。

既然强一致事务付出的性能代价太大,咱们能够反思下是否真的须要这种强一致的分布式事务?尤为是在作微服务拆分后,不少系统也不太可能放在一个统一的数据库中。尝试将一致性要求弱化,即是柔性事务,放弃ACID(Atomicity,Consistency, Isolation, Durability),转投BASE(Basically Available,Soft state,Eventually consistent),例如Saga、TCC、可靠消息保证最终一致等模型,对于大规模高并发OLTP场景,我我的更建议使用柔性事务而非强一致的分布式事务。关于柔性事务,笔者以前也写过一个技术组件,最近几年也涌现出了一些新的模型与框架(例如阿里刚开源的Fescar),限于篇幅再也不赘述,有空再单独写篇文章。

解决分布式事务是否只能用两阶段提交协议?
oceanbase1.0中经过updateserver避免分布式事务的思路颇有启发性 ,不过2.0版后也变成了2PC。
业界分布式事务也并不是只有两阶段提交这一解,也有其它方案its-time-to-move-on-from-two-phase(若是打不开,国内有翻译版https://www.jdon.com/51588)

HA与异地多活

主从模式并非最优的方式,就算是半同步复制,在极端状况下(半同步转异步)也存在丢数问题,目前业界公认更好的方案是基于paxos分布式一致性协议或者其它类paxos如raft方式,Google Spanner、TiDB、cockcoachDB、OB都采用了这种方式,基于Paxos协议的多副本存储,遵循过半写原则,支持自动选主,解决了数据的高可靠,缩短了failover时间,提升了可用性,特别是减小了运维的工做量,这种方案技术上已经很成熟,也是NewSQL数据库底层的标配。
固然这种方式其实也能够用在传统关系数据库,阿里、微信团队等也有将MySQL存储改造支持paxos多副本的,MySQL也推出了官方版MySQL Group Cluster,预计不远的将来主从模式可能就成为历史了。

分布式一致性算法自己并不难,但具体在工程实践时,须要考虑不少异常并作不少优化,实现一个生产级可靠成熟的一致性协议并不容易。例如实际使用时必须转化实现为multi-paxos或multi-raft,须要经过batch、异步等方式减小网络、磁盘IO等开销。

须要注意的是不少NewSQL数据库厂商宣传基于paxos或raft协议能够实现【异地多活】,这个其实是有前提的,那就是异地之间网络延迟不能过高。以银行“两地三中心”为例,异地之间多相隔数千里,延时达到数十毫秒,若是要多活,那便需异地副本也参与数据库日志过半确认,这样高的延时几乎没有OLTP系统能够接受的。

数据库层面作异地多活是个美好的愿景,但距离致使的延时目前并无好的方案。以前跟蚂蚁团队交流,蚂蚁异地多活的方案是在应用层经过MQ同步双写交易信息,异地DC将交易信息保存在分布式缓存中,一旦发生异地切换,数据库同步中间件会告之数据延迟时间,应用从缓存中读取交易信息,将这段时间内涉及到的业务对象例如用户、帐户进行黑名单管理,等数据同步追上以后再将这些业务对象从黑名单中剔除。因为双写的不是全部数据库操做日志而只是交易信息,数据延迟只影响一段时间内数据,这是目前我以为比较靠谱的异地度多活方案。

另外有些系统进行了单元化改造,这在paxos选主时也要结合考虑进去,这也是目前不少NewSQL数据库欠缺的功能。

Scale横向扩展与分片机制

paxos算法解决了高可用、高可靠问题,并无解决Scale横向扩展的问题,因此分片是必须支持的。NewSQL数据库都是天生内置分片机制的,并且会根据每一个分片的数据负载(磁盘使用率、写入速度等)自动识别热点,而后进行分片的分裂、数据迁移、合并,这些过程应用是无感知的,这省去了DBA的不少运维工做量。以TiDB为例,它将数据切成region,若是region到64M时,数据自动进行迁移。

分库分表模式下须要应用设计之初就要明确各表的拆分键、拆分方式(range、取模、一致性哈希或者自定义路由表)、路由规则、拆分库表数量、扩容方式等。相比NewSQL数据库,这种模式给应用带来了很大侵入和复杂度,这对大多数系统来讲也是一大挑战。

分库分表模式也能作到在线扩容,基本思路是经过异步复制先追加数据,而后设置只读完成路由切换,最后放开写操做,固然这些须要中间件与数据库端配合一块儿才能完成。

这里有个问题是NewSQL数据库统一的内置分片策略(例如tidb基于range)可能并非最高效的,由于与领域模型中的划分要素并不一致,这致使的后果是不少交易会产生分布式事务。举个例子,银行核心业务系统是以客户为维度,也就是说客户表、该客户的帐户表、流水表在绝大部分场景下是一块儿写的,但若是按照各表主键range进行分片,这个交易并不能在一个分片上完成,这在高频OLTP系统中会带来性能问题。

分布式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数据库则要求更高、“大包大揽”,它是一个通用底层技术软件,所以后者的复杂度、技术门槛也高不少。

存储引擎

传统关系数据库的存储引擎设计都是面向磁盘的,大多都基于B+树。B+树经过下降树的高度减小随机读、进而减小磁盘寻道次数,提升读的性能,但大量的随机写会致使树的分裂,从而带来随机写,致使写性能降低。NewSQL的底层存储引擎则多采用LSM,相比B+树LSM将对磁盘的随机写变成顺序写,大大提升了写的性能。不过LSM的的读因为须要合并数据性能比B+树差,通常来讲LSM更适合应在写大于读的场景。固然这只是单纯数据结构角度的对比,在数据库实际实现时还会经过SSD、缓冲、bloom filter等方式优化读写性能,因此读性能基本不会降低太多。NewSQL数据因为多副本、分布式事务等开销,相比单机关系数据库SQL的响应时间并不占优,但因为集群的弹性扩展,总体QPS提高仍是很明显的,这也是NewSQL数据库厂商说分布式数据库更看重的是吞吐,而不是单笔SQL响应时间的缘由。

成熟度与生态

分布式数据库是个新型通用底层软件,准确的衡量与评价须要一个多维度的测试模型,需包括发展示状、使用状况、社区生态、监控运维、周边配套工具、功能知足度、DBA人才、SQL兼容性、性能测试、高可用测试、在线扩容、分布式事务、隔离级别、在线DDL等等,虽然NewSQL数据库发展通过了必定时间检验,但多集中在互联网以及传统企业非核心交易系统中,目前还处于快速迭代、规模使用不断优化完善的阶段。
相比而言,传统关系数据库则通过了多年的发展,经过完整的评测,在成熟度、功能、性能、周边生态、风险把控、相关人才积累等多方面都具备明显优点,同时对已建系统的兼容性也更好。
对于互联网公司,数据量的增加压力以及追求新技术的基因会更倾向于尝试NewSQL数据库,不用再考虑库表拆分、应用改造、扩容、事务一致性等问题怎么看都是很是吸引人的方案。
对于传统企业例如银行这种风险意识较高的行业来讲,NewSQL数据库则可能在将来一段时间内仍处于探索、审慎试点的阶段。基于中间件+分库分表模式架构简单,技术门槛更低,虽然没有NewSQL数据库功能全面,但大部分场景最核心的诉求也就是拆分后SQL的正确路由,而此功能中间件模式应对仍是绰绰有余的,能够说在大多数OLTP场景是够用的。

限于篇幅,其它特性例如在线DDL、数据迁移、运维工具等特性就不在本文展开对比。

总结

若是看完以上内容,您还不知道选哪一种模式,那么结合如下几个问题,先思考下NewSQL数据库解决的点对于自身是否是真正的痛点:

  • 强一致事务是否必须在数据库层解决?
  • 数据的增加速度是否不可预估的?
  • 扩容的频率是否已超出了自身运维能力?
  • 相比响应时间更看重吞吐?
  • 是否必须作到对应用彻底透明?
  • 是否有熟悉NewSQL数据库的DBA团队?

若是以上有2到3个是确定的,那么你能够考虑用NewSQL数据库了,虽然前期可能须要必定的学习成本,但它是数据库的发展方向,将来收益也会更高,尤为是互联网行业,随着数据量的日新月异,分库分表带来的痛苦会与日俱增。固然选择NewSQL数据库你也要作好承担必定风险的准备。
若是你还未作出抉择,不妨再想一想下面几个问题:

  • 最终一致性是否能够知足实际场景?
  • 数据将来几年的总量是否能够预估?
  • 扩容、DDL等操做是否有系统维护窗口?
  • 对响应时间是否比吞吐更敏感?
  • 是否须要兼容已有的关系数据库系统?
  • 是否已有传统数据库DBA人才的积累?
  • 是否可容忍分库分表对应用的侵入?

若是这些问题有多数是确定的,那仍是分库分表吧。在软件领域不多有完美的解决方案,NewSQL数据库也不是数据分布式架构的银弹。相比而言分库分表是一个代价更低、风险更小的方案,它最大程度复用传统关系数据库生态,经过中间件也能够知足分库分表后的绝大多数功能,定制化能力更强。在当前NewSQL数据库还未彻底成熟的阶段,分库分表能够说是一个上限低但下限高的方案,尤为传统行业的核心系统,若是你仍然打算把数据库当作一个黑盒产品来用,踏踏实实用好分库分表会被认为是个稳妥的选择。

不少时候软件选型取决于领域特征以及架构师风格,限于笔者知识与所属行业特色所限,以上仅为我的粗浅的一些观点,欢迎讨论。

做者:蚊子squirrel 连接:https://www.jianshu.com/p/9131edd8fd2c 来源:简书 简书著做权归做者全部,任何形式的转载都请联系做者得到受权并注明出处。
相关文章
相关标签/搜索