亚马逊AWS官方博客

居安思危 – Amazon Aurora 故障恢复不同JDBC Driver下的时延分析

1.  Aurora failover介绍

Amazon Aurora 是亚马逊云科技自研的一项关系数据库服务,它在提供和开源数据库MySQL、PostgreSQL的完好兼容性同时,也能够提供和商业数据库媲美的性能和可用性。性能方面,Aurora MySQL能够支持到与开源标准MySQL同等配置下五倍的吞吐量,Aurora PostgreSQL能够支持与开源标准PostgreSQL同等配置下三倍的吞吐量的提升。在扩展性的角度,Aurora在存储与计算、横向与纵向方面都进行了功能的增强和创新。

Aurora支持多达128TB的存储容量,而且支持10GB为单位的存储层动态收缩。计算方面,Aurora提供多个读副本的可扩展性配置支持一个区域内多达15个读副本的扩展,提供多主的架构来支持同一个区域内4个写节点的扩展,提供Serverless无服务器化的架构实例级别的秒级纵向扩展,提供全球数据库来实现数据库的低延迟跨区域扩展。

如下图所示Aurora Primary Instance与Read Replica使用相同的底层存储,这种方式降低了存储的成本,并 且数据在主实例与读副本间复制数据带来的性能开销很小。

您的应用程序使用Aurora Connection Endpoint连接到一个Aurora集群。Connection Endpoint表示一个包含主机地址和端口的特定URL。当您创建一个Aurora实例时,AWS会在集群级和实例级创建端点。在集群级别,创建了两个端点,一个用于读/写操作(称为集群端点),另一个用于只读操作(称为只读端点)。故障转移可以通过集群端点实现,通过只读端点实现跨多个Read Replicas的负载平衡。但如果您使用的是实例的Endpoint,那么会固定连接到该Endpoint对应的数据库实例上。

当Aurora集群的主实例发生故障时,Aurora会按照如下顺序自动进行故障切换:

  1. 如果Aurora Read Replicas可用,将现有的Read Replica提升到新的主实例。
  2. 如果没有可用的读副本,则创建一个新的主实例。
  3. 如果有多个Aurora Read Replicas,则根据Read Replicas定义的优先级讲优先级最高的Replica提升为主实例。优先级号取值范围为0 ~ 15,可以随时修改。

关于Aurora Failover的详细原理与流程分析您可以参考另外一篇blog:居安思危 – Amazon Aurora 故障恢复性能提升方案

在实际开发中,我们发现应用层由于使用的JDBC连接池、JDBC driver、以及DNS配置的过期时间不同,应用程序从Aurora Failover中恢复的时间各不相同,因此本篇blog对相关的影响因素进行对比测试,可以给大家选择合适的驱动和连接池提供一些指引。

2. 环境搭建

2.1 搭建Aurora集群

首先根据Aurora集群创建指南创建一套Aurora MySQL集群,机型为db.r5.2xlarge,每套集群有一个写节点两个读节点。

2.2 准备测试Demo

  • 下载GitHub测试Demo

  git clone https://github.com/arch-team/spring-boot-sharding-sphere.git

  • 工程项目说明
spring-boot-sharding-ssphere # 父工程
  | #实现读写分离功能
  ---db-read-write
  | #实现分表功能
  ---sub-table
  | #实现分库分表功能
  ---sub-db-table                      
  | #实现分表 + 读写分离
  ---sub-table-read-write                                        
   | #实现分库分表 + 读写分离
  ---sub-db-table-read-write 
  • properties配置文件说明

这里配置了两个slave,实际测试Aurora Failover您可以使用一主一从即可。

mybatis.config-location=classpath:mybatis-config.xml
server.port=8088
#JDBC驱动实现,本实验您需要使用不同driver来做测试,每个测试场景都需要修改
spring.shardingsphere.datasource.master.driver-class-name=software.aws.rds.jdbc.mysql.Driver
spring.shardingsphere.datasource.master.password=
spring.shardingsphere.datasource.master.type=com.alibaba.druid.pool.DruidDataSource
#Aurora 读写Endpoint URL,每个测试场景都需要修改
#jdbc:mysql:aws://db-identifier.cluster-XYZ.us-east-2.rds.amazonaws.com:3306
spring.shardingsphere.datasource.master.url=
spring.shardingsphere.datasource.master.username=
spring.shardingsphere.datasource.names=master,slave0,slave1

