共计 5434 个字符,预计需要花费 14 分钟才能阅读完成。
本文由腾讯云数据库发表
前言
CynosDB 是新一代分布式数据库,100% 兼容 MySQL 和 PostgreSQL,支持存储弹性扩展,一主多从共享数据,性能更是超越社区原生 MySQL 和 PostgreSQL。CynosDB 采用 share storage 架构,其弹性扩展和高性价比的基石则是 CynosDB File System(简称 CynosFS):一款腾讯云自研的用户态分布式文件系统。本文旨在从整体上讲述 CynosDB 和 CynosFS 的核心架构设计。
挑战与应对
CynosDB 是公有云原生架构的,其核心思想是在资源池化的基础上实现公有云高性价比、高可用性以及弹性扩展等诸多优势。实现资源池化的最大技术挑战是高效、稳定的弹性调度能力,该能力也是公有云产品高可用性的基石。计算、网络和存储是公有云三大类 Iaas 产品,前面两类都有比较成熟的弹性调度架构,唯独存储产品例外。究其根本还是数据调度的代价太高。数据库是典型的计算 + 存储的产品,要做到资源池化需要:
l 存储与计算分离:这样计算资源(主要包含 CPU 和内存)就可以使用现有成熟的容器、虚拟机等技术实现资源池化
l 分布式存储:将数据分割成规格化的块,引入分布式调度系统,实现存储容量和 IO 的弹性调度,从而实现存储资源的池化
那么对于数据库产品来说,是否有现成架构可以很好的满足以上两个需求呢。我们发现虚拟机 + 分布式块存储(云盘)的方案非常合适,目前主流公有云平台也都有非常成熟的产品。腾讯云今年早些时候推出的 MySQL 基础版以及 AWS 上的 RDS 都是基于这种架构。图 1 简单描述了这种架构:
图 1
但该架构有如下不足:
l 网络 IO 重:可以看到就 1 个数据库实例,就有大量数据需要写到云盘,这些数据主要包括:WAL LOG、页数据、防止页部分写的 Double Write 或者 Full Page Write。除此之外,云盘还要将这些数据做多个备份
l 主从实例不共享数据:一方面浪费了大量存储,另一方面进一步加重了网络 IO
这些不足导致基于该架构的数据库产品在系统吞吐能力上无法与基于物理机部署的主从架构竞争,而且延迟也受到很大的挑战,这对 OLTP 类业务的影响非常明显。同时每个数据库实例都单独拥有一份(实际可能是 2 - 3 份)存储,成本也很高。
CynosDB 针对这两个不足,采用了如下设计:
l 日志下沉:WAL LOG 从逻辑上已经包含了数据的所有变动,CynosDB 将 WAL LOG 下沉到存储层,数据库实例就只需要将 WAL LOG 写到存储层,不再需要写页数据(页数据以及 Double Write 或 Full Page Write),同时这个 WAL LOG 也作为 RAFT 协议的日志来完成多个数据备份的同步,进一步减少了网络 IO。
l 主从实例共享数据:CynosDB 的主从实例共享共一份存储数据,进一步减少了网络 IO,同时极大的减少了存储容量
循着这两个解决思路,我们对传统基于云盘的架构进行优化,就有了 CynosDB 如下架构:
图 2
图中组件包括:
lDB Engine:数据库引擎,支持一主多从。
lDistributed File System:用户态分布式文件系统,主要提供分布式的文件管理,负责将文件的读写请求翻译为对应的 BLOCK 读写
lLOG/BLOCK API:Storage Service 提供的读写接口,对于读写请求有不同处理:
n 写请求:将修改日志(等价于 WAL LOG)通过 LOG API 发送到 Storage Service
n 读请求:直接通过 BLOCK API 读取数据
lDB Cluster Manager:负责一主多从 DB 集群的 HA 管理。
lStorage Service:负责日志的处理、BLOCK 数据的异步回放、读请求的多版本支持等。同时还负责将 WAL LOG 备份到 Cold Backup Storage
lSegment(Seg):Storage Service 管理数据 BLOCK 和日志的最小单元(10GB),也是数据复制的实体。图中同样颜色的 3 个 Seg 实际存储同一份数据,通过一致性协议(Raft)进行同步,我们叫做 Segment Group(SG)。
lPool:多个 SG 从逻辑上构成一个连续的存储数据 BLOCK 的块设备,供上层的 Distributed File System 分配使用。Pool 和 SG 是一对多的关系。
lStorage Cluster Manager:负责 Storage Service 以及 Segment Group 的 HA 调度,以及维护 Pool 和 SG 的对应关系。
lCold Backup Service:接收到 WAL LOG 后,进行增量备份,根据增量备份,可以灵活的生成全量备份和差异备份
可以看到,上面中除了 DB Engine 和 DB Cluster Manager 外的所有模块构成了一个与数据库引擎无关的用户态分布式文件系统,我们命名为:CynosFS。
日志下沉和异步回放
这里 CynosDB 借鉴了 AWS Aurora 论文中日志即数据库的思想,将 WAL LOG 下沉到 Storage Serivce,计算层只写 WAL LOG,而由 Storage Serivce 异步地将 WAL LOG 应用到对应的 BLOCK 上,在减少写 IO 的同时,也是 Storage Serivce 提供 MVCC 读能力的基础。而 MVCC 是主从节点共享存储的基础。Storage Serivce 中的数据和日志都是以 Segment 为单元进行管理的,图 3 描述了写的基本流程:
图 3
1. 接收到更新日志,写到磁盘,并行发起第 2 步
2. 发起 RAFT 日志复制
3.RAFT 多数派提交成功,返回写日志成功
4. 异步的将日志记录挂载到对应数据 BLOCK 的更新链上
5. 合并更新链中的日志记录到数据 BLOCK
6. 将日志备份到冷备系统
7. 回收无用日志
这里第 4 步会对更新的数据 BLOCK 形成 1 个更新链,从而支持数据 BLOCK 多个版本的读,进而提供 MVCC 能力。通过控制第 5 步的合并进度,就可以控制 MVCC 的起始窗口。
同时 CynosDB 还将页面 CRC 等操作放到了存储服务中,充分利用存储服务器的 CPU 资源
MVCC 实现
CynosFS 的 MVCC 能力是 CynosDB 一主多从架构的基础,本小节会详细描述其运行机制。
首先我们引入一系列概念:
lMini-transaction(MTR):就像数据库事务用来保证事务的 ACID 特性,MTR 用来保证磁盘上页数据的 ACID 特性。举个例子,1 个 B + 树的插入操作,在造成节点分裂的情况下,最多会修改 3 个数据页,这 3 个数据页的修改需要当做 1 个事务来处理,这就是 MTR。数据库实例在磁盘上的数据是按照 MTR 为最小单元进行更新的
lWrite Ahead Log(WAL LOG):关系数据库常用的保证数据一致性的技术。WAL LOG 是一个增量日志流水,里面的日志记录(Log Records)保存了页面修改操作。由于 CynosFS 是与具体数据库引擎无关的分布式文件系统,其 WAL LOG 中记录的是对数据 BLOCK 的二进制修改,是物理日志
lLog Sequence Number(LSN):WAL LOG 中每条 Log Record 都会有 1 个唯一标识的序列号,从 1 开始,按 Log Record 产生的连续单调递增。
lConsistency Point LSN(CPL):一个 MTR 可能对应多个磁盘数据页的修改,相应的会产生多条日志记录,这批日志记录中的最后 1 条(也就是 LSN 值最大的 1 条)标识为 CPL,这条日志记录对应了一个磁盘上的数据状态,该状态表示 1 个 MTR 的完整应用,也是 MVCC 的读一致性状态
lSegment Group Complete LSN(SGCL):1 个数据库实例的数据页会分布到多个 SG 上,因此每个 SG 只会持有部分日志记录,SCL 表示该 SG 已经将所有小于等于 SCL 的日志记录持久化到磁盘上了。对于 CynosFS 来说,因为 SG 采用了 Raft 协议,SCL 就是 Raft 的 CommitIndex。
lPool Complete LSN(PCL):表示构成该 Pool 的所有 SG 已经将小于等于 PCL 的日志持久化到磁盘上。因为 LSN 是连续单调递增的,这也要等价于中间没有空洞
lPool Consistency Point LSN(PCPL):不大于 PCL 的最大的 CPL。逻辑上表示:已经持久化到磁盘的可提供 MVCC 读一致性的点。
写
首先主实例对所有数据页的修改都经过 Distributed File System 的转换,形成 Pool 级别的日志,并附带连续单调递增的 LSN,分发到不同的 SG。SG 会在完成 Raft Commmit 后推进自己的 SGCL 并返回,主实例根据所有 SG 的完成情况,推进 PCL 和 PCPL。下面我们通过 2 幅图描述 PCL 和 PCPL 的推进过程:
图 4
首先该 Pool 由 2 个 SG 构成,每个 SG 中有 3 个 Segment,存储同一份数据。当前有 LSN 为 1~8 的日志已经持久化到 2 个 SG 中,其中 1、3、4、7 在 SG A 上,2、5、6、8 在 SG B 上。这 8 条日志属于 3 个 MTR,分别是:MTR-x(1、2、3),MTR-y(4、5),MTR-z(6、7、8),其中 3 和 5 都是 CPL,表示 MTR- x 和 MTR- y 对应的日志已经全部持久化了,8 不是 CPL,说明 MTR- z 后续还有日志记录。按照上面的定义,此时 PCL 为 8,而 PCPL 为 5
图 5
图 5 中,MTR- z 的 1 条日志 CPL9 被持久化到 SG A,按照定义,此时 PCL 和 PCPL 都更新到了 9。
读
这里主要指从实例的读流程。从实例具有自己的内存数据,在主实例更新了数据后,需要同步更新从实例的内存数据,否则会出现不一致的情况。主实例会将日志记录以及最新的 PCPL 值推送给从实例。因此从实例的 PCPL 值会较主实例有所延迟。这个 PCPL 值决定了从实例上所有事务能读到的最后 1 个 MTR。同时为了减少从实例的延迟,主实例可能不等 PCPL 值推进先把日志推送到从实例,因此从实例需要保证大于本地 PCPL 值的那些日志不被应用。从实例对这些更新日志的处理方式有两类:如果对应修改的数据页在 Buffer Pool 中,则应用此日志更新到对应数据页,否则直接丢弃。最后从实例上的读事务在每次访问数据页时(不管直接从 Buffer 中获取到,还是从 Storage Service 获取),因为可能一次读入多个页,所以需要取当前的 PCPL 值为 Read Point LSN(简称:RPL),用 RPL 达成到一致性读(因为 PRL 是一个 PCPL 值,其一定能保证 MTR 的完整性)。CynosDB 支持一主多从,每个从实例上都会有很多读事务,这些读事务都具有自己的 RPL,所有这些 RPL 中最小的我们称之为 Min-RPL(简称:MRPL),那么在 MRPL 和 PCPL 之间可能会有多个 CPL 点,不同读事务的 RPL 可能在这个区间的任何 1 个 CPL 点上。因此 Storage Service 要能支持读取在这个区间内任意 CPL 点的数据,也就是 MVCC。CynosDB 使用数据页 + 更新日志链的方式来实现。
最后让我们回到图 3,SG 需要定期回收无用的日志记录,我们可以看到,所谓无用的日志记录就是其 LSN 值小于 MRPL 的那些。而大于等于 MRPL 的那些日志因为要用来支持 MVCC,所以必须保留。
事务提交
一个数据库事务由多个 MTR 组成,最后 1 个 MTR 的最后 1 条日志的 LSN(必然也是个 CPL)我们称之为 Commit LSN(简称:CLSN)。为了提升效率,日志到 Storage Service 的推送采用异步流水线的方式,同时按照 SG 进行分组并行推送。全局来看,因为是并行的,所以可能会有乱序,但推送到某个 SG 上的日志一定是按照 LSN 单调递增的(不连续)。随着 PCPL 的推进,一旦 PCPL 值大于某个事物的 CLSN,该事物就可以完成 Commit 操作了。
崩溃恢复
首先,CynosDB 会持续的保存主实例的 PCPL,这个 PCPL 的备份值我们称之为:Last PCPL(简称:L-PCPL)。CynosDB 需要保证 L -PCPL 值的更新足够快,以确保那些大于 L -PCPL 的日志记录没有被回收。在此前提下,我们通过如下步骤实现崩溃恢复:
图 6
首先,新的主实例获取到 L -PCPL 值为 3。该实例由 2 个 SG 组成,其中 SG A 中已经持久化了日志(1、4、5),而 SG B 中持久化了日志(2、3、6、8)。
图 7
主实例向 2 个 SG 读取大于 3 的所有日志 LSN,获取到 SG A 的 4、5 以及 SG B 的 6、8。这样形成了 3、4、5、6、8 的日志流。按照定义,因为没有 LSN 为 7 的日志,所以 8 是无效的,其次 6 不是 CPL,所以 6 也是无效的,这样就计算出了最新的 PCPL 值为 5。然后将新的 PCPL 值推送给所有的从实例。
图 8
最后,主实例将新的 PCPL= 5 推送给所有 SG,以便其将大于 5 的所有日志都清理掉。
经过上面三步,整个数据就回到了 PCPL= 5 这个一致性的点。主实例和从实例就可以提供服务了。
持续备份
实际上,在 CynosDB 中,几乎不需要全量的备份操作,只要保证 SG 的 WAL LOG 在回收前,被增量保存到了冷备系统中就行了。因为逻辑上 WAL LOG 是包含了所有数据的修改操作,我们可以使用增量的 WAL LOG,按照客户需求,生成全量备份和差异备份。而这些操作都可以是由另一套独立的系统基于增量备份数据离线处理的,对 CynosDB 的线上系统不会造成任何的影响。另外我们还需要对实例的状态配置信息进行备份,以便恢复时能获取到相关信息。
此文已由作者授权腾讯云 + 社区发布,更多原文请点击
搜索关注公众号「云加社区」,第一时间获取技术干货,关注后回复 1024 送你一份技术课程大礼包!