Amazon Relational Database Service
用户指南 (API Version 2014-10-31)
AWS 服务或AWS文档中描述的功能,可能因地区/位置而异。请点击 Amazon AWS 入门,可查看中国地区的具体差异

预览版 - 兼容 PostgreSQL 的 Amazon Aurora

Amazon Relational Database Service (Amazon RDS) 正在提供 Aurora (PostgreSQL) 预览版,即兼容 PostgreSQL 的 Amazon Aurora。Aurora 是一种完全托管的、兼容 PostgreSQL 和 MySQL 的关系数据库引擎。它结合了高端商用数据库的速度和可靠性,同时还具有开源数据库的简单性和成本效益。有关 Aurora 的完整概述,请参阅 Amazon Aurora 概述

Aurora (PostgreSQL) 是 PostgreSQL 的简易替代。您用于现有 PostgreSQL 数据库的代码、工具和应用程序均可用于 Aurora (PostgreSQL)。

要注册 Aurora (PostgreSQL),请转到预览注册链接: https://pages.awscloud.com/amazon-aurora-with-postgresql-compatibility-preview-form.html。注册后,您即可访问沙盒式 AWS 区域,在其中创建您的预览 Aurora (PostgreSQL) 实例。在预览期内,您的预览数据库实例或预览数据库使用的存储免费。

Aurora (PostgreSQL) 预览版具有以下限制:

  • 预览计划期间,对可用性或正常运行不做承诺。

  • 预览版与 PostgreSQL 9.6.2 兼容。

  • 预览版目前支持以下数据库实例类:db.r3.8xlarge、db.r4.4xlarge、db.r4.8xlarge 和 db.r4.16xlarge。

  • 每个账户最多可创建三个实例。

  • 现已支持读取节点。

  • 尚不支持两阶段提交。

  • PostgreSQL 9.6.2 目前支持的所有扩展预览版均支持,无一例外。

  • 与 Amazon EC2 上使用 Amazon EBS 卷的 PostgreSQL 相比,您的性能会快一到二倍。

在预览阶段不支持某些 Amazon Aurora 功能,但 Aurora (PostgreSQL) 公开发布后就会支持这些功能。这些功能包括:

  • “自动恢复”缓存预热

  • 从 Amazon RDS for PostgreSQL 数据库实例导入数据库快照

创建 Aurora (PostgreSQL) 数据库群集

Aurora (PostgreSQL) 数据库群集由可与 PostgreSQL 兼容的实例和一个群集卷组成,该群集卷将跨三个可用区复制的数据表示为一个单一虚拟卷。数据库群集包含两类实例:主实例Aurora 副本

主实例执行针对数据库群集的所有数据修改,还支持读取工作负载。每个数据库群集均有一个主实例。Aurora 副本仅支持读取工作负载。每个数据库实例可拥有最多 15 个 Aurora 副本。可使用终端节点地址连接到数据库群集中的任何实例。

您可通过以下内容了解如何创建 Aurora (PostgreSQL) 数据库群集,以及如何为该数据库群集添加 Aurora 副本。必须先完成设置 Amazon RDS 部分的任务,然后才能创建数据库群集。

以下说明介绍的是如何使用 AWS 管理控制台创建 Aurora (PostgreSQL) 数据库群集。有关连接到 Aurora 数据库群集的简单说明,请参阅连接到 Amazon Aurora 数据库群集。有关连接到 Aurora (PostgreSQL) 数据库群集的详细指南,请参阅 RDS Aurora 连接

数据库群集先决条件

以下是创建数据库群集的先决条件。

VPC

只能在 Amazon Virtual Private Cloud (Amazon VPC) 中创建 Aurora (PostgreSQL) 数据库群集,该群集在至少两个可用区中包含至少两个子网。通过跨至少两个可用区分配您的群集实例,您可以确保数据库群集中有可用的实例,避免出现可用区故障。Aurora 数据库群集的群集卷将始终跨三个可用区提供持久性存储,数据丢失的可能性很小。

如果您要使用 Amazon RDS 控制台创建 Aurora (PostgreSQL) 数据库群集,则 Amazon RDS 可自动为您创建 VPC。或者,您也可以使用现有 VPC 或为 Aurora 数据库群集创建新的 VPC。您的 VPC 必须具有至少两个子网,才能与 Aurora (PostgreSQL) 数据库群集配合使用。有关更多信息,请参阅 如何创建 VPC 以用于 Amazon Aurora。有关 VPC 的信息,请参阅 Amazon Virtual Private Cloud (VPCs) 和 Amazon RDS

注意

可使用 ClassicLink 与不在 VPC 中的 EC2 实例和 Amazon Aurora 数据库群集进行通信。有关更多信息,请参阅 VPC 中的数据库实例由不在 VPC 中的 EC2 实例访问