#JDBC驱动实现,本实验您需要使用不同driver来做测试,每个测试场景都需要修改
spring.shardingsphere.datasource.slave0.driver-class-name=software.aws.rds.jdbc.mysql.Driver
spring.shardingsphere.datasource.slave0.password=
spring.shardingsphere.datasource.slave0.type=com.alibaba.druid.pool.DruidDataSource
#Aurora 读写Endpoint URL,每个测试场景都需要修改
#jdbc:mysql:aws://aurora-sharding-sphere.cluster-ro-****.us-east-2.rds.amazonaws.com:3306/dev?useSSL=false&characterEncoding=utf-8
spring.shardingsphere.datasource.slave0.url=
spring.shardingsphere.datasource.slave0.username=

#JDBC驱动实现,本实验您需要使用不同driver来做测试,每个测试场景都需要修改
spring.shardingsphere.datasource.slave1.driver-class-name=software.aws.rds.jdbc.mysql.Driver
spring.shardingsphere.datasource.slave1.password=
spring.shardingsphere.datasource.slave1.type=com.alibaba.druid.pool.DruidDataSource
#Aurora 读写Endpoint URL,每个测试场景都需要修改
#jdbc:mysql:aws://salve1.***.us-east-2.rds.amazonaws.com:3306/dev?useSSL=false&characterEncoding=utf-8
spring.shardingsphere.datasource.slave1.url=
spring.shardingsphere.datasource.slave1.username=admin
spring.shardingsphere.masterslave.load-balance-algorithm-type=round_robin
spring.shardingsphere.masterslave.master-data-source-name=master
spring.shardingsphere.masterslave.name=ms
spring.shardingsphere.masterslave.slave-data-source-names=slave0,slave1
#spring.shardingsphere.mode.type=Memory
spring.shardingsphere.props.sql.show=true
  • pom.xml 配置文件说明

如下图所示,在不同的测试场景下,需要修改依赖的Jdbc client driver。

本测试中我们主要验证Aurora Failover的功能,因此在本实验中只需要使用db-read-write子工程。

3. 基于 AWS JDBC Driver的时延测试

3.1  测试配置说明

  • 工程xml配置

修改./spring-boot-sharding-sphere/pom.xml文件中Jdbc Driver依赖的Jar,替换成

<dependency>
     <groupId>software.aws.rds</groupId>
     <artifactId>aws-mysql-jdbc</artifactId>
     <version>1.0.0</version>
</dependency>

关于aws-mysql-jdbc详细介绍参照GitHub

https://github.com/awslabs/aws-mysql-jdbc

  • 修改properties配置文件说明

参照2.2 准备测试Demo中的application.properties配置文件说明,你需要修改的项包括如下的内容,其中每个DataSource包括master和slave都需要修改如下内容

**省略相同的内容**.***数据源标识***.driver=
**省略相同的内容**.***数据源标识***.username=
**省略相同的内容**.***数据源标识***.password=
**省略相同的内容**.***数据源标识***.url=
spring.shardingsphere.datasource.master.username=
spring.shardingsphere.datasource.master.driver-class-name=software.aws.rds.jdbc.mysql.Driver
spring.shardingsphere.datasource.master.password=
spring.shardingsphere.datasource.master.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.master.url=

其中driver替换成software.aws.rds.jdbc.mysql.Driver

username:您的Aurora 集群用户名

password:您的Aurora 集群密码

url:Aurora Endpoint URL

使用druid作为连接池

type:com.alibaba.druid.pool.DruidDataSource 

jdbc:mysql:aws://*集群名称*.*集群id*.us-east-2.rds.amazonaws.com:3306/*数据库名*?useSSL=false&characterEncoding=utf-8

