Aurora作为aws自研的原生数据库,有很多区别于MySQL原生的特性。本文逐一整理,希望能够对大家的选型带来帮助。

数据持久性

多副本是解决数据持久性的常用办法,AWS 采用了基于 quorum 投票的协议来管理副本。简单说就是如果有 N 个副本,则一次写数据要求至少写入(N/2)+1 个节点才算写入成功,剩下的节点通过相互之间的一致性协议可以达到共同的状态,而读数据则要求至少从 N/2 个节点中读出相同的数据才能决定哪个数据是最新的。

所以 Aurora 采用的是六副本,每个可用区两副本。这种架构可以保证写入操作可以容忍一个可用区不可用的情况 4/6,而读数据可以容忍一个可用区外加一台机器不可用的情况 3/6。一旦出现了一个可用区加一台机器不可用的 3/6 情况,写数据会被禁止,但是由于读数据可以进行可以很快的根据读出的数据再恢复出一个副本达到 4/6 状态恢复写入。

数据分片

现在来想一下出现了一个 AZ 加一台机器挂掉的情况,这时我们需要重建一个副本,那么重建的时间就取决于数据库副本文件有多大。这个对一个发展越来越好的业务是不能接受的,所以需要尽可能降低数据恢复时间。**恢复时间过长还会带来另一个隐患就是在恢复的过程中如果又有一个机器故障,那么数据就没办法直接通过其他副本来恢复了,而恢复时间越长这个风险越大。**从 CAP 的角度来看 Aurora 作为一个利用分布式存储的数据库是选择了 CP,但是如果可用性出了问题能在极短的时间恢复,那么从实际使用角度也就和 CAP 系统差不多了。

一个直接的做法就是把副本分片,这样一个副本就可以散落在多台机器,这样一台机器挂的情况下我们就不需要恢复完整的副本,只需要恢复机器上的分片就可以。另一方面由于数据进行了分片,读数据的时候也可以利用多台主机的 IO 带宽,对性能也有提升。AWS 采用了 10G 的分片大小,这样在万兆网络的内网环境下,恢复一个分片可以在 10s 内完成,这样在比较极端的 1AZ+1 出故障的情况下,可以保证 10s 内恢复数据库读写。

这种数据分片的方式保证了数据库有很高的可用性,从运维角度来说就可以对这个系统进行 rolling update 了。比如想要升级底层的操作系统和软件,可以直接把机器下线进行升级,上面的分片都会很快在别的机器上进行重建,然后再把机器加回集群升级下一个。发现某台机器硬件有异常也不需要做手工的数据迁移,直接把机器下线送修。另外当出现数据热点的时候也可以直接将这个热点机器的其他分片标记为不可用把分片迁移走,来避免某一个用户的行为造成其他用户的性能下降。这些都是分片带来的好处。

副本的副作用

本来磁盘 IO 的速度就慢,多个副本之间即使是并行的写入操作,latency 也会变成最慢的节点的 latency,随着副本数的增多,抖动会变得更大。 而 MySQL 自己的一些 IO 机制主要是针对本地磁盘设计的,很多优化方法并不适用于网络存储,此外 MySQL 自己的一些事务和故障恢复的机制,会造成写放大的问题。来看一下 MySQL mirror 机制下的 IO 流程:

aws-Aurora高性能原理浅析_数据库

可以看到数据库一次写入除了要把数据写入还有 log, binlog,double-write,frm-file 这些东西要写入,而且需要在 master 上完成后才能再去 mirror 上执行同样的过程,等到 mirror 完成后一次请求才能结束。如果直接用 MySQL 的 mirror 机制那么上面提到的 6 副本系统实际上写入需要满足 6/6 才能成功,延迟会极大的加大。

Log 即数据

redo log 就是 MySQL 的 WAL log, 是为了确保事务的持久性的。每次事务提交前都需要确保 redo log 被持久化。

redo log 用来 crash recovery, binlog 会上传 s3用于 point in time restore。 在 aurora 里,只有 redo log 会通过网络复制到各个 replica, master 会等待 4/6 replicas 完成 redo log 的写入就认为写入成功 (所以失去3副本就无法写入数据了)。 其他副本会根据 redo log 重建数据(单独的 redo log applicator 进程)。

aws-Aurora高性能原理浅析_数据库_02

