返回 登录
0

Amazon Aurora深度探索(二)

前情提要

Aurora的存储架构

存储层的设计和实现,体现了“the log is the database”,其含义是日志中包含了数据的信息,可以从日志中恢复出用户的数据,所以数据不一定必须再独立存储一份。而数据库的核心不仅是数据,保障数据的拥有ACID特性的事务和提供便捷查询的SQL语句,对以数据为基础提供商业的交易服务更是必不可缺,所以更精确的说,“the log is the data”,日志就是数据也许更为合适。在笔者看来,数据库的价值不仅在数据,还在数据库的相关技术,尤其在现代巨量数据下,背靠完备的数据库理论,对以分布为要求的数据库架构提出新的工程实践挑战。Aurora就是走在这样的实践道路上的楷模。

存储层的工作

如图8所示,主机Primary RW DB写出的REDO日志(MySQL生成的日志带有LSN、Log Sequence Number、单调递增的日志顺序号)信息发送到六个Sotrage Node中的每一个Sotrage Node上的时候,只存在一个同步瓶颈点,就是图中标识为①之处,这是Aurora的一个核心设计点,尽量最小化主节点写请求的延时。在存储节点,传输来的日志进入一个队列等待被处理。

图8  日志数据在存储节点的处理过程

图8 日志数据在存储节点的处理过程

之后日志被快速持久化到物理存储设备,并立刻给主机一个回应。这是标识为②的处理过程,这个过程极其简单,没有额外的操作,因而速度会很快,这样能够满足如上所说的“尽量最小化主节点写请求的延时”的设计理念。①和②之后的其他操作,都是异步操作,不影响系统的整体性能。这样当主机Primary RW DB收到六个Sotrage Node中的四个节点的ACK后,就认为日志成功写出,可以继续其他工作了。

③所做的工作,是对持久化日志做处理,如排序/分组等操作作用在日志上,以便找出日志数据中的间隙,存在间隙的原因是多数派写日志的机制下,少数派可能丢失日志从而导致日志不连贯。

④所做的工作,就是从其他存储节点(6个存储节点构成一个PG,即Protection Group,每个节点是一个segment,存储单位是10GB,位于一个数据中心中。6个存储节点每2个位于一个AZ,共分布于3个AZ)中,通过Gossip协议,来拉取本节点丢失的日志数据,以填充满③所发现的日志间隙。在③和④的过程中,能发现所有的副本中:相同的、连续的日志段是哪一部分,其中最大的LSN被称为VCL(Volume Complete LSN)。

⑤所做的工作,就是从持久化的日志数据中产生数据,就如同系统故障时使用REDO日志做恢复的过程:解析REDO日志,获取其中保存的数据页的修改后像,恢复到类似于传统数据库的数据缓冲区中(这也是存储层需要存在“Caching”的一个明证)。

之后,第六步,周期性地把修复后的日志数据和由日志生成的以页为单位的数据刷出到S3作为备份;第七步,周期性地收集垃圾版本(PGMRPL,即Protection Group Min Read Point LSN),参考表2可以看到,垃圾收集是以VDL为判断依据的,当日志的LSN小于VDL,则可以被作为垃圾回收;第八步,周期性地用CRC做数据校验。

表2  日志在主节点和存储层的作用表(持久化实现)

表2 日志在主节点和存储层的作用表(持久化实现)

储存层的设计讨论

现在再来反观Aurora的整体设计:

  • 数据不再从数据缓冲区刷出,消除了随机写操作,减少了I/O。
  • 计算和存储分离,日志跨AZ写到多份存储节点,存在网络I/O。
  • 主备节点间传输日志和元数据,存在网络I/O。

如上是三条核心点,似乎网络I/O占了三分之二条,属于多数。但是网络I/O都是批量数据顺序写,可极大地抵消很多次随机写的网络I/O消耗,而且通过数据冗余,极大地保障了可用性和云数据的弹性,从测试数据看,整体性能得到了可观地提升。因此这样的设计是一个优秀的架构设计。

