AWS Aurora Serverless - 通信链路故障

joh*_*ohn 6 mysql amazon-web-services amazon-aurora aws-serverless

我在 python 代码中使用 MySQL Aurora Serverless 集群(启用了数据 API),但出现communications link failure异常。这通常发生在集群休眠一段时间后。

但是,一旦集群处于活动状态,我就不会出错。我必须每次发送 3-4 个请求才能正常工作。

异常详情:

最后一个成功发送到服务器的数据包是 0 毫秒前。驱动程序没有收到来自服务器的任何数据包。调用 ExecuteStatement 操作时发生错误 (BadRequestException):通信链接失败

我该如何解决这个问题?我正在使用标准的 boto3 库

joh*_*ohn 10

这是来自 AWS Premium Business Support 的回复。

Summary: It is an expected behavior
Run Code Online (Sandbox Code Playgroud)

详细解答:

我可以看到,当您的 Aurora Serverless 实例处于非活动状态时,您会收到此错误,并且一旦您的实例处于活动状态并接受连接,您就会停止接收它。请注意,这是预期的行为。一般来说,Aurora Serverless 的工作方式与 Provisioned Aurora 不同,在 Aurora Serverless 中,当集群处于“休眠”状态时,它没有分配给它的计算资源,并且当一个 db. 收到连接,分配计算资源。由于这种行为,您将不得不“唤醒”集群,并且如您所见,第一次连接可能需要几分钟才能成功。

为了避免这种情况,您可以考虑增加客户端的超时时间。此外,如果您启用了暂停,您可以考虑禁用它 [2]。禁用暂停后,您还可以将最小 Aurora 容量单位调整为更高的值,以确保您的集群始终具有足够的计算资源来为新连接提供服务 [3]。请注意,调整最小 ACU 可能会增加服务成本 [4]。

另请注意,仅建议将 Aurora Serverless 用于某些工作负载 [5]。如果您的工作负载是高度可预测的,并且您的应用程序需要定期访问数据库,我建议您使用 Provisioned Aurora 集群/实例来确保您的业务的高可用性。

[2] Aurora Serverless 的工作原理 - Aurora Serverless 的自动暂停和恢复 - https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/aurora-serverless.how-it-works.html#aurora-serverless。 how-it-works.pause-resume

[3] 设置 Aurora Serverless 数据库集群的容量 - https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/aurora-serverless.setting-capacity.html

[4] Aurora Serverless 价格https://aws.amazon.com/rds/aurora/serverless/

[5] 使用 Amazon Aurora Serverless - Aurora Serverless 的用例 - https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/aurora-serverless.html#aurora-serverless.use-cases


Arl*_*ess 7

如果这对某人有用,这就是我在 Aurora Serverless 唤醒时管理重试的方式。

客户端返回 BadRequestException,因此即使您更改客户端的配置,boto3 也不会重试,请参阅https://boto3.amazonaws.com/v1/documentation/api/latest/guide/retries.html

我的第一个选择是尝试使用 Waiters,但 RDSData 没有任何 waiter,然后我尝试创建一个带有错误匹配器的自定义 Waiter,但仅尝试匹配错误代码,忽略消息,并且因为 BadRequestException 可能由错误引发我也需要验证消息的sql语句,所以我使用了一种服务员函数:

def _wait_for_serverless():
    delay = 5
    max_attempts = 10

    attempt = 0
    while attempt < max_attempts:
        attempt += 1

        try:
            rds_data.execute_statement(
                database=DB_NAME,
                resourceArn=CLUSTER_ARN,
                secretArn=SECRET_ARN,
                sql_statement='SELECT * FROM dummy'
            )
            return
        except ClientError as ce:
            error_code = ce.response.get("Error").get('Code')
            error_msg = ce.response.get("Error").get('Message')

            # Aurora serverless is waking up
            if error_code == 'BadRequestException' and 'Communications link failure' in error_msg:
                logger.info('Sleeping ' + str(delay) + ' secs, waiting RDS connection')
                time.sleep(delay)
            else:
                raise ce

    raise Exception('Waited for RDS Data but still getting error')
Run Code Online (Sandbox Code Playgroud)

我这样使用它:

def begin_rds_transaction():
    _wait_for_serverless()

    return rds_data.begin_transaction(
        database=DB_NAME,
        resourceArn=CLUSTER_ARN,
        secretArn=SECRET_ARN
    )
Run Code Online (Sandbox Code Playgroud)