如果您没有默认 VPC 或尚未创建 VPC,在您使用 RDS 控制台创建 Aurora (PostgreSQL) 数据库群集时,Amazon RDS 可自动为您创建 VPC。否则,您必须执行以下操作:

  • 创建一个 VPC,该 VPC 具有至少两个子网,这两个子网位于至少两个可用区内。

  • 指定授权与您的 Aurora 数据库群集的连接的 VPC 安全组。有关信息,请参阅 在 VPC 中使用数据库实例

  • 指定 RDS 数据库子网组,该子网组在 VPC 中定义至少两个可由 Aurora 数据库群集使用的子网。有关信息,请参阅Amazon Virtual Private Cloud (VPCs) 和 Amazon RDS中的使用数据库子网组一节。

其他先决条件

  • 如果使用 AWS Identity and Access Management (IAM) 证书连接到 AWS,您的 IAM 账户必须拥有 IAM 策略来授予执行 Amazon RDS 操作所需的权限。有关更多信息,请参阅 Amazon RDS 的身份验证和访问控制

    如果要使用 IAM 账户访问 Amazon Aurora 控制台,必须先使用您的 IAM 账户登录 AWS 管理控制台。然后您可以转到 Amazon RDS 控制台链接 (注册预览版时获得)。

  • 若要定制您的数据库群集的配置参数,必须通过必需的参数设置来指定数据库参数组。有关创建或修改数据库参数组的信息,请参阅 使用数据库参数组

  • 您必须确定要为数据库群集指定的 TCP/IP 端口号。有些公司的防火墙不允许连接到默认的 Aurora (PostgreSQL) 端口 (5432)。如果您公司的防火墙阻止不允许连接该默认端口,请为您的数据库群集选择其他端口。数据库群集中的所有实例都使用相同端口。

使用 AWS 管理控制台启动 Aurora (PostgreSQL) 数据库群集并创建 Aurora 副本

启动 Aurora 数据库群集

以下过程介绍如何使用 AWS 管理控制台启动 Aurora (PostgreSQL) 数据库群集,以及如何在预览期间创建 Aurora 副本。

