Azure SQL DB Hyperscale 是微软推出的一款 Amazon Aurora 竞品。Aurora 采用了开源版本 MySQL 和 PostgreSQL 的前端,并将它们连接到强大的后端云存储引擎,而 Hyperscale 采用了 SQL Server 的前端(查询优化器和查询处理器),并将它们连接到新的后端。
SQL DB Hyperscale 是一种基于 SQL 的高度可扩展的服务层,适用于单个数据库,可根据工作负载需求进行调整。 借助 SQL DB Hyperscale,数据库可以快速自动扩展至 100TB,无需预先配置存储资源,并显著扩大应用程序增长的潜力,而不受存储大小的限制。
当数据库服务器在物理硬件上运行时,看起来像这样:
CPU:用于运行数据库引擎代码的 Intel 或 AMD 处理器;
内存:缓存层;
数据文件:本地存储中的文件,其中包含了数据库数据,是数据库主要的事实来源;
日志文件:本地存储中的文件,其中记录了数据库对数据文件所做的操作。当数据库服务器意外崩溃,数据文件处于不一致状态时,日志文件会非常有用;
RAID:在驱动器阵列上存储数据的处理器。
传统数据库服务器高可用性
通常,如果你让 DBA 画出数据库故障转移架构图,他们画出来的会是这张图的多个副本,它们跨越了多台独立的服务器。数据库服务器(SQL Server、Postgres、MySQL、Oracle 等)通过将记录命令复制到其他副本来保持数据同步:
一种不太常见的做法(在技术上是可行的)是将数据库服务器与文件存储分离开。你可以将数据库放在文件服务器上,然后通过 UNC 路径来访问它们。
如果数据库服务器满载,可以启动另一个数据库服务器,将数据和日志文件附加到新服务器上,然后继续提供服务。这是一种不太常见的做法,它存在一些问题,比如网络问题、启动另一个数据库服务器太慢,等等。
但如果你在云端这么做会怎样?
从概念上将存储分开
RAID 的职责是:
接收数据写入,并将它们临时存储在数量有限的快速缓存中(接近内存的速度,但在发生崩溃或断电时是安全的);
稍后,将这些写入分发给持久存储(硬盘或固态硬盘);
在读取数据时,找出哪些驱动器保存了需要读取的数据;
尝试在快速存储中缓存数据(它发现了数据的访问模式);
监控底层持久存储的运行状况,当驱动器发生故障时,自动将热备驱动器置于运行状态。
在这个新设计中,我们将构建一个更强大的存储子系统。我们将用另一种更强大的设计来替换 RAID,而在这个新设计中,我们将为存储分配比之前更多的职责:
将数据分解为几个网络服务(这可能比本地闪存存储慢一点,但比共享存储要快);
跨多个数据中心复制数据库(不涉及数据库服务器);
存储引擎负责将事务日志变更应用在数据文件上。
以下是新的架构图:
CPU:运行数据库引擎代码的虚拟机(Intel 或 AMD 处理器);
内存:本地固态缓存层;
数据文件:本地存储服务中的文件,其中包含了数据库数据,是数据库主要的事实来源;
日志文件:本地存储服务中的文件,其中记录了数据库对数据文件所做的操作。当数据库服务器意外崩溃,数据文件处于不一致状态时,日志文件会非常有用;
RAID:在驱动器阵列上存储数据的处理器服务。
当你进行数据插入时:
数据库引擎的查询处理器告诉日志服务:“我想在数据文件 1 的第 300 页添加一行”。
在将命令写入日志服务后,插入完成。
日志服务读取要完成的任务清单,打开数据文件 1,定位到第 300 页,添加相关行。
这样做的优势在于:
主副本具有较少的存储吞吐量,因为它不需要将变更写入数据文件。
日志服务可以对多个数据文件副本做出必要的数据文件变更,即使是在多个数据中心中,甚至是跨多个大洲。
你可以添加更多的数据库和数据库副本,而无需额外开销。如果你曾经处理过可用工作线程耗尽或者由于副本超载而导致同步提交延迟问题,你就会知道这有多酷。
我们可以使用廉价的本地固态存储器来线性扩展数据文件存储。
Azure SQL DB Hyperscale 是这么做的
在传统的 SQL Server 中,如果数据库很大,你可以创建多个数据文件,并将每个数据文件放在单独的卷中。
在 Hyperscale 中,微软通过一种更优雅的方式自动做到这一点:你看到的数据文件实际上是页面服务器。当上一个页面服务器达到约 80%时,会自动为你添加另一个页面服务器,这个服务器在数据库中显示为新的数据文件。
Aurora 和 Hyperscale 所面临的挑战(我不想将它们视为缺点,因为它们是可以被修复的):
现在,如果我们在 IO 子系统经过完美调优的物理服务器上运行数据库,写入延迟可能会在亚毫秒级。但说实话,这样的条件太奢侈了。对于 Azure SQL DB Hyperscale,微软的目标是将日志写入延迟控制在 2.5 毫秒以下,随着他们推出 Azure Ultra SSD,延迟降到 0.5 毫秒以下。
我们将无法使用一些依赖于直接操作数据文件的数据库引擎功能——例如,现在 Hyperscale 不提供透明数据加密或批量日志恢复模型。
缓存变得有点奇怪。主副本仍然需要自己修改内存缓存的数据页,因为有时候人们在插入一行数据后又立即查询刚刚插入的数据,不需要等待日志服务对数据页做出修改,然后主副本从缓存中获取数据页的新副本。
更多的复杂性。这种范式包含了很多新的移动部件,如果要提高可靠性,至少需要成对地运行它们。所有这些移动部件都需要进行控制、诊断和打补订。
在短期内需要花更多的钱。我打赌你们当中的一些人一定会说:“这个许可真是绝了,这个比包含 2 个节点的 Availability Group(在 1,000 美元的英特尔 PCIe 上运行 SQL Server 标准版)还要贵,而且还慢”。你说的没错。这也是为什么微软称之为“Hyperscale”。
AWS Aurora 和 Azure SQL DB Hyperscale 在这方面采用了相同的方法,将删除/更新/插入操作委托给日志服务,让日志服务直接修改数据文件。
下一阶段:扩展计算
之前说过,日志服务可以添加更多的数据库和数据库副本,而无需额外开销。既然如此,为什么不利用这个优势呢?
在 Azure SQL DB Hyperscale 中,这是借助 Always On Availability Group 监听器来实现的。当应用程序要查询一个可读副本时,应用程序在连接期间指定 ApplicationIntent = ReadOnly,并被自动重定向到其中的一个可读副本。
同样,在 AWS Aurora 中,应用程序连接到一个用于只读连接的 DNS 名称。AWS 有一个有趣的特性:对于某些类型的查询,Aurora 将跨多个可读副本进行并行化查询。DBA 很喜欢这个特性,但如果你的查询总是需要涉及多个副本,那么你的脚下可能踩着一颗定时炸弹:你将无法进行大量的并行查询,并且 AWS 会对你执行的每个 IO 收取费用。这是在往糟糕的查询上砸钱——但有时候这样做也无可厚非。
缓存当然变得有点奇怪了。使用传统的 SQL Server Availability Group,数据库引擎可以接收到每一个日志变更,因此它知道需要修改哪些页,而且即使缓存提供的是过时的数据也没关系。现在,数据页由日志服务负责修改,那么就存在副本会提供过时数据的风险。在我看来,我并不太担心这一点,因为 Availability Group 也可能发生类似的问题。异步复制可能会发生延迟(甚至暂停),并且副本可能会在应用变更时落后。
这种设计具有巨大的优势:副本之间不需要发生交互,也不需要在物理位置上靠近彼此。它们只是从数据文件和日志文件中读取数据,不需要知道任何有关刷新数据和日志文件的信息。
谁应该考虑使用 Hyperscale 和 Aurora?
如果你符合以下这些条件,那么你应该考虑使用 AWS Aurora 或 Azure SQL DB Hyperscale:
你有一个应用程序使用了 MySQL、Postgres 或 SQL Server 后端;
只读查询的工作负载足够高,需要将负载分散到多个服务器上(要么让只读查询更快,要么释放主服务器的复杂,让写入更快);
只读查询允许几秒钟的数据延迟;
你无法很快或经济地实现缓存;
你的主要瓶颈不在于写入事务日志(或者如果是,你的日志写入需要 2 毫秒以上);
你愿意依赖供应商的支持。
如果你想了解更多关于这些内容的信息,请访问以下资源:
Amazon Aurora:高吞吐量云原生关系型数据库的设计注意事项——这是一份详细的白皮书,解释了当前数据库存储存在的问题,以及他们是如何构建 Aurora 解决方案的。
Azure SQL DB Hyperscale文档——我也不喜欢在这里提供手册链接,但是这个东西太新了,几乎还没有其他公开的文档。
AWS re:Invent 视频:Deep Dive on Aurora MySQL and Aurora Postgres。
英文原文:https://www.brentozar.com/archive/2019/01/how-azure-sql-db-hyperscale-works/
评论