突破关系型数据库桎梏:云原生数据库中间件核心剖析
NewSQL的三种分类中,新架构和云数据库涉及了太多与数据库相关的底层实现,为了保证本文的范围不至太过发散,我们重点介绍透明化分片数据库中间件的核心功能与实现原理,另外两种类型的NewSQL在核心功能上类似,但实现原理会有所差别。
一、数据分片
传统的将数据集中存储至单一数据节点的解决方案,在性能和可用性两方面已经难于满足互联网的海量数据场景。由于关系型数据库大多采用B+树类型的索引,在数据量超过阈值的情况下,索引深度的增加也将使得磁盘访问的IO次数增加,进而导致查询性能的大幅下降;同时高并发访问请求也使得集中式数据库成为系统的最大瓶颈。
新架构的NewSQL会重新设计数据库存储引擎,将同一表中的数据存储在分布式文件系统中。
数据分片中间件则是尽量透明化分库分表所带来的影响,让使用方尽量像使用一个数据库一样使用水平分片之后的数据库。
消息长度为int<3>类型。它表示随后的消息体所占用的字节总数。需要注意的是,消息长度并不包含序列主键的占位在内。
序列主键为int<1>类型。它表示一次请求后返回的多个MySQL协议包中,每个协议包的序号。占位为1字节的序列主键最大值为0xff,即十进制的255,但这并非表示每次请求最多只能包含255个MySQL协议包,超过255的序列主键将再次从0开始计数。例如一次查询可能返回几十万的记录,那么MySQL协议包只需保证其序列主键连续,将大于255的序列主键重置为0,重新开始计数即可。
消息体的长度为消息长度所声明的字节数。它是MySQL协议包中真正的业务数据,根据不同的协议包类型,消息体的内容也不同。
COM_QUERY
COM_STMT_PREPARE
COM_STMT_EXECUTE
流式归并用于简单查询、排序查询、分组查询及排序和分组但排序项和分组项完全一致的场景,流式归并结果集的遍历方式是通过每一次调用next方法取出,无需占用额外的内存。
内存归并则需要将结果集中所有数据加载至内存处理,如果结果集数据过多,会占用大量内存。
原子性(Atomicity)指事务作为整体来执行,要么全部执行,要么全不执行。
一致性(Consistency)指事务应确保数据从一个一致的状态转变为另一个一致的状态。
隔离性(Isolation)指多个事务并发执行时,一个事务的执行不应影响其他事务的执行。
持久性(Durability)指已提交的事务修改数据会被持久保存。
在准备阶段时,全局事务管理器向每个资源管理器发送准备消息,用于确认本地事务操作的成功与否;
在提交阶段时,若全局事务管理器收到了所有资源管理器回复的成功消息,则向每个资源管理器发送提交消息,否则发送回滚消息。资源管理器根据接收到的消息对本地事务进行提交或回滚操作。
基本可用保证分布式事务参与方不一定同时在线;
柔性状态允许系统状态更新有一定的延时,这个延时对客户来说不一定能够察觉;
最终一致性通常是通过消息可达的方式保证系统的最终一致性。
子事务序列T1,T2,…,Tn得以完成 。这是事务的最佳情况,即无需回滚的情况。
或者序列T1,T2,…,Tx, Cx,…,C2,C1,(其中x小于n)得以完成。它能够保证当回滚发生时,补偿操作按照正向操作相反的顺序依次执行。
Try。完成业务检查,预留业务所需资源。Try操作是整个TCC的精髓所在,可灵活选择业务资源锁的粒度。
Confirm。执行业务逻辑,直接使用Try阶段预留的业务资源,无需再次做业务检查。
Cancel。释放Try阶段预留的业务资源。
检查A账户有效性,即查看A账户的状态是否为“转帐中”或者“冻结”;
检查A账户余额是否充足;
从A账户中扣减100元,并将状态置为“转账中”;
预留扣减资源,将从A往B账户转账100元这个事件存入消息或者日志中。
不做任何操作。
A账户增加100元;
从日志或者消息中,释放扣减资源。
检查B账户账户是否有效。
读取日志或者消息,B账户增加100元;
从日志或者消息中,释放扣减资源。
不做任何操作。
配置中心用于配置集中化以及动态配置更新及通知下发;
注册中心用于服务发现,这里的服务是指数据库中间层实例本身,通过它可以实现状态监测及自动通知,进而使得数据库中间件具备高可用和自我治愈能力;
限流用于流量的过载保护,分为数据库中间件本身的流量过载保护和对数据库的流量过载保护;
熔断也是流量过载的保护措施之一,它的不同之处在于熔断整个客户端对数据库的访问,以保护数据库能够为其他流量正常的系统继续提供服务,可以通过前文讲的熔断器模式实现自动熔断机制;
失效转移用于多数据副本的情况,在数据完全一致的多数据节点中,当某一节点不可用后,可通过失效转移的机制让数据库中间件访问至另外有效的数据节点操作数据;
调用链路追踪则是将对数据库访问的调用链路、性能、拓扑关系等指标以可视化的方式展现出来。
同步线上双写。即同时将数据写入分片策略修改前的原数据节点及分片策略修改后的新数据节点。可以通过一致性算法来保证双写的一致性,如前文介绍过的Paxos或Raft算法;
历史数据迁移。以离线的方式,将需要迁移到新数据节点部分的历史存量数据从原有数据节点迁移过去。可以通过SQL的方式,也可以通过binlog等二进制方式进行处理;
数据源切换。将读写请求切换至新的数据源,并停止对原数据节点的双写;
清理冗余数据。在旧数据节点中,清理已迁移至新数据节点的相关数据。