数据冗余且有效,是使用数据库系统的基本要求。逻辑备份与还原、物理备份与恢复、主从复制、两地三中心等灾备技术方案等都是数据冗余的相关技术。数据库走向对等分布式架构,除了应对巨量数据的存储和计算的需要,也要靠数据冗余来保证数据的可用性。所以数据冗余是数据系统架构设计的一个必须考虑点。

Aurora自然也要实现数据冗余。如图5所示,数据至少在3个AZ中存6份。如果不采用“the log is the database”的理念,而使用传统数据库的技术,在跨节点写出多份数据时,势必需要采用2PC/3PC等多阶段的方式来保证提交数据的正确性,这样网络交互的次数就会很多,而且大量的随机写操作会在网络蔓延。所以“the log is the database”的理念客观上避免了传统的、耗时昂贵的分布式事务的处理机制,而又达到了数据分布的目的,这又是一个亮点。

数据至少在3个AZ中存6份,其目的是要保证数据库服务的持续可用。那么,什么算是可用呢?无论是数据中心内部的局部故障还是跨数据中心甚至跨AZ出现故障,AWS也要在某些情况下提供数据服务的可用。这就要分两种情况确定,这两种情况基于6个副本的前提(3个副本能满足多数派的读写规则,但是一旦其中一个副本不可用,则其余2个就不能保证读写一致,基于3个副本的分布式设计是脆弱的,不能切实可用地起到依靠数据冗余来换取数据可用的保障):

第1种: 读写均可用

如图9,当一个AZ出现问题,即2个副本不可用,Aurora仍然能够保证读写可用,保障数据一致。设置V=6,读多数派为Vr = 3,写多数派为Vw = 4,所以一个AZ出现故障,或者3个AZ中的两个数据中心出现故障,Aurora依然能够向外提供服务。

图9  Aurora保障读写可用

图9 Aurora保障读写可用

第2种:至少读可用

当写服务不可用,至少还可以提供读服务。设置V=6,读多数派为Vr = 3,写多数派为Vw = 4时,一个AZ出现故障依旧能够提供读服务,如图10甚至跨不同AZ的3个数据中心出现故障(概率非常小),读服务依旧能够提供。

图10  Aurora保障读可用

图10 Aurora保障读可用

在第一节,曾经说过“主从节点可以位于不同的AZ(最多位于3个VPC,需要3个AZ)但需要位于同一个Region内”。如表1所示,AWS在全球提供的AZ个数尚有限,按其自身的说法部署一个Aurora需要三个AZ,那么诸如只有2个AZ的Region如北京,尚不能得到较可靠的数据可用保障。

表1 至2017年6月AWS的Region和AZ部署

表1 至2017年6月AWS的Region和AZ部署

Aurora设计的优点

首先,存储层与事务管理分离,即ACID的D特性独立,使得存储有机会成为独立的服务而存在,便于跨数据中心时实现数据的容错(fault-tolerant)、自愈(self-healing service)和快速迁移。一旦存储层具备了容错、自愈和可快速迁移特性,则对外提供服务就不用再担心数据的短暂或长久的不可用性。在数据为王的时代,此举能保护好最核心的财产,确保云数据库服务能持续不断地对外提供服务,这使得Aurora具备了云服务的弹性,此点在AWS看来十分重要。有了这种需求,推动技术架构发生变化便水到渠成。

服务的过程中,局部数据修复的能力,速度很快。数据库宕机后的恢复,速度也很快。

服务中断后,最后的招数就是数据迁移加数据库引擎重新部署,而AWS的整个云系统具备了快速迁移数据的能力,这使得以存储为核心的云数据库有了超强的持久服务能力。