注意:使用aws jdbc driver 数据库的url前缀需要使用jdbc:mysql:aws

3.2 测试过程说明

  • 启动spring boot 工程

在./spring-boot-sharding-sphere/db-read-write/src/main/java/com/oujiong/Application.java上执行 Run AS。

如下图所示本次测试使用的是(AWS) JDBC Driver for MySQL

重复执行该方法,观测该REST API执行是否成功。

  • 在Aurora的console上手动执行Aurora Failover。

3.3 测试结果说明

     API调用恢复过程的时间记录,大约是5秒钟;多次测试记录Failover时应用层的恢复时间大概在4~8秒钟之间。

<> 2022-04-15T123025.200.txt
<> 2022-04-15T123023.200.txt # Failover恢复API支持成功的时间
<> 2022-04-15T123022.500.json # API执失败的实际
<> 2022-04-15T123017.200.txt # 最近一次执行成功的实际
<> 2022-04-15T123015.200.txt
<> 2022-04-15T123013.200.txt

API调用失败的异常信息

Error updating database.  Cause: java.sql.SQLException: The active SQL connection has changed due to a connection failure. Please re-configure session state if required.
The error may exist in mapper/UserMapper.xml
The error may involve com.oujiong.mapper.UserMapper.insert-Inline
The error occurred while setting parameters
SQL: insert into tab_user (id, name, sex,       age, create_time, update_time,       status)     values (?, ?, ?,       ?, ?, ?,       ?)
Cause: java.sql.SQLException: The active SQL connection has changed due to a connection failure. Please re-configure session state if required.
; The active SQL connection has changed due to a connection failure. Please re-configure session state if required.; nested exception is java.sql.SQLException: The active SQL connection has changed due to a connection failure. Please re-configure session state if required.] with root cause

如下图所示Aurora执行Failover 读写器从salve1变成了aurora-sahrding-sphere-instance-1-us-east-2a

4.基于mysql-connector/J的时延测试

4.1  测试配置说明

  • 工程xml配置

修改./spring-boot-sharding-sphere/pom.xml文件中的Jdbc Driver依赖Jar,替换成

<dependency>
       <groupId>mysql</groupId>
       <artifactId>mysql-connector-java</artifactId>
</dependency>

关于mysql-connector-j详细介绍参照GitHub

https://github.com/mysql/mysql-connector-j

  • 修改properties配置文件说明

参照2.2 准备测试Demo中的application.properties配置文件说明,你需要修改的项包括如下的内容,其中每个DataSource包括master和slave都需要修改如下内容

**省略相同的内容**.***数据源标识***.driver=
**省略相同的内容**.***数据源标识***.username=
**省略相同的内容**.***数据源标识***.password=
**省略相同的内容**.***数据源标识***.url=
spring.shardingsphere.datasource.master.username=
spring.shardingsphere.datasource.master.driver-class-name=software.aws.rds.jdbc.mysql.Driver
spring.shardingsphere.datasource.master.password=
spring.shardingsphere.datasource.master.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.master.url=

其中driver替换成com.mysql.jdbc.Driver

username:您的Aurora 集群用户名

password:您的Aurora 集群密码

url:Aurora Endpoint URL

jdbc:mysql://*集群名称*.*集群id*.us-east-2.rds.amazonaws.com:3306/*数据库名*?useSSL=false&characterEncoding=utf-8

注意:使用mysql-connector/J数据库的url前缀需要使用jdbc:mysql

4.2 测试过程说明

  • 启动spring boot 工程

在./spring-boot-sharding-sphere/db-read-write/src/main/java/com/oujiong/Application.java上执行 Run AS。

本次测试使用的是mysql-connector/J

重复执行该方法,观测该REST API执行是否成功。

  • 在Aurora的console上手动执行Aurora Failover

4.3 测试结果说明

     API调用恢复过程的时间记录,大约是45秒钟;多次测试记录Failover应用层的恢复时间大概在30~50多秒钟之间。

