Files
MIT6.824/lecture-10-cloud-replicated-db-aurora/10.7.md
2022-01-25 02:41:31 +00:00

7.1 KiB
Raw Blame History

10.7 Aurora读写存储服务器

我之前也解释过Aurora中的写请求并不是像一个经典的Quorum系统一样直接更新数据。对于Aurora来说它的写请求从来不会覆盖任何数据它的写请求只会在当前Log中追加条目Append Entries。所以Aurora使用Quorum只是在数据库执行事务并发出新的Log记录时确保Log记录至少出现在4个存储服务器上之后才能提交事务。所以Aurora的Write Quorum的实际意义是每个新的Log记录必须至少追加在4个存储服务器中之后才可以认为写请求完成了。当Aurora执行到事务的结束并且在回复给客户端说事务已经提交之前Aurora必须等待Write Quorum的确认也就是4个存储服务器的确认组成事务的每一条Log都成功写入了。

实际上在一个故障恢复过程中事务只能在之前所有的事务恢复了之后才能被恢复。所以实际中在Aurora确认一个事务之前它必须等待Write Quorum确认之前所有已提交的事务之后再确认当前的事务最后才能回复给客户端。

这里的存储服务器接收Log条目这是它们看到的写请求。它们并没有从数据库服务器获得到新的data page它们得到的只是用来描述data page更新的Log条目。

但是存储服务器内存最终存储的还是数据库服务器磁盘中的page。在存储服务器的内存中会有自身磁盘中page的cache例如page1P1page2P2这些page其实就是数据库服务器对应磁盘的page。

当一个新的写请求到达时这个写请求只是一个Log条目Log条目中的内容需要应用到相关的page中。但是我们不必立即执行这个更新可以等到数据库服务器或者恢复软件想要查看那个page时才执行。对于每一个存储服务器存储的page如果它最近被一个Log条目修改过那么存储服务器会在内存中缓存一个旧版本的page和一系列来自于数据库服务器有关修改这个page的Log条目。所以对于一个新的Log条目它会立即被追加到影响到的page的Log列表中。这里的Log列表从上次page更新过之后开始相当于page是snapshotsnapshot后面再有一系列记录更新的Log。如果没有其他事情发生那么存储服务器会缓存旧的page和对应的一系列Log条目。

如果之后数据库服务器将自身缓存的page删除了过了一会又需要为一个新的事务读取这个page它会发出一个读请求。请求发送到存储服务器会要求存储服务器返回当前最新的page数据。在这个时候存储服务器才会将Log条目中的新数据更新到page并将page写入到自己的磁盘中之后再将更新了的page返回给数据库服务器。同时存储服务器在自身cache中会删除page对应的Log列表并更新cache中的page虽然实际上可能会复杂的多。

如刚刚提到的数据库服务器有时需要读取page。所以可能你已经发现了数据库服务器写入的是Log条目但是读取的是page。这也是与Quorum系统不一样的地方。Quorum系统通常读写的数据都是相同的。除此之外在一个普通的操作中数据库服务器可以避免触发Quorum Read。数据库服务器会记录每一个存储服务器接收了多少Log。所以首先Log条目都有类似12345这样的编号当数据库服务器发送一条新的Log条目给所有的存储服务器存储服务器接收到它们会返回说我收到了第79号和之前所有的Log。数据库服务器会记录这里的数字或者说记录每个存储服务器收到的最高连续的Log条目号。这样的话当一个数据库服务器需要执行读操作它只会挑选拥有最新Log的存储服务器然后只向那个服务器发送读取page的请求。所以数据库服务器执行了Quorum Write但是却没有执行Quorum Read。因为它知道哪些存储服务器有最新的数据然后可以直接从其中一个读取数据。这样的代价小得多因为这里只读了一个副本而不用读取Quorum数量的副本。

但是数据库服务器有时也会使用Quorum Read。假设数据库服务器运行在某个EC2实例如果相应的硬件故障了数据库服务器也会随之崩溃。在Amazon的基础设施有一些监控系统可以检测到Aurora数据库服务器崩溃之后Amazon会自动的启动一个EC2实例在这个实例上启动数据库软件并告诉新启动的数据库你的数据存放在那6个存储服务器中请清除存储在这些副本中的任何未完成的事务之后再继续工作。这时Aurora会使用Quorum的逻辑来执行读请求。因为之前数据库服务器故障的时候它极有可能处于执行某些事务的中间过程。所以当它故障了它的状态极有可能是它完成并提交了一些事务并且相应的Log条目存放于Quorum系统。同时它还在执行某些其他事务的过程中这些事务也有一部分Log条目存放在Quorum系统中但是因为数据库服务器在执行这些事务的过程中崩溃了这些事务永远也不可能完成。对于这些未完成的事务我们可能会有这样一种场景第一个副本有第101个Log条目第二个副本有第102个Log条目第三个副本有第104个Log条目但是没有一个副本持有第103个Log条目。

所以故障之后新的数据库服务器需要恢复它会执行Quorum Read找到第一个缺失的Log序号在上面的例子中是103并说好吧我们现在缺失了一个Log条目我们不能执行这条Log之后的所有Log因为我们缺失了一个Log对应的更新。

所以这种场景下数据库服务器执行了Quorum Read从可以连接到的存储服务器中发现103是第一个缺失的Log条目。这时数据库服务器会给所有的存储服务器发送消息说请丢弃103及之后的所有Log条目。103及之后的Log条目必然不会包含已提交的事务因为我们知道只有当一个事务的所有Log条目存在于Write Quorum时这个事务才会被commit所以对于已经commit的事务我们肯定可以看到相应的Log。这里我们只会丢弃未commit事务对应的Log条目。

所以某种程度上我们将Log在102位置做了切割102及之前的Log会保留。但是这些会保留的Log中可能也包含了未commit事务的Log数据库服务器需要识别这些Log。这是可行的可以通过Log条目中的事务ID和事务的commit Log条目来判断10.3哪些Log属于已经commit的事务哪些属于未commit的事务。数据库服务器可以发现这些未完成的事务对应Log并发送undo操作来撤回所有未commit事务做出的变更。这就是为什么Aurora在Log中同时也会记录旧的数值的原因。因为只有这样数据库服务器在故障恢复的过程中才可以回退之前只提交了一部分但是没commit的事务。