网络存储架构
Redrock Postgres 支持数据库服务器以存储服务器的模式运行,并能为连接到网络上的其他数据库服务器提供存储访问服务。我们把这些用来对数据进行存储访问的服务器,称为数据库存储服务器,那些主要用来对数据进行计算处理的服务器,称作数据库计算服务器。计算服务器使用 PostgreSQL 客户端和服务端通信访问协议和存储服务器进行数据的传输。
本节描述网络表空间的存储架构。
使用传统的本地表空间时,修改数据页时会记录预写式日志(WAL)。WAL 的中心概念是数据文件(存储着表和索引)的修改必须在这些动作被日志记录之后才被写入,即在描述这些改变的日志记录被刷到持久存储以后。如果我们遵循这种过程,我们不需要在每个事务提交时刷写数据页面到磁盘,因为我们知道在发生崩溃时可以使用日志来恢复数据库:任何还没有被应用到数据页面的改变可以根据其日志记录重做(这是前滚恢复,也被称为 REDO)。事务提交要求必须写入日志,但是数据页的写入可能会延迟。
使用网络表空间时,通过网络进行写入的主要是 WAL 日志记录。不论是后台写入、检查点机制还是缓存逐出,在数据库计算服务层都不太会写入数据页。取而代之的是,将 WAL 日志应用能力推送到数据库存储服务层,从而在后台通过应用 WAL 日志生成数据库页面,实现数据的持久化存储。
将处理流程移到存储服务最大程度地减少了崩溃恢复时间,提高了系统的可用性,并且还可以消除由后台处理(例如检查点、后台数据页写入和备份)引起的抖动。
我们来对比一下崩溃恢复。使用传统的本地表空间时,发生崩溃后,系统必须从最近的检查点开始并回放 WAL 日志,确保所有已持久化的 WAL 日志都被应用。而在网络表空间中,持久化 WAL 日志的应用持续、异步地发生在存储服务层,并分布在各个节点中。最终对于崩溃处理的过程分散在所有正常的前台处理中,在数据库启动的时候不需要做任何操作。
数据库存储服务的核心设计原则是最小化在计算服务器中的前台写入请求的延迟。我们将大多数存储处理移至后台。考虑到存储层从峰值到平均请求的差异,我们有足够的时间在前台操作路径之外去执行这些任务。
我们来进一步研究一下存储节点的各种处理流程。如图 1 所示,它涉及到以下步骤:
-
接收日志记录并将其添加到 WAL 缓冲区中。
-
计算服务层事务提交时,通知存储服务层将 WAL 缓冲区的内容写出到磁盘,并返回确认消息告知进度。
-
启动恢复后台进程检测新的日志记录,持续、异步地应用持久化的 WAL 日志。
-
计算服务层收到存储服务层返回的进度消息,在刷写脏页时可用于判断数据页面是否已经持久化,如果还没有持久化,这里会将数据页发送给存储服务层进行持久化(除非存储服务层应用日志的速度很慢,一般都不会发生)。
-
定期进行检查点操作,将所有脏数据页刷写到磁盘,写入一条特殊的检查点记录到 WAL 日志文件。
-
完成一个检查点后位于包含重做记录的日志段之前的日志段就不再需要了,可以将其回收或删除。
注意上述每个步骤都是异步的,并且仅仅只有步骤 1 和步骤 2 位于前台处理路径中,可能会影响延时。
在网络表空间中,计算服务层不断与存储服务层交互,并推进表空间的数据持久化。计算服务层在需要刷写脏页时,在确认来自存储服务层的回复指示它们已经收到了记录该页面修改的 WAL 日志并且已经应用了该日志后,就不需要发起页面的刷写动作了。
与传统的本地表空间一样,在网络表空间中,页面由缓冲区缓存提供,并且仅当相关页面不存在于缓存中时才会向存储服务层发起页面读取请求。
如果缓冲区缓存已满,系统将找到要从缓存中逐出的数据页面。在传统数据库系统中,如果这个页面是“脏页”,则在替换之前将其刷新到磁盘。这是为了确保随后的页面读取始终能获取到最新的数据。在网络表空间中,数据库不太会在逐出数据页时写出页面,但它会做出类似的保证:缓冲区中的数据页面必须始终是最新版本。
大多数传统数据库使用诸如 ARIES 这类的恢复协议,该协议依赖于预写式日志(WAL)的存在,该日志可以表示所有已提交事务的精确内容。这些系统还定期对数据库进行检查点操作,以粗粒度的方式建立持久性点,方法是将脏页刷新到磁盘并将检查点记录写入日志。重新启动时,任何给定的页面都可能错过一些已提交的数据或包含未提交的数据。因此,在崩溃恢复时,系统按照 WAL 日志应用逻辑将每条日志记录应用于相关数据库页来处理自上次检查点以来的重做日志记录。此过程使数据库页在故障点处于一致状态,在此之后,可以通过执行相关的撤消日志记录来回滚崩溃期间正在进行的事务。崩溃恢复可能是一项代价高昂的操作。缩短检查点间隔会有所帮助,但代价是干扰前台事务。对于网络表空间,不需要进行这样的权衡。
传统数据库的一个很好的简化原则是,前台修改数据页面的流程和故障恢复流程使用相同的 WAL 日志应用逻辑,在故障恢复过程完成 WAL 日志应用之前,数据库不会提供服务。我们在网络表空间中也依赖于相同的原则,除了 WAL 日志应用能力与计算服务层分离,并在存储服务层并行运行,并且始终在后台运行。数据库启动后,它会与存储服务协作执行表空间恢复,因此,网络表空间可以非常快速地恢复(通常在 10 秒内),即使它在每秒处理超过 10000 个事务时崩溃。
数据库仍需要执行撤消恢复,以在崩溃时取消正在进行的事务的操作。但是,当系统从回滚段构建这些正在进行的事务的列表后,当数据库处于联机状态时,可能会发生撤消恢复。