<> 2022-04-15T125920.200.txt
<> 2022-04-15T125918.200.txt # Failover恢复API支持成功的时间
<> 2022-04-15T125909.500.json # API执失败的实际
<> 2022-04-15T125904.500.json # API执失败的实际
<> 2022-04-15T125900.500.json # API执失败的实际
<> 2022-04-15T125855.500.json
<> 2022-04-15T125849.500.json # API执失败的实际
<> 2022-04-15T125844.500.json # API执失败的实际
<> 2022-04-15T125840.500.json # API执失败的实际
<> 2022-04-15T125834.500.json # API执失败的实际
<> 2022-04-15T125833.200.txt  # 最近一次执行成功的实际
<> 2022-04-15T125831.200.txt

API调用失败的异常信息

2022-04-15 12:58:33.975 INFO 26782 --- [nio-8088-exec-7] ShardingSphere-SQL : Rule Type: master-slave
2022-04-15 12:58:33.975 INFO 26782 --- [nio-8088-exec-7] ShardingSphere-SQL : SQL: insert into tab_user (id, name, sex,
age, create_time, update_time,
status)
values (?, ?, ?,
?, ?, ?,
?) ::: DataSources: master
2022-04-15 12:58:33.989 ERROR 26782 --- [nio-8088-exec-7] com.alibaba.druid.pool.DruidDataSource : discard connection
java.sql.SQLException: Could not retrieve transaction read-only status from server
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:965) ~[mysql-connector-java-5.1.47.jar:5.1.47]
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:898) ~[mysql-connector-java-5.1.47.jar:5.1.47]
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:887) ~[mysql-connector-java-5.1.47.jar:5.1.47]
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:861) ~[mysql-connector-java-5.1.47.jar:5.1.47]
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:878) ~[mysql-connector-java-5.1.47.jar:5.1.47]

如下图所示Aurora执行Failover ,读写器从aurora-sahrding-sphere-instance-1-us-east-2a变成了salve1

5. 基于MariaDB Connector/J的时延测试

5.1  测试配置说明

  • 工程xml配置

修改./spring-boot-sharding-sphere/pom.xml文件中的Jdbc Driver依赖Jar,替换成

<dependency>
    <groupId>org.mariadb.jdbc</groupId>
    <artifactId>mariadb-java-client</artifactId>
    <version>3.0.4</version>
</dependency>

关于mariadb-connector-j详细介绍参照GitHub

https://github.com/mariadb-corporation/mariadb-connector-j

  • 修改properties配置文件说明

参照2.2 准备测试Demo中的application.properties配置文件说明,你需要修改的项包括如下的内容,其中每个DataSource包括master和slave都需要修改如下内容

**省略相同的内容**.***数据源标识***.driver=
**省略相同的内容**.***数据源标识***.username=
**省略相同的内容**.***数据源标识***.password=
**省略相同的内容**.***数据源标识***.url=
spring.shardingsphere.datasource.master.username=
spring.shardingsphere.datasource.master.driver-class-name=software.aws.rds.jdbc.mysql.Driver
spring.shardingsphere.datasource.master.password=
spring.shardingsphere.datasource.master.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.master.url=

其中driver替换成org.mariadb.jdbc.Driver

username:您的Aurora 集群用户名

password:您的Aurora 集群密码

url:Aurora Endpoint URL

jdbc:mariadb://*集群名称*.*集群id*.us-east-2.rds.amazonaws.com:3306/*数据库名*?useSSL=false&characterEncoding=utf-8

注意:使用mariadb-java-client数据库的url前缀需要使用jdbc:mariadb

5.2 测试过程说明

与基于mysql-connector/J的时延测试章节的内容类似,这里不再重复描述。

5.3 测试结果说明

在分别使用mariadb-java-client 3.0.4 和 1.1.9 发现如下问题,采用mariadb-java-client应用层从Failover中恢复的时间高达十来分钟。

<> 2022-04-15T211640.200.txt
<> 2022-04-15T213015.200.txt
<> 2022-04-15T213003.200.txt # Failover恢复API支持成功的时间
<> 2022-04-15T212952.500.json
<> 2022-04-15T212511.500.json
<> 2022-04-15T212230.500.json
<> 2022-04-15T211653.500.json
<> 2022-04-15T211642.500.json # API执失败的实际
<> 2022-04-15T211641.200.txt # 最近一次执行成功的实际

