mysql AWS Aurora无服务器-通信链路故障

bq3bfh9z  于 2022-12-17  发布在  Mysql
关注(0)|答案(4)|浏览(199)

我在我的python代码中使用MySQL Aurora无服务器集群(启用了Data API),我收到了一个communications link failure异常,这通常发生在集群休眠了一段时间之后。
但是,一旦集群处于活动状态,我就不会得到任何错误。我必须每次发送3-4个请求才能正常工作。
异常详细信息:
上次成功发送到服务器的数据包是在0毫秒之前。驱动程序尚未从服务器接收到任何数据包。调用ExecuteStatement操作时出错(BadRequestException):通信链路故障
如何解决这个问题?我使用的是标准boto 3库

izj3ouym

izj3ouym1#

下面是AWS高级业务支持的回复。

Summary: It is an expected behavior

详细答案:
我可以看到,当您的Aurora无服务器示例处于非活动状态时,您会收到此错误,而一旦您的示例处于活动状态并接受连接,您就会停止接收此错误。请注意,这是一种预期行为。通常,Aurora无服务器的工作方式与Provisioned Aurora不同,在Aurora无服务器中,当群集处于“休眠”状态时,它没有分配任何计算资源,当接收到db.连接时,计算资源已分配。由于此行为,您将不得不“唤醒”群集,并且可能需要几分钟才能成功进行第一次连接,如您所见。
为了避免这种情况,您可以考虑增加客户端的超时时间。另外,如果您已启用暂停,则可以考虑禁用它[2]。禁用暂停后,你也可以调整Aurora的最小容量单位到更高的值,以确保你的集群总是有足够的计算资源来服务于新的连接[3]。请注意,调整最小ACU可能会增加服务成本[4]。
还需要注意的是Aurora无服务器仅适用于特定的工作负载[5]。如果您的工作负载是高度可预测的,并且您的应用程序需要定期访问数据库,我建议您使用Provisioned Aurora集群/示例来确保业务的高可用性。
[2]Aurora无服务器的工作原理-Aurora无服务器的自动暂停和恢复-https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/aurora-serverless.how-it-works.html#aurora-serverless.how-it-works.pause-resume
[3]设置Aurora无服务器数据库集群的容量-https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/aurora-serverless.setting-capacity.html
[4]Aurora无服务器价格https://aws.amazon.com/rds/aurora/serverless/
[5]使用Amazon Aurora无服务器-Aurora无服务器的使用案例-https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/aurora-serverless.html#aurora-serverless.use-cases

vbopmzt1

vbopmzt12#

如果它对某人有用,这就是我在Aurora无服务器唤醒时管理重试的方式。
客户端返回BadRequestException,因此即使您更改客户端的配置,boto3也不会重试,请参见https://boto3.amazonaws.com/v1/documentation/api/latest/guide/retries.html
我的第一个选择是尝试使用Waiters,但RDSData没有任何waiter,然后我尝试使用Error matcher创建一个自定义Waiter,但只尝试匹配错误代码,忽略消息,并且因为在SQL语句中的错误可能引发BadRequestException,所以我也需要验证消息,所以我使用了一种waiter函数:

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')

我是这样使用它的

def begin_rds_transaction():
    _wait_for_serverless()

    return rds_data.begin_transaction(
        database=DB_NAME,
        resourceArn=CLUSTER_ARN,
        secretArn=SECRET_ARN
    )
bprjcwpo

bprjcwpo3#

我也遇到了这个问题,并从Arless使用的解决方案和与Jimbo的对话中获得灵感,提出了以下解决方案。
我定义了一个装饰器,它重试无服务器RDS请求,直到可配置的重试持续时间到期。

import logging
import functools
from sqlalchemy import exc
import time

logger = logging.getLogger()

def retry_if_db_inactive(max_attempts, initial_interval, backoff_rate):
    """
    Retry the function if the serverless DB is still in the process of 'waking up'.
    The configration retries follows the same concepts as AWS Step Function retries.
    :param max_attempts: The maximum number of retry attempts
    :param initial_interval: The initial duration to wait (in seconds) when the first 'Communications link failure' error is encountered
    :param backoff_rate: The factor to use to multiply the previous interval duration, for the next interval
    :return:
    """

    def decorate_retry_if_db_inactive(func):

        @functools.wraps(func)
        def wrapper_retry_if_inactive(*args, **kwargs):
            interval_secs = initial_interval
            attempt = 0
            while attempt < max_attempts:
                attempt += 1
                try:
                    return func(*args, **kwargs)

                except exc.StatementError as err:
                    if hasattr(err.orig, 'response'):
                        error_code = err.orig.response["Error"]['Code']
                        error_msg = err.orig.response["Error"]['Message']

                        # Aurora serverless is waking up
                        if error_code == 'BadRequestException' and 'Communications link failure' in error_msg:
                            logger.info('Sleeping for ' + str(interval_secs) + ' secs, awaiting RDS connection')
                            time.sleep(interval_secs)
                            interval_secs = interval_secs * backoff_rate
                        else:
                            raise err
                    else:
                        raise err

            raise Exception('Waited for RDS Data but still getting error')

        return wrapper_retry_if_inactive

    return decorate_retry_if_db_inactive

可以像这样使用:

@retry_if_db_inactive(max_attempts=4, initial_interval=10, backoff_rate=2)
def insert_alert_to_db(sqs_alert):
    with db_session_scope() as session:
        # your db code
        session.add(sqs_alert)

    return None

请注意,我使用的是sqlalchemy,所以代码需要调整以适应特定的目的,但希望作为一个有用的入门。

u5rb5r59

u5rb5r594#

这可能有点晚,但是有一种方法可以停用数据库的DORMANT行为。
从CDK创建群集时,可以按如下方式配置属性:

new rds.ServerlessCluster(
  this,
  'id',
  {
    engine: rds.DatabaseClusterEngine.AURORA_MYSQL,
    defaultDatabaseName: 'name',
    vpc,
    scaling:{
      autoPause:Duration.millis(0) //Set to 0 to disable
    }
  }
)

该属性为autoPause。默认值为5分钟(不使用数据库5分钟后,可能会出现Communication link failure消息)。最大值为24小时。但是,您可以将该值设置为0,这将禁用自动关闭。之后,即使没有连接,数据库也不会进入睡眠状态。
当从AWS查看配置时(RDS -〉数据库-〉'示例' -〉配置-〉容量设置),您会注意到这个属性没有值(如果设置为0):

最后,如果不希望数据库一直处于ON状态,请设置自己的autoPause值,使其按预期运行。

相关问题