使用控制台启动 Aurora (PostgreSQL) 数据库群集

  1. 打开 Amazon RDS 控制台链接 (注册预览版时获得)。选择 Get Started Now

  2. 在 AWS 管理控制台的右上角,选择要在其中创建数据库群集的区域。

  3. 在导航窗格中,选择 Instances

  4. 选择 Launch DB Instance 以启动 Launch DB Instance Wizard。向导在 Select Engine 页面上打开。

  5. Select Engine 页面上,选择 Aurora (PostgreSQL) 数据库引擎对应的 Select

  6. Specify DB Details 页面上,指定数据库群集信息。下表显示的是 Aurora (PostgreSQL) 数据库实例的设置。

    对于此选项 请执行此操作

    数据库实例类

    选择定义数据库群集中每个实例的处理和内存要求的数据库实例类。对于此预览版,Amazon (PostgreSQL) 支持 db.r4.4xlarge、db.r4.8xlarge、db.r4.16xlarge 和 db.r3.8xlarge 数据库实例类。有关数据库实例类选项的更多信息,请参阅数据库实例类

    Multi-AZ Deployment

    确定是否要在其他可用区中创建 Aurora 副本以实现故障转移支持。如果您选择 Create Replica in Different Zone,Amazon RDS 将在其他可用区中为您创建 Aurora 副本,而不是在数据库群集的主实例中创建。

    有关多可用区的详细信息,请参阅区域和可用区

    DB Instance Identifier

    键入数据库群集中主实例的名称。此标识符在您的数据库群集主实例的终端节点地址中使用。

    数据库实例标识符具有以下限制:

    • 它必须包含 1 到 63 个字母数字字符或连字符。

    • 它的第一个字符必须是字母。

    • 它不能以连字符结束或包含两个连续连字符。

    • 在一个区域中,它对于每个 AWS 账户的所有数据库实例必须是唯一的。

    Master Username

    使用字母数字字符键入一个名称,该名称将用作您登录数据库群集的主用户名。

    Master Password

    键入一个包含 8 到 41 位可打印 ASCII 字符 (的密码用不包括 /、"、和 @) 用作您的主用户密码。

  7. 选择 Next

  8. Configure Advanced Settings 页面上,您可以自定义 Aurora (PostgreSQL) 数据库群集的其他设置。下表显示数据库群集的高级设置。

    对于此选项 请执行此操作

    VPC

    选择将托管数据库群集的 VPC。选择 Create a New VPC 以让 Amazon RDS 为您创建 VPC。有关更多信息,请参阅本主题前面的数据库群集先决条件

    子网组

    选择要用于数据库群集的数据库子网组。选择 Create a New DB Subnet Group 以让 Amazon RDS 为您创建数据库子网组。有关更多信息,请参阅本主题前面的数据库群集先决条件

    公开访问

    选择 Yes 可向数据库群集提供公有 IP 地址;否则,请选择 No。数据库群集可以混合使用公有和私有数据库实例。有关隐藏实例以防止公开访问的更多信息,请参阅从 Internet 隐藏 VPC 中的数据库实例

    可用区

    确定您是否希望指定特定的可用区。有关可用区的更多信息,请参阅区域和可用区

    VPC 安全组

    选择一个或多个 VPC 安全组以保护对数据库群集的网络访问。选择 Create a New VPC Security Group 以让 Amazon RDS 为您创建 VPC 安全组。有关更多信息,请参阅本主题前面的数据库群集先决条件

    DB Cluster Identifier

    为数据库群集键入一个名称,该名称在您选择的区域中对于您的账户是唯一的。此标识符在数据库群集的群集终端节点地址中使用。有关群集终端节点的信息,请参阅 Aurora 终端节点

    数据库群集标识符具有以下限制:

    • 它必须包含 1 到 63 个字母数字字符或连字符。

    • 它的第一个字符必须是字母。

    • 它不能以连字符结束或包含两个连续连字符。

    • 它对于每个区域的每个 AWS 账户的所有数据库群集必须是唯一的。

    Database Name

    为您的默认数据库键入一个包含多达 8 位字母数字字符的名称。如果您未提供名称,Amazon RDS 将不会在您创建的数据库群集上创建数据库。

    要创建其他数据库,请连接到数据库群集并使用 SQL 命令 CREATE DATABASE。有关连接到数据库群集的更多信息,请参阅连接到 Amazon Aurora 数据库群集

    Database Port

    指定应用程序和实用程序用来访问数据库的端口。Aurora (PostgreSQL) 数据库群集默认为使用默认 PostgreSQL 端口 5432。有些公司的防火墙不允许连接到默认的 PostgreSQL 端口。如果您公司的防火墙不允许连接默认端口,请为新数据库群集选择其他端口。

    参数组

    选择参数组。Aurora 具有一个可使用的默认参数组,或者您也可以创建自己的参数组。有关参数组的更多信息,请参阅 使用数据库参数组

    选项组

    选择选项组。Aurora 具有一个可使用的默认选项组,或者您也可以创建自己的选项组。有关选项组的更多信息,请参阅 使用选项组

    启用加密

    此预览版选择 No。有关更多信息,请参阅 加密 Amazon RDS 资源

    优先级

    选择实例的故障转移优先级。如果您未选择值,则默认值为 tier-1。此优先级决定从主实例故障恢复时提升 Aurora 副本的顺序。有关更多信息,请参阅 Aurora 数据库群集的容错能力

    备份保留期

    选择 Aurora 将保留数据库的备份副本的时间长度 (1 到 35 天)。可使用备份副本对数据库执行时间点还原 (PITR),以还原到第二个时间点。

    Enable Enhanced Monitoring

    选择 Yes 可实时收集您的数据库群集在其上运行的操作系统的指标。有关更多信息,请参阅 增强监控

    粒度

    仅当 Enable Enhanced Monitoring 设置为 Yes 时可用。设置为数据库群集收集指标的时间之间的间隔 (以秒为单位)。

    Auto Minor Version Upgrade

    此预览版选择 No

    Maintenance Window

    选择可以进行系统维护的每周时间范围。

  9. 选择 Launch DB Instance 启动您的 Aurora (PostgreSQL) 数据库实例,然后选择 Close 关闭该向导。

    在 Amazon RDS 控制台中,新数据库实例显示在数据库实例列表中。数据库实例具有 creating 状态,直到该数据库实例完成创建并可供使用。当状态更改为 available 时,您可连接到数据库群集的主实例。根据所分配的数据库实例类和存储的不同,新实例可能需要数分钟时间才能变得可用。

    要查看新创建的群集,请选择 Amazon RDS 控制台中的 Clusters 视图。有关更多信息,请参阅 查看 Amazon Aurora 数据库群集

     Amazon Aurora 数据库实例列表

    记下群集的端口和终端节点。在您的执行写入或读取操作的任何应用程序的 JDBC 和 ODBC 连接字符串中,使用群集的终端节点和端口。

使用控制台创建 Aurora 副本

创建 Aurora 数据库群集的主实例之后,可通过使用 Create Aurora Replica 向导添加最多 15 个 Aurora 副本。

使用 AWS 管理控制台创建 Aurora 副本

  1. 打开 Amazon RDS 控制台链接 (注册预览版时获得)。

  2. 在左侧导航窗格中,选择 Instances

  3. 选中 Aurora 数据库群集主实例左侧的复选框。

  4. 选择 Instance Actions,然后选择 Create Aurora Replica

  5. Create Aurora Replica 页面上,指定 Aurora 副本的选项。下表显示 Aurora 副本的设置。

    对于此选项 请执行此操作

    数据库实例类

    选择定义 Aurora 副本的处理和内存要求的数据库实例类。对于预览版,Aurora (PostgreSQL) 支持 db.r4.4xlarge、db.r4.8xlarge、db.r4.16xlarge 和 db.r3.8xlarge 数据库实例类。有关数据库实例类选项的更多信息,请参阅数据库实例类

    Aurora 副本源

    选择要为其创建 Aurora 副本的主实例的标识符。

    DB Instance Identifier

    为该实例键入一个名称,该名称在您所选区域中对于您的账户是唯一的。您可选择对该名称进行一些巧妙处理,例如将您所选的区域和数据库引擎包括在名称中,例如 aurora-read-instance1

    公开访问

    选择 Yes 可向 Aurora 副本提供公有 IP 地址;否则,请选择 No。有关隐藏 Aurora 副本以防止公开访问的更多信息,请参阅从 Internet 隐藏 VPC 中的数据库实例

    可用区

    确定您是否希望指定特定的可用区。该列表仅包括那些由您之前指定的数据库子网组映射的可用区。有关可用区的更多信息,请参阅区域和可用区

    优先级

    选择实例的故障转移优先级。如果您未选择值,则默认值为 tier-1。此优先级决定从主实例故障恢复时提升 Aurora 副本的顺序。有关更多信息,请参阅 Aurora 数据库群集的容错能力

    Database Port

    Aurora 副本的端口与数据库群集的端口相同。

    Auto Minor Version Upgrade

    此预览版选择 No

  6. 选择 Create Aurora Replica 创建 Aurora 副本。

记下 Aurora 副本的终端节点。在您的执行只读操作的任何应用程序的 JDBC 和 ODBC 连接字符串中,使用 Aurora 副本的终端节点。

连接到 Amazon Aurora 数据库群集

您可使用用于连接 PostgreSQL 数据库的工具来连接 Aurora 数据库实例。在连接过程中,您使用相同的公有密钥进行安全套接字层 (SSL) 连接。可以在连接到 PostgreSQL 数据库实例的任何脚本、实用程序或应用程序的连接字符串中,使用 Amazon Aurora 数据库群集中的主实例或 Aurora 副本的终端节点和端口信息。在连接字符串中,指定主实例或 Aurora 副本终端节点中的 DNS 地址作为主机参数,并指定该终端节点中的端口号作为端口参数。

连接到 Amazon Aurora 数据库群集之后,您便可以运行与 PostgreSQL 版本 9.6.2 兼容的任何 SQL 命令。

有关连接到 Amazon Aurora 数据库群集的辅助详细指南,请参阅 RDS Aurora 连接

您可以在数据库群集详细信息视图中找到群集终端节点。请在您的 PostgreSQL 连接字符串中使用这个终端节点。该终端节点由数据库群集的域名和端口组成。例如,如果终端节点值为 mycluster.cluster-123456789012.us-east-1.rds.amazonaws.com:3306,则需要在 PostgreSQL 连接字符串中指定以下值:

  • 对于主机或主机名,请指定 mycluster.cluster-123456789012.us-east-1.rds.amazonaws.com

  • 对于端口,指定 5432 或在创建数据库群集时使用的端口值。

群集终端节点将您连接到数据库群集的主实例。可使用群集终端节点执行读取和写入操作。数据库群集还可以具有最多 15 个 Aurora 副本,这些副本支持对数据库群集中的数据进行只读访问。主实例和每个 Aurora 副本分别具有唯一的终端节点,该终端节点独立于群集终端节点。这个唯一的终端节点允许您与群集中特定的数据库实例直接连接。群集终端节点始终指向主实例。如果主实例发生故障并被替换,群集终端节点将指向新的主实例。

 Amazon Aurora 启动数据库实例向导创建 Aurora 副本数据库实例

修复 Aurora (PostgreSQL) 连接故障

注意

有关连接到 Amazon Aurora 数据库群集的辅助详细指南,请参阅 RDS Aurora 连接

导致新 Aurora 数据库群集连接故障的常见原因如下所示:

  • 创建数据库群集所用的 VPC 不允许从您的设备进行连接。要修复此故障,请修改 VPC 以允许从您的设备进行连接,或者创建允许从您的设备进行连接的数据库群集的新 VPC。有关示例,请参阅创建 VPC 和子网

  • 您公司的防火墙规则不允许公司网络中的设备连接到创建数据库群集所用的端口值。要修复此故障,请重新创建使用不同端口的实例。

Aurora (PostgreSQL) 快速故障转移最佳实践

通过 Aurora (PostgreSQL) 有几个方法可以更快地进行故障转移。本部分将具体讨论以下每个方法:

  • 主动设置 TCP keepalive,确保运行时间较长、等待服务器响应的查询在发生故障的情况下在读取超时到期之前被终止。

  • 主动设置 Java DNS 缓存超时,确保 Aurora 只读终端节点能够在后续的连接尝试中在只读节点之间进行正常的循环切换。

  • 将在 JDBC 连接字符串中使用的超时变量设置得尽可能低。对短时间和长时间运行的查询使用不同的连接对象。

  • 使用提供的读取和写入 Aurora 终端节点建立到群集的连接。

  • 使用 RDS API 测试在服务器端发生故障时的应用程序响应,使用丢包工具测试在客户端发生故障时的应用程序响应。

设置 TCP keepalive 参数

TCP keepalive 过程很简单:在设置 TCP 连接时,会关联一组定时器。当 keepalive 定时器计时到零,则发送一个 keepalive 探测数据包。如果收到 keepalive 探测的回复,则可认为连接仍在正常运行。

启用并主动设置 TCP keepalive 参数,可确保在客户端不再能够连接到数据库时,任何活动连接都能很快关闭。此操作使应用程序能够做出恰当的反应,例如选择要连接的新主机。

应设置以下 TCP keepalive 参数:

  • tcp_keepalive_time 控制一个以秒为单位的时间,如果套接字未发送数据 (ACK 不视为数据) 的时间达到此时间段,则发送 keepalive 数据包。建议进行以下设置:

    tcp_keepalive_time = 1

  • tcp_keepalive_intvl 控制发送第一个数据包后到发送后续 keepalive 数据包之间的时间,以秒为单位 (使用 tcp_keepalive_time 参数设置)。建议进行以下设置:

    tcp_keepalive_intvl = 1

  • tcp_keepalive_probes 是在应用程序收到通知之前未获确认的 keepalive 探测包的数量。建议进行以下设置:

    tcp_keepalive_probes = 5

这些设置应在数据库停止响应的五秒内通知应用程序。如果在应用程序的网络中经常出现 keepalive 数据包丢包,则可以将 tcp_keepalive_probes 值设置得较大。将 tcp_keepalive_probes 值设置得较大将增加检测实际故障所花费的时间,但有助于在可靠度不佳的网络中减少不必要的故障转移。

在 Linux 上设置 TCP keepalive

  1. 在测试如何配置 TCP keepalive 参数时,建议在命令行中使用以下命令。请注意,此建议配置是针对整个系统的,这就是说,会影响在 SO_KEEPALIVE 选项打开的情况下创建套接字的所有其他应用程序。

    Copy
    sudo sysctl net.ipv4.tcp_keepalive_time=1 sudo sysctl net.ipv4.tcp_keepalive_intvl=1 sudo sysctl net.ipv4.tcp_keepalive_probes=5
  2. 找到对应用程序有效的配置后,必须通过在 /etc/sysctl.conf 中添加以下行 (包括所做的任何更改) 来保留这些设置:

    Copy
    tcp_keepalive_time = 1 tcp_keepalive_intvl = 1 tcp_keepalive_probes = 5

有关在 Windows 上设置 TCP keepalive 参数的信息,请参阅 Things You May Want to Know About TCP Keepalive

配置应用程序以实现快速故障转移

本部分介绍您可进行的几项特定于 Aurora (PostgreSQL) 的配置更改。PostgreSQL JDBC 网站提供了有关 JDBC 驱动程序的常规设置和配置的文档。

减少 DNS 缓存超时

当应用程序尝试在故障转移后建立连接时,将从群集中的一个只读实例中选择新 Aurora (PostgreSQL) 主 (读写) 实例。所选的新主实例可使用 Aurora 读取终端节点在完全传播 DNS 更新之前找到。将 Java DNS TTL 设置为较小的值有助于在后续连接尝试时在读取节点之间进行循环切换。

Copy
// Sets internal TTL to match the Aurora RO Endpoint TTL java.security.Security.setProperty("networkaddress.cache.ttl" , "1"); // If the lookup fails, default to something like small to retry java.security.Security.setProperty("networkaddress.cache.negative.ttl" , "3");

设置 Aurora (PostgreSQL) 连接字符串以实现快速故障转移

要利用 Aurora (PostgreSQL) 快速故障转移,应用程序的连接字符串应有多个主机 (在下例中以粗体突出显示) 而不是单个主机。下面是可用来连接 Aurora (PostgreSQL) 群集的连接字符串示例:

Copy
jdbc:postgresql://myauroracluster.cluster-c9bfei4hjlrd.us-east-1-beta.rds.amazonaws.com:5432, myauroracluster.cluster-ro-c9bfei4hjlrd.us-east-1-beta.rds.amazonaws.com:5432 /postgres?user=<masteruser>&password=<masterpw>&loginTimeout=2 &connectTimeout=2&cancelSignalTimeout=2&socketTimeout=60 &tcpKeepAlive=true&targetServerType=master&loadBalanceHosts=true

为获得最佳可用性并避免对 RDS API 的依赖,最好的连接选择是保留一个包含主机字符串的文件,在建立与数据库的连接时,应用程序从该字符串进行读取。此主机字符串将包含群集可用的所有 Aurora 终端节点。有关 Aurora 终端节点的更多信息,请参阅 Aurora 终端节点。例如,您可以在本地的一个文件中存储终端节点,如下所示:

Copy
myauroracluster.cluster-c9bfei4hjlrd.us-east-1-beta.rds.amazonaws.com:5432, myauroracluster.cluster-ro-c9bfei4hjlrd.us-east-1-beta.rds.amazonaws.com:5432

应用程序从该文件进行读取,以填充 JDBC 连接字符串的主机部分。重命名数据库群集将导致这些终端节点更改;确保应用程序能够在发生此事件时进行处理。

另一个选择是使用一系列数据库实例节点:

Copy
my-node1.cksc6xlmwcyw.us-east-1-beta.rds.amazonaws.com:5432, my-node2.cksc6xlmwcyw.us-east-1-beta.rds.amazonaws.com:5432, my-node3.cksc6xlmwcyw.us-east-1-beta.rds.amazonaws.com:5432, my-node4.cksc6xlmwcyw.us-east-1-beta.rds.amazonaws.com:5432

这种方法的优点是 PostgreSQL JDBC 连接驱动程序将在此列表中的所有节点中循环查找有效连接,但是当使用 Aurora 终端节点时,每次连接尝试将仅尝试两个节点。使用数据库实例节点的缺点是,如果对群集添加或删除节点,则实例终端节点列表就变得陈旧,连接驱动程序可能永远找不到应该连接的主机。

主动设置以下参数有助于确保应用程序不用等太长时间就能连接任意一台主机。

  • loginTimeout - 控制应用程序在建立套接字连接之后 等待多长时间才能登录到数据库。

  • connectTimeout - 控制套接字等待多长时间才能与数据库建立连接。

还可以修改其他应用程序参数,以加速连接过程,具体取决于应用程序需要多快建立连接。

  • cancelSignalTimeout - 在某些应用程序中,可能需要对已经超时的查询发送“尽力”取消信号。如果此取消信号在故障转移路径中,则应该考虑主动设置它,以免将此信号发送给已停止运行的主机。

  • socketTimeout - 此参数控制套接字在执行读取操作之前等待多长时间。此参数可用作全局“查询超时”,以确保任何查询等待的时间都不会超过此值。一种好方法是,采用两个连接处理程序,一个运行短时间存在的查询并将此值设置得较小,另一个处理长时间运行的查询并将此值设置得较大。这样,如果服务器出现故障,可以由 TCP keepalive 参数来终止长时间运行的查询。

  • tcpKeepAlive - 启用此参数可确保所设置的 TCP keepalive 参数有效。

  • targetServerType- 此参数可用于控制驱动程序是连接到读取 (从) 还是写入 (主) 节点。可能的值为:anymasterslave preferSlave。如果设置为 preferSlave 值,将首先尝试与读取节点建立连接,如果无法与读取节点建立连接,则转而连接写入节点。

  • loadBalanceHosts - 如果设置为 true,则此参数让应用程序连接到从候选主机列表中随机选择的主机。

用于获取主机字符串的其他选项

可以从多个源 (包括 replica_host_status 表) 以及通过使用 Amazon RDS API 获取主机字符串。

应用程序可以连接数据库群集中的任意数据库实例,可以查询 replica_host_status 表以确定群集的写入节点,也可以查找群集中的其他读取节点。使用此状态表可以减少查找要连接的主机所需的时间,但是,在发生特定网络故障的情况下,replica_host_status 表可能显示过时或不完整的信息。

要确保应用程序找到要连接的节点,一个好办法是尝试连接群集写入终端节点,然后连接群集读取终端节点,直至能够建立一个可读取的连接。除非重命名数据库群集,否则这些终端节点不会发生更改,这样,一般情况下会保留为应用程序的静态成员,或存储在应用程序会读取的资源文件中。

在使用其中一个终端节点建立连接之后,可以查询状态表获取有关群集中其余节点的信息。例如,以下命令从 replica_host_status 表中检索信息。

Copy
postgres=> select server_id, session_id, vdl, highest_lsn_rcvd, cur_replay_latency, now(), last_update_time from replica_host_status; server_id | session_id | vdl | highest_lsn_rcvd | cur_replay_latency | now | last_update_time -----------------------------------+--------------------------- -----------+-----------+------------------+--------------------+- ------------------------------+------- mynode-1 | 3e3c5044-02e2-11e7-b70d-95172646d6ca | 594220999 | 594221001 | 201421 | 2017-03-07 19:50:24.695322+00 | 2017-03-07 19:50:23+00 mynode-2 | 1efdd188-02e4-11e7-becd-f12d7c88a28a | 594220999 | 594221001 | 201350 | 2017-03-07 19:50:24.695322+00 | 2017-03-07 19:50:23+00 mynode-3 | MASTER_SESSION_ID | 594220999 | | | 2017-03-07 19:50:24.695322+00 | 2017-03-07 19:50:23+00 (3 rows)

连接字符串的主机部分可以从群集的写入和读取终端节点开始:

Copy
myauroracluster.cluster-c9bfei4hjlrd.us-east-1-beta.rds.amazonaws.com:5432, myauroracluster.cluster-ro-c9bfei4hjlrd.us-east-1-beta.rds.amazonaws.com:5432

在这种情况下,应用程序将尝试与任意节点类型 (主或从) 建立连接。连接之后,一种好方法是先运行命令 SHOW transaction_read_only 检查节点的读写状态。

如果查询的返回值为 OFF,表示已成功连接到主节点。如果返回值为 ON,并且应用程序需要读写连接,则可以查询 replica_host_status 表以确定 session_id='MASTER_SESSION_ID'server_id。此查询为您提供主节点的名称。您可以将此与下述“endpointPostfix”结合使用。

需要注意当连接数据过时的副本的情况。这时,replica_host_status 表可能显示过时的信息。可以按应用程序级别设置陈旧阈值,通过查看服务器时间与 last_update_time 之间的差异可以检查此阈值。一般来说,应用程序应确保避免由于 replica_host_status 表中的信息冲突而在两个主机之间来回切换。也就是说,应用程序宁可先尝试所有已知主机,而不是盲目遵从 replica_host_status 表的信息。

使用 Amazon RDS API 查找主机字符串

您可以使用 AWS Java 软件开发工具包,特别是 DescribeDbClusters API 以程序方式查找实例列表。下面的小示例介绍如何通过 java 8 实现:

Copy
AmazonRDS client = AmazonRDSClientBuilder.defaultClient(); DescribeDBClustersRequest request = new DescribeDBClustersRequest() .withDBClusterIdentifier(clusterName); DescribeDBClustersResult result = rdsClient.describeDBClusters(request); DBCluster singleClusterResult = result.getDBClusters().get(0); String pgJDBCEndpointStr = singleClusterResult.getDBClusterMembers().stream() .sorted(Comparator.comparing(DBClusterMember::getIsClusterWriter) .reversed()) // This puts the writer at the front of the list .map(m -> m.getDBInstanceIdentifier() + endpointPostfix + ":" + singleClusterResult.getPort())) .collect(Collectors.joining(","));

pgJDBCEndpointStr 将包含终端节点的格式化终端节点列表,如:

Copy
my-node1.cksc6xlmwcyw.us-east-1-beta.rds.amazonaws.com:5432, my-node2.cksc6xlmwcyw.us-east-1-beta.rds.amazonaws.com:5432

变量“endpointPostfix”可以是应用程序设置的常量,也可通过 DescribeDBInstances API 对群集中的单个实例进行查询来获取。此值在一个区域中或对于单个客户将保持常量,因此可省去一次 API 调用,只需将此常量保存在应用程序将读取的资源文件中。在上面的示例中,将其设置为:

Copy
.cksc6xlmwcyw.us-east-1-beta.rds.amazonaws.com

考虑到可用性,如果 API 无响应或响应时间过长,默认使用数据库群集的 Aurora 终端节点是一个好方法。在终端节点更新 DNS 记录所用时间 (通常少于 30 秒) 之内,应确保其最新。这也仍然可以存储在应用程序使用的资源文件中。

测试故障转移

在任何情况下,数据库群集都必须包含不少于两个数据库实例。

在服务器端,某些 API 可以引起中断,您可以利用此中断来测试应用程序的响应情况:

  • FailoverDBCluster - 尝试将数据库群集中的新数据库实例提升为写入实例。

    Copy
    public void causeFailover() { /* * See http://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/basics.html for more details on setting up an RDS client */ final AmazonRDS rdsClient = AmazonRDSClientBuilder.defaultClient(); FailoverDBClusterRequest request = new FailoverDBClusterRequest(); request.setDBClusterIdentifier("cluster-identifier"); rdsClient.failoverDBCluster(request); }
  • RebootDBInstance - 在此 API 中无法保证故障转移。但是,它将在写入实例上关闭数据库,可用于测试应用程序对连接丢失的响应 (请注意,ForceFailover 参数不适用于 Aurora 引擎,应使用 FailoverDBCluster API)。

  • ModifyDBCluster - 修改 Port 将在群集中节点开始侦听新端口时引起中断。一般情况下,如果确保只有应用程序控制端口更改,则应用程序可以响应此故障,通过在 API 级别修改时手动更新端口,或在应用程序中查询 RDS API 以确定端口是否已更改,可以相应地更新它依赖的终端节点。

  • ModifyDBInstance - 修改 DBInstanceClass 会引起中断。

  • DeleteDBInstance - 删除主/写入实例会导致数据库群集中的新数据库实例提升为写入实例。

对应用程序/客户端而言,如果使用的是 Linux,可以测试应用程序对突然发生的丢包情况以及没有使用 iptables 发送或接收 tcp keepalive 数据包时如何基于端口、主机做出响应。

快速故障转移最佳实践示例

以下代码示例演示应用程序如何设置 Aurora (PostgreSQL) 驱动程序管理器。当应用程序需要连接时,它会调用 getConnection(...)。在有些时候,例如找不到写入实例,但 targetServerType 设置为“master”,而调用应用程序直接重试时,对该函数的调用可能无法找到有效主机。这些问题可以用一个连接池程序轻松解决,以免将重试操作推送到应用程序。大多数连接池程序允许指定 JDBC 连接字符串,这样,应用程序可以调用 getJdbcConnectionString(...) 并将它传递到连接池程序以利用 Aurora (PostgreSQL) 上更快的故障转移。

Copy
import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; import java.util.stream.IntStream; import org.joda.time.Duration; public class FastFailoverDriverManager { private static Duration LOGIN_TIMEOUT = Duration.standardSeconds(2); private static Duration CONNECT_TIMEOUT = Duration.standardSeconds(2); private static Duration CANCEL_SIGNAL_TIMEOUT = Duration.standardSeconds(1); private static Duration DEFAULT_SOCKET_TIMEOUT = Duration.standardSeconds(5); public FastFailoverDriverManager() { try { Class.forName("org.postgresql.Driver"); } catch (ClassNotFoundException e) { e.printStackTrace(); } /* * RO endpoint has a TTL of 1s, we should honor that here. Setting this aggressively makes sure that when * the PG JDBC driver creates a new connection, it will resolve a new different RO endpoint on subsequent attempts * (assuming there is > 1 read node in your cluster) */ java.security.Security.setProperty("networkaddress.cache.ttl" , "1"); // If the lookup fails, default to something like small to retry java.security.Security.setProperty("networkaddress.cache.negative.ttl" , "3"); } public Connection getConnection(String targetServerType) throws SQLException { return getConnection(targetServerType, DEFAULT_SOCKET_TIMEOUT); } public Connection getConnection(String targetServerType, Duration queryTimeout) throws SQLException { Connection conn = DriverManager.getConnection(getJdbcConnectionString(targetServerType, queryTimeout)); /* * A good practice is to set socket and statement timeout to be the same thing since both * the client AND server will kill the query at the same time, leaving no running queries * on the backend */ Statement st = conn.createStatement(); st.execute("set statement_timeout to " + queryTimeout.getMillis()); st.close(); return conn; } private static String urlFormat = "jdbc:postgresql://%s" + "/postgres" + "?user=%s" + "&password=%s" + "&loginTimeout=%d" + "&connectTimeout=%d" + "&cancelSignalTimeout=%d" + "&socketTimeout=%d" + "&targetServerType=%s" + "&tcpKeepAlive=true" + "&ssl=true" + "&loadBalanceHosts=true"; public String getJdbcConnectionString(String targetServerType, Duration queryTimeout) { return String.format(urlFormat, getFormattedEndpointList(getLocalEndpointList()), CredentialManager.getUsername(), CredentialManager.getPassword(), LOGIN_TIMEOUT.getStandardSeconds(), CONNECT_TIMEOUT.getStandardSeconds(), CANCEL_SIGNAL_TIMEOUT.getStandardSeconds(), queryTimeout.getStandardSeconds(), targetServerType ); } private List<String> getLocalEndpointList() { /* * As mentioned in the best practices doc, a good idea is to read a local resource file and parse the cluster endpoints. * For illustration purposes, the endpoint list is hardcoded here */ List<String> newEndpointList = new ArrayList<>(); newEndpointList.add("myauroracluster.cluster-c9bfei4hjlrd.us-east-1-beta.rds.amazonaws.com:5432"); newEndpointList.add("myauroracluster.cluster-ro-c9bfei4hjlrd.us-east-1-beta.rds.amazonaws.com:5432"); return newEndpointList; } private static String getFormattedEndpointList(List<String> endpoints) { return IntStream.range(0, endpoints.size()) .mapToObj(i -> endpoints.get(i).toString()) .collect(Collectors.joining(",")); } }