所有的 Replica 节点不需要将数据写入磁盘了,数据同步由底层的 EBS 系统来做。Replica 节点只需要接收 Primay 的 Log 信息来更新本地的缓存和一些全局的配置。Primary 的写入操作也不再需要各种各样的 log 写入,只需要把 WAL 给底层存储系统,存储系统会自动的写入到一定的 quorum 节点上。同步Redo log和FRM file(元数据文件)之后,Replica实例拿到这些文件先添加到内存队列,持久化到磁盘之后发出确认信息给主实例。接着把redo log 记录合并到新的data page中,更新各自的buffer cache。

而有了这些 log,存储系统会自动的去做 checkpoint,备份和故障恢复,而且这些耗时的操作都是在后台默默的异步执行的,不需要前台的 MySQL 引擎。此外在故障恢复的时候 MySQL 在启动时需要花大量的时间对比日志和实际数据状态的差异,就行数据修复,这个过程也会导致故障恢复时间的延长。

只同步 redo log 可以大大提高 MySQL 的写能力, 论文中给的数据是,和直接的基于 EBS mirror 的 MySQL 相比, aurora 的TPS 是35 倍, 每个事务产生的 IO 减少了7.7 倍。

每个 redo log 有一个单调递增的 LSN (Log Sequence Number)。 一个 PG 里的副本通过 gossip 协议相连, 如果有一个副本缺少部分 redo log, 可以直接从同 PG 内其他副本同步过来。


RDS MySQL的问题

在两个 AZ 里各起一台 EC2 作为 MySQL server, 其中一台为 primary, 通过底层的 EBS 做同步. 应用通过 DNS 域名连接 MySQL, 总是指向当前的 primary, 当发生 failover 时, DNS 自动切换到 standby 的 server, 这个域名的 TTL 很短(5s), 客户端重连后就到了新的 MySQL。

aws-Aurora高性能原理浅析_mysql_03

这种结构的问题:

  • multi AZ 中的另一台 server 无法作为 read replica, 但要付和 primary server 一样的钱。
  • 需要 read replica 的话,要另起一台, 它和 master 之间是通过 binlog replication 同步的。当 master 在做很耗时的 DDL 操作时, 所有更改都会 pending, 等 master 做完 DDL, read replica 才能开始做 DDL, 然后才继续接受数据。
  • EBS 的大小要自己指定, 不够要手工扩容。
  • 单机 size 16TB (EBS 的最大 size)。
  • standby 的 MySQL内存中 innodb buffer pool 是空的, 需要时间重建。

Aurora MySQL的改变

aurora 提供三种访问的endpoint 域名:

cluster endpoint: 永远指向当前的 master server, failover 发生时, cluster endpoint 自动刷新

reader endpoint: 会自动在 read replicas 之间做 load balancer, 如果只有一台 master,没read replicas, reader endpoint 会指向 master, 此时也是可以写入的

instance endpoint: 每台 server 单独的 endpoint, 用于访问特定的 server, 但这个就没法做 failover了

和 RDS MySQL 比的优势:

没有浪费的 standby server, 所有 read replicas都能用来做 failover对象。
副本和 master 之间在存储层同步, DDL不会导致 read replica 的同步延迟。
磁盘空间每10GB自动增长, 最多64TB, 只收一份的钱(rds的read replica,磁盘要另收费)。

要注意的地方:

  • aurora 只支持 InnoDB 存储引擎
  • aurora 价格 = db instance + disk cost + io cost (02.$/每百万io)
  • aurora provision 的磁盘空间按你数据库曾今达到的最大值算, 如果 drop 掉表,计费的空间不会减少, 后续新数据可以重用这部分空间。所以如果在 aurora 上跑会生成很大的临时表的 ETL 要注意。
  • 官方号称 aurora 的性能是 rds MySQL 的 5倍, 但从 percona 的文章和 quora 的这个回答看, 如果你的工作负载写大于读, 且写的表上有non unique 的二级索引的话, aurora 性能还不如 MySQL。
  • disk size 能自动扩展, 但如果你删除数据库中的数据,空出的空间并不能立刻被复用,必须达到某个内部阈值这部分空间才能被重用(这个阈值文档里没有说明)

小结

读写分离架构如何理解?性价比更加高

  • 计算和存储分离,Aurora是Log型,MySQL需要写到磁盘。写Log成功就可以返回,不需要写到磁盘。写完一份,底层复制对应用层没有影响
  • 快速恢复速度,传统MySQL的恢复需要2-3分钟,Aurora需要1分钟左右。只是服务器的切换时间,因为存储的持久性
  • 读写的延迟非常低,ms级别。Aurora的读副本可以作为一个高可用节点。(传统的高可用节点不可以作为读节点)