使用 Aurora 多主集群
Amazon 公布了 Amazon Aurora MySQL 兼容版 v1 的终止使用策略。有关 Aurora MySQL 版本 1 保持可用的时间以及如何迁移到更高 Aurora MySQL 版本的详细信息,请参阅 准备终止使用 Amazon Aurora MySQL 兼容版的版本 1 。
接下来,您可以了解 Aurora 多主集群。在多主集群中,所有数据库实例都具有读/写功能。与单主集群相比,多主集群具有不同的可用性特征、对数据库功能的支持以及用于监控和故障排除的过程。
Aurora 多主集群概述
在设置新 Aurora 集群时,使用以下背景信息可帮助您选择多主集群或单主集群。为了让您做出明智的选择,我们建议您首先了解计划如何调整架构设计和应用程序逻辑,以便最好地与多主集群配合使用。
对于每个新 Amazon Aurora 集群,您可以选择是创建单主集群还是多主集群。
大多数类型的 Aurora 集群都是单主 集群。例如,预置集群、Aurora Serverless 集群、并行查询集群和全局数据库集群都是单主集群。在单主集群中,一个数据库实例执行所有写操作,任何其他数据库实例都是只读的。如果写入器数据库实例不可用,则故障转移机制会将其中一个只读实例提升为新的写入器。
在多主集群 中,所有数据库实例都可以执行写操作。单个读/写主实例和多个只读 Aurora 副本的概念不适用。当写入器数据库实例不可用时,不会发生任何故障转移,因为另一个写入器数据库实例可以立即接管失败实例的工作。我们将这种类型的可用性称为持续可用性,以区别于单主集群提供的高可用性(故障转移期间有短暂的停机时间)。
多主集群在许多方面与其他类型的 Aurora 集群不同,例如预置集群、Aurora Serverless 集群和并行查询集群。利用多主集群,您可以在高可用性、监控、连接管理和数据库功能等方面考虑不同的因素。例如,在您无法承受数据库写入操作的短暂停机时间的应用程序中,多主集群可以帮助避免在写入器实例变得不可用时发生中断。多主集群不使用故障转移机制,因为它不需要提升另一个数据库实例以具有读/写功能。利用多主集群,您可以检查与所有数据库实例而不是单个主实例的 DML 吞吐量、延迟和死锁相关的指标。
目前,多主集群需要 Aurora MySQL 版本 1,该版本与 MySQL 5.6 兼容。在 Amazon Web Services Management Console、Amazon CLI 或 RDS API 中指定数据库引擎版本时,请选择 5.6.10a
。
要创建多主集群,您可以在创建集群时选择 Database features (数据库功能) 下的 Multiple writers (多个写入器)。与其他类型的 Aurora 集群相比,这样做可以在数据库实例、可用性和性能之间实现不同的复制行为。此选择对集群的生命周期仍有效。确保您了解适合于多主集群的专用案例。
多主集群术语
通过学习以下定义,您可以了解有关多主集群的术语。这些术语在多主集群的整个文档中都有使用。
- 写入器
-
可以执行写操作的数据库实例。在 Aurora 多主集群中,所有数据库实例都是写入器。这与 Aurora 单主集群有着显著差异,其中仅一个数据库实例可充当写入器。对于单主集群,如果写入器变得不可用,则故障转移机制会将另一个数据库实例提升为新的写入器。利用多主集群,您的应用程序可以将写操作从失败的数据库实例重定向到集群中的任何其他数据库实例。
- 多主
-
Aurora 集群的架构,其中每个数据库实例均可执行读写操作。将此方面与单主 集群进行比较。多主集群最适合分段工作负载,例如多租户应用程序。
- 单主
-
Aurora 集群的默认架构。单个数据库实例(主实例)执行写操作。所有其他数据库实例(Aurora 副本)处理只读查询流量。将此方面与多主 集群进行比较。此架构适用于通用应用程序。在此类应用程序中,一个数据库实例可以处理所有数据操作语言 (DML) 和数据定义语言 (DDL) 语句。可扩展性问题主要涉及
SELECT
查询。 - 写冲突
-
当不同的数据库实例尝试同时修改同一数据页时发生的情况。Aurora 会将写入冲突作为死锁错误报告给您的应用程序。此错误情况会导致事务回滚。您的应用程序必须检测错误代码并重试事务。
Aurora 多主集群的主要设计考虑和性能优化目标是以最小化写冲突的方式划分数据库实例之间的写操作。这就是多主集群非常适合分片应用程序的原因。有关写冲突机制的详细信息,请参阅 多主集群的冲突解决。
- 分片
-
特定类别的分段工作负载。数据在物理上被划分为多个分区、表、数据库,甚至单独的集群。数据的特定部分的容器称为分片。在 Aurora 多主集群中,每个分片由一个特定的数据库实例管理,并且一个数据库实例可以负责多个分片。分片架构设计很好地映射到您在 Aurora 多主集群中管理连接的方式。
- 分片
-
分片部署中的粒度单位。它可能是一个表、一组相关表、一个数据库、一个分区,或者甚至是整个集群。利用 Aurora 多主集群,您可以将分片应用程序的数据整合到单个 Aurora 共享存储卷中,从而使数据库持续可用且数据易于管理。您可以决定每个数据库实例管理哪些分片。您可以随时更改此映射,而无需物理地重新组织数据。
- 重新分片
-
物理地重新组织分片数据,以便不同的数据库实例可以处理特定的表或数据库。您无需在 Aurora 多主集群中物理地重新组织数据,以响应不断变化的工作负载或数据库实例故障。您可以避免重新分片操作,因为集群中的所有数据库实例都可以通过共享存储卷访问所有数据库和表。
- 多租户
-
特定类别的分段工作负载。每个客户、客户端或用户的数据都保存在单独的表或数据库中。此设计可确保隔离,并帮助您在单个用户级别管理容量和资源。
- 自带分片 (BYOS)
-
一种您拥有数据库架构以及使用了分片的关联应用程序的情况。您可以相对轻松地将此类部署转移到 Aurora 多主集群。在这种情况下,您可以将精力投入到研究诸如服务器整合和高可用性等 Aurora 好处方面。您无需创建新的应用程序逻辑来处理写请求的多个连接。
- 全局先写后读 (GRAW)
-
一种引入同步的设置,使得任何读操作始终能看到数据的最新状态。默认情况下,多主集群中的读操作所看到的数据会受到复制延迟(通常是几毫秒)的影响。在此短暂的间隔期间,如果同一数据由不同的数据库实例同时修改,则对一个数据库实例的查询可能会检索过时数据。要启用此设置,请将
aurora_mm_session_consistency_level
从INSTANCE_RAW
(默认设置)更改为REGIONAL_RAW
。这样做可确保读操作的集群范围一致性,而不管执行读写操作的数据库实例如何。有关 GRAW 模式的详细信息,请参阅 多主集群的一致性模型。
多主集群架构
多主集群具有不同于其他类型的 Aurora 集群的架构。在多主集群中,所有数据库实例都具有读/写功能。其他类型的 Aurora 集群有一个执行所有写操作的专用数据库实例,而所有其他数据库实例都是只读的,并且仅处理 SELECT
查询。多主集群没有主实例或只读 Aurora 副本。
应用程序控制哪些写请求由哪个数据库实例处理。因此,利用多主集群,您可以连接到单个实例终端节点来发出 DML 和 DDL 语句。这与其他类型的 Aurora 集群不同,在这些集群中,通常将所有写操作指向单个集群终端节点,并将所有读操作指向单个读取器终端节点。
Aurora 多主集群的底层存储类似于单主集群的存储。您的数据仍存储在一个高度可靠且自动增长的共享存储卷中。核心差异在于数据库实例的数量和类型。在多主集群中,有 N 个读/写节点。目前,N 的最大值为 4。
多主集群没有专用的只读节点。因此,有关 Aurora 副本的 Aurora 过程和准则不适用于多主集群。您可以临时将数据库实例设置为只读,以将读写工作负载放在不同的数据库实例上。为此,请参阅 使用实例只读模式。
使用低延迟和低滞后 Aurora 复制连接多主集群节点。多主集群使用全对等复制。复制直接在写入器之间进行。每个写入器均会将其更改复制到所有其他写入器。
多主集群中的数据库实例独立地处理重新启动和恢复操作。如果一个写入器重新启动,则不需要其他写入器也重新启动。有关详细信息,请参阅Aurora 多主集群的高可用性注意事项。
多主集群跟踪所有数据库实例中数据的所有更改。度量单位是数据页,其固定大小为 16 KB。这些更改包括对表数据、二级索引和系统表的修改。Aurora 内部管理任务也可能造成更改。在共享存储卷中与数据库实例内存中,Aurora 会确保为每个数据页保留的多个物理副本之间的一致性。
如果两个数据库实例几乎在同一时刻尝试修改同一数据页,则会发生写冲突。最早的更改请求是使用法定数量投票机制批准的。该更改将保存到永久存储中。未批准更改的数据库实例将回滚包含尝试更改的整个事务。回滚事务可确保数据保持一致状态,并且应用程序始终能看到可预测的数据视图。您的应用程序可以检测死锁情况并重试整个事务。
有关如何最大程度地减少写冲突和相关性能开销的详细信息,请参阅 多主集群的冲突解决。
建议的多主集群工作负载
多主集群最适合特定类型的工作负载。
主动/被动工作负载
利用主动/被动 工作负载,您可以一次在一个数据库实例上执行所有读写操作。您可以保留 Aurora 集群中的任何其他数据库实例。如果原始活动数据库实例变得不可用,则立即将所有读和写操作切换到另一个数据库实例。利用此配置,可以最大程度地减少写操作的任何停机时间。另一个数据库实例可以接管应用程序的所有处理,而无需执行故障转移。
主动/主动工作负载
利用主动/主动 工作负载,您可以同时对所有数据库实例执行读和写操作。在此配置中,通常会对工作负载进行分段,以便不同的数据库实例不会同时修改相同的基础数据。这样做可最大程度地降低发生写冲突的可能性。
多主集群可以很好地与专为分段工作负载 设计的应用程序逻辑配合使用。在此类工作负载中,您可以按数据库实例、数据库、表或表分区划分写操作。例如,您可以在同一个集群上运行多个应用程序,每个应用程序均分配给一个特定的数据库实例。或者,您可以运行一个使用多个小型表的应用程序,例如为在线服务的每个用户使用一个表。理想情况下,您可以设计架构,以便不同的数据库实例的写操作不会同时更新同一表中的重叠行。分片应用程序就是此类架构的一个例子。
有关主动/主动工作负载的设计的示例,请参阅 将多主集群用于分片数据库。
多主集群的优势
您可以利用 Aurora 多主集群的以下优势:
-
多主集群进一步提高了 Aurora 的高可用性。您可以重新启动读/写数据库实例,而不会导致集群中的其他数据库实例重新启动。当读/写数据库实例变得不可用时,没有故障转移过程和相关的延迟。
-
多主集群非常适合分片应用程序或多租户应用程序。在管理数据时,可以避免复杂的重新分片操作。您可能能够使用较少数量的集群或数据库实例来合并分片应用程序。有关详细信息,请参阅将多主集群用于分片数据库。
-
Aurora 会立即检测写冲突,而不是在事务提交时这样做。有关写冲突机制的详细信息,请参阅 多主集群的冲突解决。
多主集群的限制
Aurora 多主集群仅适用于 Amazon Aurora MySQL 兼容版 v1。Amazon 公布了该主要 Aurora MySQL 版本的终止使用策略。
有关 Aurora MySQL 版本 1 保持可用的时间以及如何迁移到更高 Aurora MySQL 版本的详细信息,请参阅 准备终止使用 Amazon Aurora MySQL 兼容版的版本 1 。
Amazon和 Aurora 限制
以下限制当前适用于Amazon以及可用于多主集群的 Aurora 功能:
-
目前,多主集群中最多可以有四个数据库实例。
-
目前,多主集群中的所有数据库实例必须位于同一 Amazon 区域中。
-
仅支持的数据库实例类为
db.r4.2xlarge
–db.r4.16xlarge
。 -
您无法从多主集群启用跨区域副本。
-
多主集群在以下 Amazon 区域中可用:
US East (N. Virginia) Region
美国东部(俄亥俄)区域
US West (Oregon) Region
亚太地区 (孟买) 区域
亚太区域(首尔)
Asia Pacific (Tokyo) Region
欧洲(法兰克福)区域
Europe (Ireland) Region
-
Stop
操作不适用于多主集群。 -
多主集群不支持 Aurora 自动恢复页面缓存(也称为自动恢复缓冲池)。
-
多主集群不对连接进行任何负载平衡。您的应用程序必须实现自己的连接管理逻辑,以在多个数据库实例终端节点之间分配读和写操作。通常,在自带分片 (BYOS) 应用程序中,您已拥有将每个分片映射到特定连接的逻辑。要了解如何在应用程序中调整连接管理逻辑,请参阅 多主集群的连接管理。
-
Aurora 多主集群高度专用于连续可用性使用案例。因此,此类集群通常可能不适用于所有工作负载。通过将更大的数据库实例类与 Aurora 单主集群配合使用,可以满足您的性能、可扩展性和可用性要求。如果是这样,请考虑使用预置集群或 Aurora Serverless 集群。
-
多主集群具有一些处理和网络开销,用于数据库实例之间的协调。对于写密集型和读密集型应用程序,此开销会产生以下影响:
-
在具有多个并发写操作的繁忙集群上,吞吐量优势最为明显。在许多情况下,具有单个主实例的传统 Aurora 集群可以处理集群的写流量。在这些情况下,多主集群的优势主要在于高可用性而不是性能。
-
单查询性能通常低于等效的单主集群。
-
-
您无法使用在单主集群上创建的快照并在多主集群上还原该快照,反之亦然。相反,要将所有数据从一种集群传输到另一种集群,请使用由 Amazon Database Migration Service (Amazon DMS) 等工具或 mysqldump 命令生成的逻辑转储。
-
当您还原在多主集群上创建的快照时,请确保包含
--engine-mode multimaster
选项。如果您不使用此选项,会收到错误。 -
您不能在多主集群上使用并行查询、Aurora Serverless 或全局数据库功能。
多主特性是集群的永久选择。您无法在多主集群和另一种集群(如 Aurora Serverless 或并行查询集群)之间切换现有 Aurora 集群。
-
零停机时间修补 (ZDP) 和零停机时间重启 (ZDR) 功能不适用于多主集群。
-
与其他Amazon服务(例如 Amazon Lambda、Amazon S3 和 Amazon Identity and Access Management)的集成不适用于多主集群。
-
Performance Insights 功能不适用于多主集群。
-
无法克隆多主集群。
-
无法为多主集群启用回溯功能。
数据库引擎限制
以下限制适用于可用于多主集群的数据库引擎功能:
-
无法对多主集群执行二进制日志 (binlog) 复制。此限制意味着您也无法在多主集群中使用全局事务 ID (GTID) 复制。
-
事件计划程序不适用于多主集群。
-
多主集群上未启用哈希联接优化。
-
查询缓存在多主集群上不可用。
-
无法在多主集群上使用某些 SQL 语言功能。有关 SQL 差异的完整列表以及有关调整 SQL 代码以解决这些限制的说明,请参阅 多主集群的 SQL 注意事项。
从多主集群迁移
从 Aurora 多主集群迁移意味着更改回 Aurora 单主数据库集群。请使用 Amazon Database Migration Service (Amazon DMS) 之类的工具或 mysqldump 命令生成的逻辑转储。
创建 Aurora 多主集群
您无法再使用 Amazon Web Services Management Console创建 Aurora 多主数据库集群。使用 Amazon CLI 或 RDS API。如果您之前未创建任何 Aurora 集群,则可了解 创建 Amazon Aurora 数据库集群 中的一般过程。
要使用 Amazon CLI 创建多主集群,请运行 create-db-cluster Amazon CLI 命令并包含值为 multimaster
的 --engine-mode
选项。
以下命令显示用于通过多主复制创建 Aurora 集群的语法。有关创建 Aurora 集群的一般过程,请参阅 创建数据库集群。
对于 Linux、macOS 或 Unix:
aws rds create-db-cluster --db-cluster-identifier sample-cluster --engine aurora \ --engine-version 5.6.10a --master-username
user_name
--master-user-passwordpassword
\ --db-subnet-group-namemy_subnet_group
--vpc-security-group-idsmy_vpc_id
\ --engine-mode multimaster
对于 Windows:
aws rds create-db-cluster --db-cluster-identifier sample-cluster --engine aurora ^ --engine-version 5.6.10a --master-username
user_name
--master-user-passwordpassword
^ --db-subnet-group-namemy_subnet_group
--vpc-security-group-idsmy_vpc_id
^ --engine-mode multimaster
创建多主集群后,您可以向其添加写入器数据库实例。有关更多信息,请参阅向 Aurora 多主集群添加数据库实例。
要使用 RDS API 创建多主集群,请运行 CreateDBCluster 操作。为 multimaster
参数指定值 EngineMode
。有关创建 Aurora 集群的一般过程,请参阅 创建数据库集群。
创建多主集群后,您可以向其添加写入器数据库实例。有关更多信息,请参阅向 Aurora 多主集群添加数据库实例。
向 Aurora 多主集群添加数据库实例
您需要多个数据库实例才能看到 Aurora 多主集群的优势。创建第一个实例后,您可以创建其他数据库实例,最多可创建四个数据库实例。多主集群的区别在于新数据库实例具有读/写功能而不是只读 Aurora 副本。
控制台
您可以使用 Amazon Web Services Management Console同时向多主数据库集群添加两个初始写入器数据库实例。后续的数据库实例将单独添加。
向多主数据库集群添加数据库实例
-
在 Databases(数据库)页面上,选择数据库集群。
-
对于 Actions(操作),选择 Add DB instance(添加数据库实例)。
-
(可选)命名您的数据库实例并选择可用区。
-
对于 DB instance class(数据库实例类),选择 Include previous generation classes(包括上一代类),然后选择
db.r4
数据库实例类。 -
选择 Add DB instance(添加数据库实例)。
Amazon CLI 或 RDS API
使用 Amazon CLI 或 RDS API 可一次添加一个写入器数据库实例。按照将 Aurora 副本添加到数据库集群中的常规程序进行操作。
以下 Amazon CLI 示例向 Aurora 多主数据库集群添加写入器实例。
对于 Linux、macOS 或 Unix:
aws rds create-db-instance \ --db-instance-identifier mm-cluster2-instance \ --db-cluster-identifier mm-cluster2 \ --db-instance-class db.r4.2xlarge \ --engine aurora
对于 Windows:
aws rds create-db-instance ^ --db-instance-identifier mm-cluster2-instance ^ --db-cluster-identifier mm-cluster2 ^ --db-instance-class db.r4.2xlarge ^ --engine aurora
管理 Aurora 多主集群
您对 Aurora 多主集群进行大多数管理的方式与其他类型的 Aurora 集群相同。以下部分介绍了用于管理的多主集群的差异和独特功能。
监控 Aurora 多主集群
多主集群还支持 MySQL 和 Aurora 单主集群支持的大多数监控和诊断功能:
-
MySQL 错误日志、常规日志和慢速查询日志。
-
MySQL 内置诊断功能,例如 SHOW 命令、状态变量、InnoDB 运行时状态表等。
-
MySQL 性能架构。
-
高级审核。
-
CloudWatch 指标。
-
增强监控。
Aurora 多主集群目前不支持以下监控功能:
-
Performance Insights。
多主集群的数据摄取性能
在多主集群上进行 DML 操作的一个最佳实践是使事务保持小而简短。此外,将特定表或数据库的写操作路由到特定数据库实例。进行批量导入可能需要放松对事务大小的指导。但是,您仍可以分发写操作以最大程度地降低发生写冲突的可能性。
从批量导入分发写工作负载
-
为架构中的每个数据库、表或其他对象发出单独的
mysqldump
命令。将每个mysqldump
的结果存储在一个文件中,该文件的名称反映了要转储的对象。作为替代方案,您可以使用专门的转储和导入工具来自动并行转储多个表,例如mydumper
。 -
为每个数据文件运行单独的
mysql
会话,连接到处理相应架构对象的相应实例终端节点。同样,作为替代方案,您可以使用专门的并行导入命令,例如myloader
。 -
跨多主集群中的数据库实例并行运行导入会话,而不是先等待每个会话完成,然后再开始下一个会话。
您可以使用以下方法将数据导入 Aurora 多主集群中:
-
如果语句不使用任何不受 Aurora 支持的功能,则可以将逻辑(SQL 格式)转储从其他与 MySQL 兼容的服务器导入到 Aurora 多主集群。例如,包含 MySQL 全文搜索 (FTS) 索引的表中的逻辑转储不起作用,因为多主集群不支持 FTS 功能。
-
您可以使用 DMS 等托管服务将数据迁移到 Aurora 多主集群。
-
对于从与 MySQL 不兼容的服务器到 Aurora 多主集群的迁移,请按照现有的异构 Aurora 迁移说明进行操作。
-
Aurora 多主集群可以 SQL 格式生成与 MySQL 兼容的逻辑转储。任何可以理解此类格式的迁移工具(例如 Amazon DMS)都可以使用来自 Aurora 多主集群的数据转储。
-
Aurora 不支持将多主集群作为 binlog 主集群或工作集群来进行二进制日志记录。无法将基于 binlog 的 CDC 工具与多主集群结合使用。
-
在从与 MySQL 不兼容的服务器迁移时,您可以使用 Amazon DMS 的连续更改数据捕获 (CDC) 功能复制到多主集群。这种类型的复制将 SQL 语句传输到目标集群,因此对 binlog 复制的限制不适用。
有关迁移方法和建议的详细讨论,请参阅 Amazon Aurora 迁移手册
从多主集群导出数据
您可以保存多主集群的快照并将其还原到另一个多主集群。目前,您无法将多主集群快照还原到单主集群中。
要将数据从多主集群迁移到单主集群,请使用逻辑转储并使用 mysqldump
等工具进行还原。
无法将多主集群用作二进制日志复制的源或目标。
Aurora 多主集群的高可用性注意事项
在 Aurora 多主集群中,任何数据库实例都可以重新启动,而不会导致任何其他实例重新启动。与 Aurora 单主集群相比,此行为为读/写和只读连接提供了更高级别的可用性。我们将此可用性级别称为连续可用性。在多主集群中,当写入器数据库实例失败时,写可用性没有停机时间。多主集群不使用故障转移机制,因为所有集群实例都是可写的。如果数据库实例在多主集群中失败,则您的应用程序可以将工作负载重定向到剩余的正常实例。
在单主集群中,重新启动主实例会使写操作不可用,直到故障转移机制提升新的主实例。只读操作也会遇到短暂的停机时间,因为集群中的所有 Aurora 副本都会重新启动。
要最大程度地减少多主集群中的应用程序的停机时间,请执行频繁的 SQL 级别运行状况检查。如果多主集群中的数据库实例变得不可用,您可以根据预期的中断长度和工作负载中写操作的紧急程度来决定要执行的操作。如果您希望中断很短且写操作不紧急,则可以等待数据库实例恢复,然后再恢复通常由该数据库实例处理的工作负载。或者,您可以将该工作负载重定向到其他数据库实例。基础数据始终对集群中的所有数据库实例可用。即使在不太可能发生影响整个可用区的故障的情况下,高度分布的 Aurora 存储卷也可以使数据持续可用。有关从不可用的数据库实例切换写操作的计时注意事项的信息,请参阅 将多主集群用作活动备用。
多主集群和其他集群之间的复制
多主集群不支持传入或传出二进制日志复制。
升级多主集群
Aurora 多主集群使用与其他类型的 Aurora 集群相同的版本编号方案,包括主版本号和次要版本号。不过,Enable auto minor version upgrade (启用自动次要版本升级) 设置不适用于多主集群。
在升级 Aurora 多主集群时,升级过程通常会将数据库引擎从当前版本移至下一个更高版本。如果升级到版本号增加 1 以上的 Aurora 版本,则升级将使用多步骤方法。每个数据库实例均升级到下一个更高版本,然后是下一个更高版本,依此类推,直到达到指定的升级版本。
根据旧版本和新版本之间是否存在任何向后不兼容的更改,该方法会有所不同。例如,对系统架构的更新被视为向后不兼容的更改。您可以通过参阅发布说明来检查特定版本是否包含任何向后不兼容的更改。
如果旧版本和新版本之间没有任何不兼容的更改,则会单独升级和重新启动每个数据库实例。升级是交错进行的,因此整个集群不会遇到任何停机时间。在升级过程中,至少有一个数据库实例随时可用。
如果旧版本和新版本之间存在不兼容的更改,则 Aurora 将在脱机模式下执行升级。所有集群节点都会同时升级和重新启动。集群会经历一些停机时间,以避免旧引擎写入较新的系统表。
Aurora 多主集群目前不支持零停机时间修补 (ZDP)。
Aurora 多主集群的应用程序注意事项
接下来,您可以了解应用程序中可能需要进行的任何更改,因为多主机集群和单主机集群之间的功能支持或行为存在差异。
多主集群的 SQL 注意事项
以下是适用于可与多主集群结合使用的 SQL 语言功能的主要限制:
-
在多主集群中,您无法使用某些更改行布局的设置或列类型。无法启用
innodb_large_prefix
配置选项。无法使用列类型MEDIUMTEXT
、MEDIUMBLOB
、LONGTEXT
或LONGBLOB
。 -
无法在多主集群中将
CASCADE
子句与任何外键列结合使用。 -
多主集群不能包含任何具有全文搜索 (FTS) 索引的表。无法在多主集群上创建或向其导入此类表。
-
DDL 在多主集群和单主集群上的工作方式不同。例如,快速 DDL 机制不适用于多主集群。当多主集群中的表正在进行 DDL 时,无法对该表进行写入。有关 DDL 差异的完整详细信息,请参阅 对多主集群执行 DDL 操作。
-
无法在多主集群上使用
SERIALIZABLE
事务隔离级别。在 Aurora 单主集群上,可以在主实例上使用此隔离级别。 -
使用
auto_increment_increment
和auto_increment_offset
参数处理自动递增列。参数值是预先确定的且不可配置。参数auto_increment_increment
设置为 16,这是任意 Aurora 集群中的最大实例数。然而,多主集群目前对数据库实例的数量有一个较低的限制。有关详细信息,请参阅使用自动递增列。
在为 Aurora 多主集群调整应用程序时,请将该活动作为迁移处理。您可能必须停止使用某些 SQL 功能,并更改其他 SQL 功能的应用程序逻辑:
-
在
CREATE TABLE
语句中,将定义为MEDIUMTEXT
、MEDIUMBLOB
、LONGTEXT
或LONGBLOB
的任何列更改为不需要页外存储的更短类型。 -
在
CREATE TABLE
语句中,从任何外键声明中删除CASCADE
子句。如有必要,添加应用程序逻辑以通过CASCADE
或INSERT
语句模拟DELETE
效果。 -
删除 InnoDB 全文搜索 (FTS) 索引的任何使用。在源代码中检查
MATCH()
语句中的SELECT
运算符以及 DDL 语句中的FULLTEXT
关键字。检查任何来自INFORMATION_SCHEMA.INNODB_SYS_TABLES
系统表的表名是否包含字符串FTS_
。 -
在应用程序中检查 DDL 操作(例如
CREATE TABLE
和DROP TABLE
)的频率。由于 DDL 操作在多主集群中具有更多开销,因此,请避免运行多个小型 DDL 语句。例如,寻找提前创建所需表的机会。有关与多主集群的 DDL 差异的信息,请参阅 对多主集群执行 DDL 操作。 -
检查对自动递增列的使用。对于多主集群,自动递增列的值序列与其他类型的 Aurora 集群不同。检查 DDL 语句中的
AUTO_INCREMENT
关键字、last_insert_id()
语句中的函数名称SELECT
以及自定义配置设置中的名称innodb_autoinc_lock_mode
。有关差异及其处理方式的详细信息,请参阅 使用自动递增列。 -
检查代码中的
SERIALIZABLE
关键字。无法将此事务隔离级别用于多主集群。
多主集群的连接管理
多主集群的主要连接注意事项是可用的 DNS 终端节点的数量和类型。对于多主集群,您经常使用实例终端节点,这些终端节点很少用于其他类型的 Aurora 集群。
Aurora 多主集群具有以下类型的终端节点:
- 集群终端节点
-
此类型的终端节点始终指向具有读/写功能的数据库实例。每个多主集群都具有一个集群终端节点。
由于多主集群中的应用程序通常包含用于管理与特定数据库实例的连接的逻辑,因此您很少需要使用此终端节点。它主要用于连接到多主集群来执行管理。
当您不知道及其中数据库实例的状态时,也可以连接到此终端节点来检查集群拓扑。要了解此过程,请参阅 描述集群拓扑。
- 数据库实例终端节点
-
此类型的终端节点会连接到特定的命名数据库实例。对于 Aurora 多主集群,您的应用程序通常将数据库实例终端节点用于所有(或者说几乎所有)连接。您可以根据分片与集群中的数据库实例之间的映射,确定要为每个 SQL 语句使用哪个数据库实例。每个数据库实例都有一个这样的终端节点。因此,多主集群具有这些终端节点中的一个或多个,并且在多主集群中添加或删除数据库实例时,数量会发生更改。
在单主集群和多主集群之间使用数据库实例终端节点的方式不同。对于单主集群,通常不经常使用此终端节点。
- 自定义终端节点
-
此类型的终端节点是可选的。您可以创建一个或多个自定义终端节点,以便出于特定目的将数据库实例组合在一起。在连接到终端节点时,Aurora 每次都返回不同的数据库实例的 IP 地址。在多主集群中,通常使用自定义终端节点来指定一组主要用于读操作的数据库实例。我们建议不要使用具有多主集群的自定义终端节点来对写操作进行负载平衡,因为这样做会增大发生写冲突的可能性。
多主集群没有读取器终端节点。在可行的情况下,使用通常写入同一表的相同数据库实例终端节点发出 SELECT
查询。这样做可以更有效地使用缓冲池中的缓存数据,并避免因集群内的复制滞后而导致的过时数据的潜在问题。如果您没有在写入相同表的相同数据库实例上找到 SELECT
语句,并且您需要对某些查询进行严格的先写后读保证,请考虑使用 多主集群的一致性模型 中所述的全局先写后读 (GRAW) 机制来运行这些查询。
有关 Aurora 和 MySQL 连接管理的一般最佳实践,请参阅 Amazon Aurora 迁移手册
有关如何在多主数据库集群中模拟只读数据库实例的信息,请参阅 使用实例只读模式。
在创建自定义 DNS 终端节点并为 Aurora 多主集群设计驱动程序和连接器时,请遵循以下准则:
-
对于 DDL、DML 和 DCL 语句,请勿使用以循环或随机方式运行的终端节点或连接路由技术。
-
避免长时间运行的写入查询和长写入事务,除非保证这些事务不会与集群中的其他写入流量发生冲突。
-
更喜欢使用自动提交的事务。在可行的情况下,避免全局或会话级别的
autocommit=0
设置。在为编程语言使用数据库连接器或数据库框架时,请检查是否为使用连接器或框架的应用程序启用了autocommit
。如果需要,在整个代码中的逻辑点添加COMMIT
语句以确保事务是简短的。 -
当需要全局读一致性或先写后读保证时,请遵循 多主集群的一致性模型 中所述的全局先写后读 (GRAW) 的建议。
-
在可行的情况下,将集群终端节点用于 DDL 和 DCL 语句。集群终端节点有助于最大程度地减少对单个数据库实例的主机名的依赖。您无需像对 DML 语句那样按表或数据库划分 DDL 和 DCL 语句。
多主集群的一致性模型
Aurora 多主集群支持可在会话级别配置的全局先写后读 (GRAW) 模式。此设置引入了额外同步,以便为每个查询创建一致性读取视图。这样一来,查询始终能看到最新数据。默认情况下,多主集群中的复制滞后意味着在数据更新之后,数据库实例可能会在几毫秒内看到旧数据。如果您的应用程序依赖于查看任何其他数据库实例所做的最新数据更改的查询,则启用此功能,即使必须等待查询结果也是如此。
如果使用相同的数据库实例写入然后读取数据,则复制滞后不会影响查询结果。因此,GRAW 功能主要适用于通过不同的数据库实例发出多个并发写操作的应用程序。
在使用 GRAW 模式时,默认情况下不要为所有查询启用它。全局一致性读取明显慢于本地读取。因此,选择性地将 GRAW 用于需要它的查询。
请注意这些有关使用 GRAW 的注意事项:
-
GRAW 涉及到性能开销,这是由于建立集群范围内的一致性读取视图的成本造成的。事务必须首先确定集群范围内的一致时间点,然后复制必须赶上该时间。总延迟取决于工作负载,但它通常在几十毫秒的范围内。
-
无法在事务中更改 GRAW 模式。
-
在没有显式事务的情况下使用 GRAW 时,每个单独的查询都会产生建立全局一致性读取视图的性能开销。
-
启用 GRAW 后,性能损失将同时适用于读和写操作。
-
在将 GRAW 与显式事务结合使用时,建立全局一致视图的开销在事务开始时对每个事务应用一次。在事务中稍后执行的查询与在没有 GRAW 的情况下运行的查询一样快。如果多个连续语句可使用相同的读取视图,则可以将它们包装在单个事务中来提高总体性能。这样一来,每个事务(而不是每个查询)仅导致一次性能损失。
多主集群和事务
标准 Aurora MySQL 指南适用于 Aurora 多主集群。Aurora MySQL 数据库引擎已针对短期 SQL 语句进行优化。这些类型的语句通常与在线事务处理 (OLTP) 应用程序关联。
特别是,使您的写事务尽可能短。这样做可降低发生写冲突的可能性。冲突解决机制是乐观的,这意味着它在写冲突很少时表现最佳。权衡的结果是,当冲突发生时,它们会产生大量开销。
一些工作负载可以从大型事务中受益。例如,当使用多 MB 事务而不是单语句事务运行时,批量数据导入的速度要快得多。如果在运行此类工作负载时发现冲突数量是不可接受的,请考虑以下选项:
-
减小事务大小。
-
重新计划或重新安排批处理作业,使它们不发生重叠,并且不会引起与其他工作负载的冲突。如果可行,请重新计划批处理作业,使其在非高峰时段运行。
-
重构批处理作业,使其在与导致冲突的其他事务相同的写入器实例上运行。当在同一实例上运行冲突的事务时,事务引擎将管理对行的访问。在此情况下,不会发生存储级别写冲突。
多主集群中的写冲突和死锁
多主集群的一个重要性能方面是写冲突的频率。当 Aurora 存储子系统中出现此类问题时,您的应用程序会收到死锁错误,并对死锁情况进行常见错误处理。Aurora 使用无锁的乐观算法,该算法在此类冲突很少发生时表现最佳。
在多主集群中,所有数据库实例都可对共享存储卷进行写入。对于您修改的每个数据页,Aurora 自动在多个可用区 (AZ) 中分发多个副本。当多个数据库实例尝试在很短的时间内修改同一数据页时,会发生写冲突。Aurora 存储子系统在完成写操作之前检测到更改重叠并解决冲突。
Aurora 检测物理数据页面级别的写冲突,此数据页面的固定大小为 16 KiB。因此,即使更改影响不同的行,如果这些行都在同一个数据页中,也会发生冲突。
当发生冲突时,清理操作需要额外的工作来撤消来自某个数据库实例的更改。从应用程序的角度来看,引发冲突的事务会遇到死锁,并且 Aurora 会回滚整个事务。您的应用程序收到错误代码 1213。
撤消事务可能需要修改其更改已应用于 Aurora 存储子系统的许多其他数据页。根据事务更改的数据量,撤消事务可能会产生大量开销。因此,最大程度减小写冲突的可能性是 Aurora 多主集群的关键设计考虑因素。
一些冲突是由您发起的更改造成的。这些更改包括 SQL 语句、事务和事务回滚。您可以通过应用程序中的架构设计和连接管理逻辑来最大程度地减少这些类型的冲突。
发生其他冲突的原因是,SQL 语句和内部服务器线程同时发生了更改。这些冲突很难预测,因为它们依赖于您可能不知道的内部服务器活动。导致这些冲突的两种主要内部活动是垃圾回收(称为清除),以及由 Aurora 自动执行的事务回滚。例如,Aurora 在崩溃恢复期间或客户端连接丢失时自动执行回滚。
事务回滚会物理还原已进行的页面更改。回滚会像原始事务一样产生页面更改。回滚需要时间,可能是原始事务的几倍。当回滚正在进行时,它产生的更改可能会与您的事务发生冲突。
垃圾回收与多版本并发控制 (MVCC) 有关,它是 Aurora MySQL 事务引擎使用的并发控制方法。利用 MVCC,数据更改会创建新的行版本,并且数据库会保留多个版本的行以实现事务隔离,同时允许对数据进行并发访问。当不再需要行版本时,将删除(清除)它们。同样,清除过程会产生页面更改,这可能会与您的事务发生冲突。根据工作负载,数据库可以产生清除滞后:等待垃圾回收的更改队列。如果滞后显著增加,即使您停止提交 SQL 语句,数据库也可能需要相当长的时间才能完成清除。
如果内部服务器线程遇到写冲突,则 Aurora 会自动重试。相反,应用程序必须处理任何遇到冲突的事务的重试逻辑。
当来自同一数据库实例的多个事务导致这些类型的重叠更改时,Aurora 将使用标准事务并发规则。例如,如果同一数据库实例上的两个事务修改同一行,则其中一个事务将等待。如果等待时间长于配置的超时时间(innodb_lock_wait_timeout
,默认为 50 秒),则等待事务将中止,并显示“Lock wait timeout exceeded (超过锁定等待超时)”消息。
多主集群和锁定读取
Aurora 多主集群支持以下形式的锁定读取。
SELECT ... FOR UPDATE SELECT ... LOCK IN SHARE MODE
有关锁定读取的更多信息,请参阅 MySQL 参考手册
所有节点都支持锁定读操作,但锁定范围对于运行此命令的节点是本地的。在一个写入器上执行的锁定读取不会阻止其他写入器访问或修改锁定的行。尽管有此限制,您仍然可以在保证写入器之间的严格工作负载范围隔离的使用案例中使用锁定读取,例如在分片数据库或多租户数据库中。
请考虑以下准则:
-
请记住,节点始终能够立即看到其更改,而没有延迟。如果可能,您可以在同一个节点上进行读写操作,以消除 GRAW 要求。
-
如果必须运行只读查询并获得全局一致的结果,请使用 GRAW。
-
如果只读查询关心数据可见性而非全局一致性,请使用 GRAW 或在每次读取之前引入定时等待。例如,一个应用程序线程可能维护与两个不同节点的 C1 和 C2 连接。应用程序在 C1 上写入并在 C2 上读取。在这种情况下,应用程序可以使用 GRAW 立即发出读取,也可以在发出读取之前休眠。睡眠时间应等于或长于复制滞后(通常约为 20–30 ms)。
使用 aurora_mm_session_consistency_level
会话变量控制先写后读功能。有效值为 INSTANCE_RAW
(对于本地一致性模式)( 默认值)和 REGIONAL_RAW
(对于集群范围内的一致性):
对多主集群执行 DDL 操作
SQL 数据定义语言 (DDL) 语句对多主集群有特殊注意事项。这些语句有时会导致基础数据的重大重组。此类大规模更改可能会影响共享存储卷中的许多数据页。针对表和其他架构对象的定义保存在 INFORMATION_SCHEMA
表中。Aurora 会专门处理对这些表的更改,以免在多个数据库实例同时运行 DDL 语句时发生写入冲突。
对于 DDL 语句,Aurora 自动将语句处理委派给集群中的一个特殊服务器进程。由于 Aurora 将更改集中到 INFORMATION_SCHEMA
表中,因此,此机制将消除 DDL 语句之间发生写冲突的可能性。
DDL 操作会阻止对该表进行的并发写入。在对表执行 DDL 操作期间,多主集群中的所有数据库实例都限制为对该表的只读访问,直到 DDL 语句完成。
以下 DDL 行为在 Aurora 单主集群和多主集群中相同:
-
在一个数据库实例上执行的 DDL 会促使其他实例使用该表主动终止任何连接。
-
可使用
MyISAM
或MEMORY
存储引擎在任何节点上创建会话级别的临时表。 -
如果数据库实例没有足够的本地临时存储,则对非常大的表执行 DDL 操作可能会失败。
请注意多主集群中的以下 DDL 性能注意事项:
-
尽量避免在应用程序中发出大量简短的 DDL 语句。在可行的情况下,提前创建数据库、表、分区、列等。对于通常非常快的简单 DDL 语句,复制开销可能会带来显著的性能开销。在将更改复制到集群中的所有数据库实例之前,该语句不会完成。例如,多主集群创建空表、删除表或删除包含许多表的架构所需的时间比其他 Aurora 集群长。
如果您确实需要执行大量 DDL 操作,则可通过多个线程并行发出语句来减少网络和协调开销。
-
长时间运行的 DDL 语句受到的影响较小,因为复制延迟只占 DDL 语句总时间的一小部分。
-
在 Aurora 单主集群和多主集群上,会话级临时表上的 DDL 性能应大致相当。临时表上的操作在本地进行,不受同步复制开销的影响。
将 Percona Online Schema Change 与多主集群结合使用
pt-online-schema-change
工具使用多主集群。如果您的优先级是以最无阻塞的方式运行表修改,则可以使用它。但是,请注意架构更改过程的写冲突含义。
概括来说,pt-online-schema-change
工具的工作方式如下所示:
-
它创建一个具有所需结构的新的空表。
-
它在原始表上创建
DELETE
、INSERT
和UPDATE
触发器,以便在新表上重做原始表上的任何数据更改。 -
它使用小块将现有行移至新表中,同时使用触发器自动处理正在进行的表更改。
-
在移动所有数据后,它删除触发器并通过重命名表来切换表。
在将数据传输到新表时,可能会出现争用点。最初创建新表时,它完全为空,因此会成为锁定热点。在其他类型的数据库系统中也是如此。由于触发器是同步的,因此,来自热点的影响可传播回查询。
在多主集群中,影响会更明显。这种可见性是因为新表不仅引发锁争用,而且增大了发生写冲突的可能性。该表最初只有很少的页面,这意味着写入是高度本地化的,因此容易发生冲突。在表增长之后,写操作应展开,并且写冲突应不再成为问题。
可以将该在线架构更改工具与多主集群结合使用。不过,它可能需要更仔细的测试,并且在操作的最初几分钟,它对正在进行的工作负载的影响可能会略微明显一些。
使用自动递增列
Aurora 多主集群使用现有配置参数 auto_increment_increment
和 auto_increment_offset
处理自动递增列。有关更多信息,请参阅 MySQL 参考手册
参数值是预先确定的,无法更改。具体来说,auto_increment_increment
参数已硬编码为 16,这是任何类型的 Aurora 集群中的数据库实例的最大数目。
由于硬编码的递增设置,自动递增值的使用速度比在单主集群中快得多。即使给定的表仅由单个数据库实例修改过,也是如此。要获得最佳结果,请始终对自动递增列使用 BIGINT
数据类型而非 INT
。
在多主集群中,您的应用程序逻辑必须准备好容忍具有以下属性的自动递增列:
-
这些值是不连续的。
-
值可能不会在空表上从 1 开始。
-
值以大于 1 的增量增加。
-
与单主集群相比,使用这些值的速度要快得多。
以下示例说明多主集群中自动递增值的序列与预期的不同。
mysql> create table autoinc (id bigint not null auto_increment, s varchar(64), primary key (id)); mysql> insert into autoinc (s) values ('row 1'), ('row 2'), ('row 3'); Query OK, 3 rows affected (0.02 sec) mysql> select * from autoinc order by id; +----+-------+ | id | s | +----+-------+ | 2 | row 1 | | 18 | row 2 | | 34 | row 3 | +----+-------+ 3 rows in set (0.00 sec)
您可以更改 AUTO_INCREMENT
表属性。只有当非默认值大于表中已有的任何主键值时,才能可靠地使用该值。不能使用较小的值来填充表中的空间隔。如果这样做的话,更改将暂时生效或根本不生效。此行为继承自 MySQL 5.6,并且不特定于 Aurora 实现。
多主集群功能参考
接下来,您可以查找特定于 Aurora 多主集群的命令、过程和状态变量的快速参考。
使用先写后读功能
使用 aurora_mm_session_consistency_level
会话变量控制先写后读功能。有效值为 INSTANCE_RAW
(对于本地一致性模式)( 默认值)和 REGIONAL_RAW
(对于集群范围内的一致性)。
下面是一个示例。
mysql> select @@aurora_mm_session_consistency_level; +---------------------------------------+ | @@aurora_mm_session_consistency_level | +---------------------------------------+ | INSTANCE_RAW | +---------------------------------------+ 1 row in set (0.01 sec) mysql> set session aurora_mm_session_consistency_level = 'REGIONAL_RAW'; Query OK, 0 rows affected (0.00 sec) mysql> select @@aurora_mm_session_consistency_level; +---------------------------------------+ | @@aurora_mm_session_consistency_level | +---------------------------------------+ | REGIONAL_RAW | +---------------------------------------+ 1 row in set (0.03 sec)
检查数据库实例读写模式
在多主集群中,所有节点都在读/写模式下运行。innodb_read_only
变量始终返回零。以下示例说明当您连接到多主集群中的任何数据库实例时,数据库实例会报告它具有读/写功能。
$ mysql -h mysql -A -h multi-master-instance-1.example123.us-east-1.rds.amazonaws.com mysql> select @@innodb_read_only; +--------------------+ | @@innodb_read_only | +--------------------+ | 0 | +--------------------+ mysql> quit; Bye $ mysql -h mysql -A -h multi-master-instance-2.example123.us-east-1.rds.amazonaws.com mysql> select @@innodb_read_only; +--------------------+ | @@innodb_read_only | +--------------------+ | 0 | +--------------------+
检查节点名称和角色
您可以使用 aurora_server_id
状态变量检查当前连接到的数据库实例的名称。下面的示例演示如何操作。
mysql> select @@aurora_server_id; +----------------------+ | @@aurora_server_id | +----------------------+ | mmr-demo-test-mm-3-1 | +----------------------+ 1 row in set (0.00 sec)
要查找多主集群中所有数据库实例的此信息,请参阅 描述集群拓扑。
描述集群拓扑
您可以通过从 information_schema.replica_host_status
表中进行选择来描述多主集群拓扑。多主集群与单主集群的区别如下:
-
has_primary
列标识节点的角色。对于多主集群中所有处理 DDL 和 DCL 语句的数据库实例,此值为 True。Aurora 会将此类请求转发给多主集群中的某个数据库实例。 -
replica_lag_in_milliseconds
列报告所有数据库实例的复制滞后。 -
last_reported_status
列报告数据库实例的状态。它可以是Online
、Recovery
或Offline
。
下面是一个示例。
mysql> select server_id, has_primary, replica_lag_in_milliseconds, last_reported_status -> from information_schema.replica_host_status; +----------------------+-------------+-----------------------------+----------------------+ | server_id | has_primary | replica_lag_in_milliseconds | last_reported_status | +----------------------+------------------+------------------------+----------------------+ | mmr-demo-test-mm-3-1 | true | 37.302 | Online | | mmr-demo-test-mm-3-2 | false | 39.907 | Online | +----------------------+-------------+-----------------------------+----------------------+
使用实例只读模式
在 Aurora 多主集群中,通常会向特定的数据库实例发出 SELECT
语句,该实例对关联的表执行写操作。这样做可以避免因复制滞后导致的一致性问题,并最大程度地重用缓冲池中的表和索引数据。
如果需要跨多个表运行查询密集型工作负载,则可将多主集群中的一个或多个数据库实例指定为只读。
要在运行时将整个数据库实例置于只读模式中,请调用 mysql.rds_set_read_only
存储过程。
mysql> select @@read_only; +-------------+ | @@read_only | +-------------+ | 0 | +-------------+ 1 row in set (0.00 sec) mysql> call mysql.rds_set_read_only(1); Query OK, 0 rows affected (0.00 sec) mysql> select @@read_only; +-------------+ | @@read_only | +-------------+ | 1 | +-------------+ 1 row in set (0.00 sec) mysql> call mysql.rds_set_read_only(0); Query OK, 0 rows affected (0.00 sec) mysql> select @@read_only; +-------------+ | @@read_only | +-------------+ | 0 | +-------------+ 1 row in set (0.00 sec)
调用此存储过程等同于运行 SET GLOBAL read_only = 0|1
。该设置仅为运行时设置,且不能在引擎重启后继续运行。通过在数据库实例的参数组中将 read_only
参数设置为 true
,可以将数据库实例永久设置为只读。
Aurora 多主集群的性能注意事项
对于单主集群和多主集群,Aurora 引擎已针对 OLTP 工作负载进行优化。OLTP 应用程序主要由具有高选择性、随机访问查询的短期事务组成。借助同时运行许多此类操作的工作负载,您可以从 Aurora 获得最大优势。
避免始终以 100% 的利用率运行。这样做可让 Aurora 跟上内部维护工作。要了解如何测量多主集群的繁忙程度以及需要的维护工作量,请参阅 监控 Aurora 多主集群。
多主集群的查询性能
多主集群不提供专用的只读节点或只读 DNS 终端节点,但可以创建只读数据库实例组并将其用于预期目的。有关更多信息,请参阅“使用实例只读模式”。
您可以使用以下方法来优化多主集群的查询性能:
-
对数据库实例执行
SELECT
语句,该语句处理包含查询中涉及的关联表、数据库或其他架构对象的分片。此技术能够最大程度地重用缓冲池中的数据。它还可避免在多个数据库实例上缓存相同的数据。有关此技术的更多详细信息,请参阅 优化缓冲池和词典缓存使用。 -
如果需要读/写工作负载隔离,请将一个或多个数据库实例指定为只读,如使用实例只读模式中所述。您可以通过连接到相应的实例终端节点,或通过定义与所有只读实例关联的自定义终端节点,将只读会话定向到这些数据库实例。
-
跨所有数据库实例分布只读查询。此方法的效率最低。在可行的情况下使用其他方法之一,特别是当您从开发和测试阶段转向生产阶段时。
多主集群的冲突解决
多主集群的许多最佳实践都侧重于降低发生写冲突的可能性。解决写冲突涉及到网络开销。您的应用程序还必须处理错误情况并重试事务。如果可能,请尝试最大程度地减少这些不必要的后果:
-
在可行的情况下,使用相同的数据库实例对特定表及其关联索引进行所有更改。如果仅有一个数据库实例修改了数据页面,则更改该页面不会触发任何写冲突。此访问模式在分片或多租户数据库部署中很常见。因此,将此类部署切换到使用多主集群相对轻松。
-
多主集群没有读取器终端节点。读取器终端节点对传入连接进行负载平衡,使您无需知道哪个数据库实例正在处理特定的连接。在多主集群中,管理连接需要知道每个连接使用哪个数据库实例。这样一来,对特定数据库或表的修改始终可以路由到相同的数据库实例。
-
少量数据(一个 16 KB 页面)的写冲突可能会触发大量工作以回滚整个事务。因此,理想情况下,您应保持多主集群的事务相对简短。OLTP 应用程序的此最佳实践对于 Aurora 多主集群特别重要。
在页面级别检测冲突。由于来自不同的数据库实例的建议更改会修改页面中的不同行,因此可能会发生冲突。系统中引入的所有页面更改都将进行冲突检测。无论源是用户事务还是服务器后台进程,此规则都将适用。无论数据页是来自表、二级索引、撤消空间等,此规则也将适用。
您可以划分写操作,以便每个数据库实例处理一组架构对象的所有写操作。在此情况下,每个数据页面的所有更改都由一个特定实例进行。
优化缓冲池和词典缓存使用
多主集群中的每个数据库实例都维护单独的内存缓冲区和缓存,例如缓冲池、表处理程序缓存和表词典缓存。对于每个数据库实例,缓冲区和缓存的内容和周转量取决于该实例处理的 SQL 语句。
有效使用内存可帮助提高多主集群的性能并降低 I/O 成本。使用分片设计可物理分隔数据并从特定数据库实例对每个分片进行写入。这样做可在每个数据库实例上最有效地使用缓冲区缓存。尝试将表的 SELECT
语句分配给执行该表的写操作的同一数据库实例。这样做可帮助这些查询在该数据库实例上重用缓存数据。如果您有大量表或分区,则此技术还会减少每个数据库实例在内存中保留的唯一表处理程序和词典对象的数量。
Aurora 多主集群的方法
在以下部分中,您可以找到适用于多主集群的特定部署的方法。这些方法涉及划分工作负载的方式,以便数据库实例对不重叠的数据部分执行写操作。这样做可最大程度地降低发生写入冲突的可能性。写冲突是多主集群的性能调优和故障排除的主要焦点。
将多主集群用于分片数据库
分片是一种流行的架构设计,能很好地适用于 Aurora 多主集群。在分片架构中,分配每个数据库实例以更新一组特定的架构对象。这样一来,多个数据库实例可对同一个共享存储卷进行写入,而不会因并发更改而产生冲突。每个数据库实例均可处理多个分片的写操作。您可以通过更新应用程序配置来随时更改数据库实例到分片的映射。执行此操作时,您无需重新组织数据库存储或重新配置数据库实例。
使用分片架构设计的应用程序非常适合与 Aurora 多主集群一起使用。数据在分片系统中的物理划分方式有助于避免写冲突。您将每个分片映射到架构对象,例如分区、表或数据库。您的应用程序将特定分片的所有写操作定向到相应的数据库实例。
自带分片 (BYOS) 描述了一个使用案例,其中您已拥有分片/分区数据库和能够访问该数据库的应用程序。分片在物理上已经是分离的。因此,您可以轻松地将工作负载移至 Aurora 多主集群,而无需更改架构设计。相同的简单迁移路径适用于多租户数据库,其中每个租户使用一个专用表、一组表或整个数据库。
您可以将分片或租户以一对一或多对一的方式映射到数据库实例。每个数据库实例处理一个或多个分片。分片设计主要适用于写操作。您可以从具有相同性能的任何数据库实例发出对任何分片的 SELECT
查询。
假设您将多主集群用于分片游戏应用程序。您可以分发工作,以便特定的数据库实例执行数据库更新,这具体取决于玩家的用户名。您的应用程序会处理将每个播放器映射到相应的数据库实例并连接到该实例的终端节点的逻辑。每个数据库实例均可处理多个不同分片的写操作。您可以向任何数据库实例提交查询,因为只有在写操作期间才会发生冲突。您可以指定一个数据库实例来执行所有 SELECT
查询,以最大限度地减少执行写入操作的数据库实例的开销。
假设随着时间的推移,其中一个分片变得更加活跃。要重新平衡工作负载,可以切换负责该分片的数据库实例。在非 Aurora 系统中,您可能必须将数据物理移至其他服务器。利用 Aurora 多主集群,您可以通过将分片的所有写操作定向到具有未使用计算容量的其他数据库实例来重新进行此类分片。Aurora 共享存储模型避免了物理重新组织数据的需要。
使用不带分片的多主集群
如果架构设计未将数据细分为物理上独立的容器(例如数据库、表或分区),您仍可以在多主集群的数据库实例中分割 DML 语句之类的写操作。
您可能会看到一些性能开销,并且当写冲突被视为死锁条件时,您的应用程序可能必须处理偶尔的事务回滚。在对小型表执行写操作期间,更有可能发生写冲突。如果表包含很少的数据页,则主键范围的各个部分中的行可能位于同一数据页中。如果这些行由不同的数据库实例同时更改,则此重叠可能会导致写冲突。
在此情况下,您还应最大程度地减少二级索引的数量。在对表中的索引列进行更改时,Aurora 会在关联的二级索引中进行相应的更改。由于二级索引和关联表之间的行的顺序和分组不同,因此,更改索引可能会导致发生写冲突。
由于您在使用此技术时可能仍会遇到一些写冲突,因此 Amazon 建议您使用其他方法(如果可行)。查看您是否能使用将数据细分为不同架构对象的备用数据库设计。
将多主集群用作活动备用
活动备用 是与另一个数据库实例保持同步的数据库实例,可以很快地接管它。此配置有助于在单个数据库实例可以处理完整工作负载的情况下实现高可用性。
通过将所有流量(读/写和只读流量)定向到单个数据库实例,可以在活动的备用配置中使用多主集群。如果该数据库实例变得不可用,则应用程序必须检测问题并将所有连接切换到其他数据库实例。在此情况下,Aurora 不执行任何故障转移,因为其他数据库实例已可用于接受读/写连接。通过一次只对一个数据库实例进行写入,可以避免写冲突。因此,您无需使用分片数据库架构来以该方式使用多主集群。
如果您的应用程序可以容忍短暂的暂停,则可在数据库实例变得不可用之后等待几秒钟,然后再将写流量重定向到另一个实例。当一个实例因重启而变得不可用时,它会在约 10 至 20 秒后再次可用。如果实例无法快速重新启动,则 Aurora 可能会为该实例启动恢复。在关闭实例时,它会在关闭过程中执行一些额外的清理活动。如果在实例重新启动、正在恢复或关闭时开始对其他实例进行写入,则可能会遇到写冲突。新实例上的 SQL 语句与重新启动或关闭的实例上的恢复操作(例如回滚和清除)之间可能会发生冲突。