其中上层API调用的报错信息如下:

“timestamp”: “2022-04-15T13:39:26.858+0000”,
“status”: 500,
“error”: “Internal Server Error”,
“message”: “\n### Error updating database. Cause: java.sql.SQLException: (conn=5) The MySQL server is running with the —read-only option so it cannot execute this statement\n### The error may exist in mapper/UserMapper.xml\n### The error may involve com.oujiong.mapper.UserMapper.insert-Inline\n### The error occurred while setting parameters\n### SQL: insert into tab_user (id, name, sex, age, create_time, update_time, status) values (?, ?, ?, ?, ?, ?, ?)\n### Cause: java.sql.SQLException: (conn=5) The MySQL server is running with the —read-only option so it cannot execute this statement\n; uncategorized SQLException; SQL state [HY000]; error code [1290]; (conn=5) The MySQL server is running with the —read-only option so it cannot execute this statement; nested exception is java.sql.SQLException: (conn=5) The MySQL server is running with the —read-only option so it cannot execute this statement”,
“path”: “/save-user”

6. 基于RDS Proxy的时延

RDS Proxy的测试可以通过直接连接Proxy的Endpoint执行SQL即可,本篇blog不做描述,如果您决定在生产上使用RDS Proxy它可以有效降低Failover的恢复时间,考虑在服务端降低Failover 恢复时间可以使用这种方案。

使用RDS Proxy Failover 恢复时间的测试,请参考另外一篇blog

   居安思危 – Amazon Aurora 故障恢复性能提升方案

7. 结论

影响Amazon Aurora for MySQL的时延因素包括如下方面

1、使用SQL Driver,包括

mariadb-java-client
aws-mysql-jdbc
mysql-connector-java

2、使用的数据库连接池

HikariCP
druid

综合测试结果来看aws-mysql-jdbc与druid 或者 HikariCP Failover的时延都比较短,大概在7~8秒左右;druid 与 aws-mysql-jdbc或者mariadb-java-client  Failover恢复时间大概在40秒左右。HikariCP 与mysql-connector-java和mariadb-java-client Failover 恢复时间在分钟级别。

注意:以上的测试数据是基于通过公网连接Aurora进行的,另外由于使用的中间件不同,中间件的版本也有区别,另外本篇blog主要关注Aurora Failover恢复的时间,实际使用中还需要关注性能、连接的稳定性等,因此上述测试数据仅供参考,生产使用时要评估Aurora Failover的时间,建议以您实际的部署环境和真实使用的软件系统为基准进行测试。

8.参考资料

https://aws.amazon.com/cn/blogs/database/improve-application-availability-with-the-aws-jdbc-driver-for-amazon-aurora-mysql/

https://aws.amazon.com/cn/blogs/database/failover-with-amazon-aurora-postgresql/

https://crishantha.medium.com/aws-aurora-why-is-it-better-6faae33a0ed0

9.问题记录

在使用hikari时,数据库连接的url配置的应该使用jdbc-url,而不是url;在使用druid作为连接池时,应该使用的url。

spring.shardingsphere.datasource.ds_master.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds_master.jdbc-url=***

springboot配置文件中不能有空格,如下的包名加了空格的话会提示找不到HikariDataSource

com.zaxxer.hikari.HikariDataSource

相关博客

居安思危 —— Amazon Aurora 故障恢复之降低DNS切换对应用影响篇

本篇作者

孙进华

亚马逊云科技资深解决方案架构师,负责帮助客户进行上云架构的设计和咨询。加入AWS前自主创业负责电商平台搭建和车企电商平台整体架构设计。曾就职于全球领先的通讯设备公司,担任高级工程师,负责LTE设备系统的多个子系统的开发与架构设计。在高并发、高可用系统架构设计、微服务架构设计、数据库、中间件、IOT等方面有着丰富的经验。