其次,存储层从高度耦合的数据库引擎中分离,降低了数据库引擎的复杂度,数据库组件的分离使得数据库部署适应巨量数据的分布式处理需求。这将进一步带动数据库引擎上层的语法分析、查询优化、SQL执行、事务处理等组件进一步的解耦。

笔者认为,这是Aurora用实践为数据库架构技术的发展指出的可行方向。一个具有实践意义的分布式发展架构总是最亮眼的,也总是具有指导意义的。存储与计算解耦,各种组件互相解耦,不断解耦……在此种思路下,AWS已经走在发展万能数据库引擎的道路上(参见下文“万能数据库”一节)。

Aurora的事务处理

Aurora基于MySQL和InnoDB,实现的是单点写的一主多从架构,所以在事务处理方面,没有大的变动,事务处理技术得到继承。整体上是依据SS2PL和MVCC技术实现了事务模型和并发控制。

持久性

对于Aurora,事务的ACID特性,只有D特性与MySQL和InnoDB有很大的不同。Aurora利用MySQL的Mini-transaction和LSN在存储节点构造数据页(基本过程参见“存储层的工作”一节)。

如前所述,Aurora的存储层与计算层分离。存储层其功能在“存储层的工作”一节讨论,其设计思想参见“存储层的设计讨论”一节。本节从事务的角度来讨论与存储层紧密相关的持久性,如表2所示存储层是表中的“存储节点S1、S2、S3、S4、S5、S6”。

在存储层,日志被写到持久化的存储设备后,主节点收到应答则不被阻塞,上层工作能够继续进行,且存储层的日志落盘操作保证了整个Aorora的日志持久化。然后存储层利用日志做实时恢复,这样使得日志数据转变为了“Caching”中存储的页面格式的数据。这些工作完成,才相当于传统架构的数据库持久化完成。

但是,因为存储层不再是单点而是分布式结构,故存在故障的种类变多,如多节点的数据在实时运行过程中的一致性问题、在系统故障后的数据恢复时多节点的数据一致性问题。Aurora使用如表2的几个概念来表示关键的一些日志点信息,然后凭借这些点来解决“日志数据的不一致”问题,这几个概念分别是:

  • LSN,Log Sequence Number,日志序列号:单调递增,唯一标识每一条日志记录。如表2所示,LSN1到LSN9表示共有9条日志记录,每条有独立的LSN值。

  • CPL,Consistency Point LSN,一致性点:MySQL的每个Mini事务产生的最后一个LSN为一个CPL即一致性点(一个事务包括多个Mini事务,一个Mini事务包括一到多个日志记录。这是在描述以Mini事务为基本单位的一个局部一致,尚不能达到事务一致)。如表2所示,“T1-Mini-t1”T1事务的第一个Mini事务的一致性点是LSN3,如果此时系统故障,之后做恢复,事务T1不会被恢复成功;如果事务T1在主节点被标识为了提交(InnoDB的事务提交标志,是在内存标识为事务已经提交,然后才刷出日志,这点不符合预写日志的要求),事务日志尚没有持久化到存储层,这意味着数据可能会丢失。但是,InnoDB对这种先标识事务提交后刷日志的方式给出了不丢失数据的解决方式,而Aurora改变了日志的刷出机制,可能会改变或不改变InnoDB原有的数据一致性保障机制 ,如果改变了原有机制,论文对这一个重要点没有加以描述,只能存疑待问。

  • SCL,Segment Complete LSN,段完整LSN:每一个存储节点对应的最大连续LSN,在系统存活期间,可以利用SCN与其他节点交互,采用Gossip协议,填补丢失的日志记录。如表2所示,只标识出了S1节点的SCL是LSN9,而对于S5节点,其SCL是LSN7。

  • VCL,Volume Complete LSN,卷完整LSN:每个存储节点接收到的最大连续日志ID,因为多数派协议的使用,每个存储节点的VCL会不同。如表2所示,没有表示出S1到S6各个存储节点的VCL,而是只标识出了六个节点中所有VCL中的公共最大点,这个点是系统故障后恢复所能恢复到的一致点。注意依旧不是事务一致而是Mini事务一致,存疑的是:不能达到事务一致,其意义何在?还有什么重要的细节没有公开吗?留意到下面这段话,我们可以看出一点端倪(存储层的恢复不需要保证事务一致,存储层恢复之后,计算层还会继续恢复工作,这样才能达到事务一致):

