Amazon Aurora
一、名词解释
AWS的概念:
名词 | 解释 |
EC2 | 通用虚拟机。很适合运行网页服务器。不太适合在上面运行数据库——不容易scale、不容错。 |
S3 | 大容量存储器。可以用来做数据库的定期备份用。 |
EBS | 不是EC2上本机的磁盘,但是可以像磁盘一样挂载到EC2上面当磁盘用——可以在上面创建EXT4文件系统。1个EBS由2个replicas构成,采用链式复制,所以EBS本身可以容错。 |
DB-on-EBS | 比如说用MySQL,数据库文件创建在EBS上。缺点是慢、不够容错。慢是因为EBS两个副本间复制的最小单位是数据页。 |
WAL | Write-Ahead Log。数据库概念。所有的修改在提交之前都要先写入log文件中,如果执行一半机器失败重启,数据库系统能知道如何继续完成已经commit的事务,如何取消未commit的事务。 |
LSID | 日志(log)项的编号 |
AZ | availability zone。同一个机房,或者同一个数据中心。(我想:就是在1个建筑内,一次灾害可能导致里面的所有机器同时都不可用。 |
Amazon’s multi-AZ RDS | 亚马逊的跨机房关系数据库服务,(似乎就是论文的figure 2所示)。这不是Aurora,而是早前就已经有的服务。由2个EC2和各自拥有的ECB构成,2套EC2+EBS分处2个不同机房。(机器构成上是DB-on-EBS × 2) |
Aurora的概念:
名词 | 解释 |
AZ+1 | Aurora要实现的容错目标,1个AZ当掉,仍然可以写;再加1台replica当掉,仍然可以读。 |
SCL | SCL是一个log编号。代表一个存储服务器里拥有从开头到 |
VCL | volumn complete LSN。(我想应该是指6台数据replicas的 |
PG | Protection Groups。就是Aurora的分片(shard),数据库页面太大了,每10G分一片。 |
CPL | consistency point LSNs,这里的consistency是ACID里的A(atomic)(要么全执行,要么全都不执行。)一个事务分成多个迷你事务(MTR),每个迷你事务由一段连续的log组成,迷你事务的结尾是一条CPL log。 |
VDL | highest committed LSN。VDL代表其中最大的并早于VCL那个CPL。And the VDL marks the last such point(CPL) before the VCL. |
二、基本组成
3台EC2、每台各配2个存储服务器。(3 EC2 + 6 storage servers)
1台EC2是数据库服务器(唯一的写者)。2台EC2运行只读的数据库服务。
shard
如果数据超过10GB,会每10GB分成1个PG (PG就相当于Lab 4的shard)。
1个PG有6副本,又叫做6个segments(它们分别存在6台不同存储服务器上)
名词 | 解释 |
volume | 整个数据库 |
PG | shard。1个大数据库shard成多个PG。 |
segment | 一个PG由6个副本组成,这些副本叫做segment |
上图来自1
存储服务器包含了log applier
与传统数据库最大的不同是:存储服务器不是单纯地负责存储数据。Aurora的存储服务器懂得怎么将REDO log应用到数据库页中。所以db服务器只要发送redo log给存储器,减少了它们之间通信的网络流量。但是增加了存储服务器的CPU负担。(是异步的。不需要收到log立刻应用REDO log,可以先答复,等CPU空闲了再做应用。)
阿里云
阿里巴巴的PolarDB采用了不一样的判断。他们认为数据中心内都采用RDMA,网络协议运行在用户空间,网络通信变得跟访问本地内存一样快,网络通信不再是瓶颈。所以他们没有采用这样的设计。(但是我想如果要实现容灾,不能全部机器都在同一个机房,跨地区的网络通信就仍然是瓶颈,因为若要加快读取速度,最好是在本地读。像facebook那篇论文说的,东西海岸都各有一个完整的数据库replica,东海岸的读操作只要在东海岸执行。这就要求数据从西海岸机房复制到东海岸机房,所以大概网络仍是瓶颈?)1
三、单一写者系统2
- Aurora整个系统中只有主数据库服务器负责写。一切并发控制都是在主数据库服务器做的。比如说二阶段锁,比如说事务的冲突与回滚,都是在主服务器做,在主服务器判断,所以不需要用到2PC二阶段提交。
- 反之,Spanner可以有多个写者(也就是事务协调者),多台机器并发地发起事务。所以Spanner需要用到二阶段提交。
- 后来好像有改进成多master的架构,参见这个知乎回答,细节我也不清楚。3
四、复制(replication):quarum法
6个存储副本之间怎么做replication?Aurora采用的quorum read/write方法。就是根据副本机器数量N,预先确定两个数字R(读至少要读多少台副本)、W(写至少要成功写到多少台副本),要求R + W = N + 1。
这样由于鸽巢原理,读和写的机器集合必然会有交集,保证了读能读到最近的写。
具体数字
Amazon Aurora的配置是这样:N = 6,W = 4,R = 3。因为6个副本是分散在3个不同可用区,每个可用区2台。
这样如果一个可用区不能访问了,比如遇到火灾整个坏了,那就失去2台,剩下4台,仍然可以满足W = 4。也就是说,一个可用区宕掉,依然可以写。
如果再有一台存储服务器宕机,就剩下3台,依然满足R = 3,还是可以读。这满足了Aurora的“AZ+1”的高可用性需求。
Gossip
同时,虽然只要写到W台机器就算成功(W台机器commit log写入,就可以答复客户端了),但是6个副本最终目标是保存所有数据,所以它们之间会通过gossip,通过找别人询问的方式,填补自己缺失的数据。所以最终6个副本都成功写入。
quarum与raft相比
- quarum法是一种历史悠久的想法了。因为它基于读多少台 / 写多少台 这样的概念,所以它一般只支持简单的读/写操作。不像Raft并未对Op有什么假设,Op不一定是简单的读/写,Raft可以支持各种复杂的状态机操作。
- quarum法比较灵活之处是可以根据需要调整W/R数值,比如对于写比较繁重的任务,可以减少W的数值,但是这样也降低了故障耐受。对于读比较繁重的任务,可以减少R的数值,代价是W要增大,遇到“一台机器慢写延迟增加”的可能性增大。
五、读/写/恢复
5.1 写
- 主数据库服务器发送redo log给所有6台存储服务器。
- 什么时候算是commit?等4台以上机器都将这条log写入,并且它们都有从头到此处的完整log时,也就是 VDL >= 事务的最后一条日志LSN。
- 主数据库服务器确定VDL大于事务最后一条LSN,就可以释放相关的锁(2PL的步骤),然后答复客户端。
- 锁的控制,事务要不要回滚,都在主服务器决定。存储服务器只管根据log去修改数据库页。
- 存储服务器不必等应用完log再回复主服务器,应用是异步的,只要log落盘,就可以回复主服务器。
5.2 读
- 如果是buffer pool里面有的,当然可以直接读出来答复客户端。
- 如果cache里没有,就要从几个存储服务器中读取最新的页面数据。因为存储服务器时常向主db服务器报告自己拥有多少完整的log,所以主db知道谁拥有足够新的log,该向谁发起读操作。
- 存储服务器收到请求后,如果page数据内容还不是最新的,它会将相关的log应用下去,将page内的数据更新到最新,然后传送给主db服务器。
5.3 恢复
- 恢复的时候才要用到quarum read。因为系统宕机的时候,有些写只写到部分机器,比如说只写到4台,已经满足写quarum,算是commit了。这个事务就需要继续复制到其他服务器。如果宕机的时候不到这个quarum,比如说只复制到2台,这个事务就要回滚。
- 所以恢复的时候,主服务器只要向R = 3 台服务器查询,就能重新确定VDL。然后它会叫所有的存储服务器删除掉LSN大于VDL的那些后续的log。
- VDL是以MTR(mini-transacation)为边界划分的。如果一个事务只有部分MTR完成,那么主db还要向存储服务器发送UNDO日志,回滚这些MTR。
由此猜测存储服务器需要支持什么样的API
What must API look like between database instance and storage?
- write log record (affecting pages) 写入一条日志
- read data page (possibly as of a particular LSN) 读取一个页面
- delete log records in some LSN range (e.g., above VDL during recovery) 删除大于某LSN的日志项
- query info about SCL (presumably needed) 查询SCL(你拥有多少连续日志) 4
只读数据库服务器
- 因为最好要做到本地读。所以在每个可用区都有自己的数据库服务器,当然都是只读的。他们从自己本地的存储服务器读取page,存到自己的buffer pool。
- 这个buffer pool如何保持数据最新?- 主db也要把所有日志发送给只读db。只读db跟着应用到相关的page上,但是(1)要忽略掉还未commit的事务(根据VDL判断,只有commit大于VDL的事务才写入)。(2)从存储服务器传往只读db的page一定是以一个MTR结束的,不会传送一些中间结果给只读db——比如B-tree修改一半。
- 一致性:这个只读db与主db之间有一定延迟(20ms)。因为主db是先答复的客户,再传送redo log给各只读db,这应该是为了降低延迟,防止个别慢机器、网络拖慢系统。
PolarDB
以下内容纯数猜测:
阿里云的PolarDB是怎么做的呢?分成DDL和非DDL两种语句。DDL语句是这样:主服务器要等到所有备份服务器收到log,并且应用到buffer pool里,才算会答复客户端。这样就不会出现用户从备份服务器读出stale data。4这会造成假如有个别机器慢,整个系统也要听下来等它应用。PolarDB的优势是主服务器与备份服务器是通过RDMA共享一块内存来同步日志。
他们还提到session一致读的概念,应该就是Read-your-own-Write,那就不是强一致性了。不同session就可能读到stale data。这是针对非DDL语句,主服务器不停下来等备份服务器应用Log。
另外,我们的Proxy支持Session一致读,即同一个session内的读和写保证是逻辑相关的,在写之后立即读,一定会读到最新的数据(只有由于读写分离,会把读请求发到有延迟的只读节点,从而导致读取到历史版本的数据4