However, upon restart, before the database is allowed to access the storage volume, the storage service does its own recovery which is focused not on user-level transactions, but on making sure that the database sees a uniform view of storage despite its distributed nature.

  • VDL,Volumn Durable LSN,卷持久点:传统的数据库提供CheckPoint功能,在日志中加入一个CheckPoint点,作为故障恢复时的起始点。VDL就是存储层的“CheckPoint点”,在VDL之前的日志,已经无用可以被GC,但因存储层的日志一直在持续不断地被用于“恢复”日志为“Caching”中的数据页,所以其作用和原始的“CheckPoint点”相反。注意VDL是所有存储节点上的日志比较后得到的一个共同点,不是一个Segment级的点,这和VCL相似,都是PG(Protection Group)级别的。其定义如下:

VDL or the Volume Durable LSN as the highest CPL that is smaller than or equal to VCL and truncate all log records with LSN greater than the VDL.

事务与数据分布

在“核心技术与架构”一节,我们曾说,目前制约存储层内的“Caching”起更大作用的因素,主要在于分布式事务机制的选取和InnoDB自身的事务实现机制。

这有两层含义:一是InnoDB自身的事务实现机制制约了存储层内的“Caching”起更大作用;二是分布式事务机制的选取关联着存储层内的“Caching”是否有机会起更大作用。

首先:InnoDB的事务信息,几乎不在数据上(除了元组头上有个事务ID用于版本可见性判断外再无其他信息),而是位于内存中。这其实是在说,InnoDB的行级锁即索引项的记录锁,其锁表位于内存,不能随着Aurora的数据分布而“分布”。而Oracle的RAC可是在数据页上存储了足够多的事务信息(参见《数据库事务处理的艺术》一书的第六章),所以RAC中的其他节点,就能够随着被分布的数据而获取事务相关的信息从而在分布的各节点上处理事务的ACID特性。此点是MySQL能否走向分布式事务的一个关键点(当然选用不同的分布式事务实现机制会反过来影响这点结论)。

其次:分布式事务机制的选取为什么会影响着Aurora的存储层内的“Caching”,是否有机会起更大作用呢?

有的分布式事务架构,采取的是集中式架构,即中央点总控事务管理。事务的决策判断都要经过中央点进行,多个子节点需要和中央节点多次交互。比如PostgreSQL-XC提供了全局事务管理器。如果MySQL/InnoDB或者Aurora的分布式架构向这个方向发展,则存储层内的“Caching”就没有多少机会起更大的作用了。

而有的分布式事务架构,采取的是事务信息随同存储分布。这样不同的节点就可以进行“分布式”的事务处理。比如基于BigTable的Percolator系统,其核心不在于两阶段提交,而是在于分布的数据项上,有着丰富的事务信息,这些信息足以被任何节点用于做ACID的实现判断(参考《Large-scale Incremental Processing Using Distributed Transactions and Notifications》)。如果MySQL/InnoDB或者Aurora的分布式架构向这个方向发展,则存储层内的“Caching”就有很大的机会起更大的作用。

走向哪条路,或走向另外的路,需看Aurora的雄心有多大。目前的Aurora告诉我们的是,其分布式架构的选择,仅是用户数据分布。事务数据的分布,其实是一个更大的话题。

事务处理

MySQL和InnoDB的事务处理技术,采用了SS2PL,把强严格两阶段锁融合到平板事务模型中,以提交和回滚机制实现A特性,并进一步在读数据时加锁确保C特性,通过MVCC实现了I特性中的RR和RC隔离级别以提高并发度。这些技术,在目前的Aurora中没有大的改变。如前所述,Aurora改变的是依据事务日志做持久化处理(D特性)和系统故障后恢复的一部分流程处理(A、C特性的一部分),从整体上看,没有革命性的变化。但是,Aurora的事务提交却是异步的且和VDL相关(确保持久化),这点在论文中描述很细致:

In Aurora, transaction commits are completed asynchronously. When a client commits a transaction, the thread handling the commit request sets the transaction aside by recording its “commit LSN” as part of a separate list of transactions waiting on commit and moves on to perform other work. The equivalent to the WAL protocol is based on completing a commit, if and only if, the latest VDL is greater than or equal to the transaction’s commit LSN. As the VDL advances, the database identifies qualifying transactions that are waiting to be committed and uses a dedicated thread to send commit acknowledgements to waiting clients. Worker threads do not pause for commits, they simply pull other pending requests and continue processing.

在“核心技术与架构”一节我们提到“鉴于以上几点,备机数据获取和更新的这个细节,算是个谜”,即备机的数据获取,是从存储层而来还是从主节点而来?我们不妨做个论文没有提及的猜想:备机的数据源自存储层和主节点,存储层统一向上层提供数据页的缓冲服务,用以不断响应计算层的数据缺页请求,这起到了传统的数据缓冲区的作用。而主节点传输日志给备节点,备节点可以从中解析出UNDO日志信息(UNDO也是受到REDO保护的),从而能够构造出主节点在某个时刻的完整计算环境状态(数据缓冲区+UNDO信息),这样,备机就可以为接到的读请求构造一致的“ReadView”,为读操作提供事务读数据的一致性状态。如为此点,则是一个巧妙的设计。更进一步,主机直接传输给备机的,可以只是准备写入REDO的UNDO信息。

锁管理

基于MySQL的Aurora同样使用了基于封锁的并发访问控制技术。但是,Aurora改造了MySQL的锁管理器,这点论文没有提及,而在2017年的Percona技术大会上,Aurora的一个分享展示了如图11的内容。图中显示,在MySQL的锁表管理器上,对于Scan、Delete、Insert三种操作,把lock互斥了三种类型的并发,而Aurora分别按操作类型加锁“lock manager”,提高了并发度,这样的锁看起来是一个系统锁,把一个粗粒度的系统锁拆分为三个细粒度的系统锁。但是,较为奇怪的是,如图12,Aurora展示了其效果却十分的惊人(图13是测试环境的配置)。

图11  Aurora锁管理器改进图

图11 Aurora锁管理器改进图

图12   Aurora锁管理器改进后的性能测试对比

图12 Aurora锁管理器改进后的性能测试对比

云服务能力

强化的云服务能力

除了通过更多的数据冗余(跨3个AZ的6个副本)提高高可用性外,Aurora还有着其他强大的云服务能力,这是云数据库需要重点建设的能力。

  • 存储方面,存储的单位是段(segment),每个段的大小为10GB,单实例数据库存储最大限是64TB。
    处理系统故障方面:

    1. 10秒内完成一个10GB的Segment的网络迁移。30秒完成故障转移。
    2. 以Segment为单位周期性并行备份。
    3. 以REDO日志为单位周期性并行备份。
    4. 通过日志实时地持续恢复,提供了更快的crash recovery。
  • 性能方面:

    1. 更快的索引构建。采用自底向上的索引构建方式,比MySQL快2倍到4倍。
    2. 无锁并发Read-View算法。构造ReadView采用无锁算法减少竞争提高性能。
    3. 无锁队列提高审计功能的速度。
    4. 其他如热行竞争、批量数据插入等性能提升明显。
  • 其他云服务:

    1. 提供快速provisioning和部署。
    2. 自动安装补丁和软件升级。
    3. 备份和point-in-time恢复。
    4. 计算和存储的扩展性支持。
    5. 如图3所示,存储系统的元数据存于Amazon DynamoDB中,使用Amazon SWF提供的工作流实现对Aurora的自动化管理,这也是云中规模化服务的重要能力。

万能数据库

AWS的Aurora不只是MySQL的一个分支版本,更像是一个万能的数据库系统,这样的系统,通过兼容各种主流数据库的SQL语法、功能,也许能在云上一统数据库的服务,把各种数据库的用户应用接入,通过一个统一的分布式数据库引擎,提供各种数据库的数据服务能力。

AWS的官网,声明了“兼容 PostgreSQL的Amazon Aurora”如下:

Amazon Relational Database Service (Amazon RDS) 正在提供 Aurora (PostgreSQL) 预览版,即兼容PostgreSQL的Amazon Aurora。Aurora是一种完全托管的、兼容PostgreSQL和MySQL的关系数据库引擎。

单从字面看,Aurora不再是MySQL,而是MySQL+PostgreSQL,所以将来将会是 “MySQL+PostgreSQL+…+…”,各种数据库都将融于Aurora当中。这样提供强大无比的云数据库服务,此点非常重要,用户基于任何数据库的应用均不用修改应用的代码,无缝接入Aurora。

从技术层面看,实现这样的目标,有多种方式。简单的方式,就是利用相同的云基础设施和云服务概念,把各个数据库单独云化,然后用Aurora统一命名。但如果进一步把计算层分离,如把语法解析、查询器、执行器拆分,不同种类的数据库使用各自的语法解析和查询优化,然后统一执行计划交给统一的执行器去执行,事务处理和数据存储则可以独自研发独立于上层的计算。如此,想象空间得以打开……

小结

本文探讨了Aurora的实现方面的技术内容,由于作者水平有限,错漏之处,请不吝指正。Aurora在实现方面的诸多细节,论文并没有提及,在此逐一列出如下,期待以此文抛砖引玉,期待多方指点讨论,共同进步。

  • 架构方面

    1. 主备切换机制是什么样的?
    2. 主机宕机,多个备机之间如何选其一作为主?
    3. 备机的数据是如何获取的?为什么需要从主机和全局共享存储层这两个源头拉取数据?
    4. Caching层的设计细节是什么?有什么的问题和挑战?
    5. 共享存储层未来的Roadmap会是什么样?
    6. 15个备份的数字15是否有特别的考虑?
    7. 计算层是否有进一步解耦的打算?如把优化器和执行器分离等。
  • 事务方面

    1. 数据项是否有携带更多事务信息的打算?
    2. 如何实现备机的读一致性?此点是怎么利用MySQL的SS2PL+MVCC+UNDO的?
    3. 可序列化隔离级别是否在主备机间得到保证?
  • 存储方面:共享存储的作用和价值,以及实现的细节?

附录

参考资料:

  1. 《Amazon Aurora: Design Considerations for High Throughput Cloud Native Relational Databases》
  2. https://aws.amazon.com/
  3. Aurora deep dive - Percona Live 2017
  4. https://aws.amazon.com/tw/blogs/database/category/aurora/?nc1=h_l
  5. 《High performance transactions in deuteronomy》

作者:李海翔,网名那海蓝蓝,熟悉PostgreSQL、MySQL、Informix等数据库内核技术。腾讯金融云数据库技术专家。著有《数据库查询优化器的艺术》,被誉为查询优化技术领域的里程碑之作。2017年出版《数据库事务处理的艺术 事务管理与并发控制》,被再次誉为事务处理领域的新里程碑。
责编:仲培艺,纠错、寻求报道或者投稿请致邮zhongpy@csdn.net。
本文为《程序员》原创文章,未经允许不得转载,更多精彩文章请订阅2017年《程序员》

评论