在我目前正在工作的项目中,我们正在将使用 PHP 和 Vertica 数据库构建的 Web 应用程序迁移到 React SAP + Serverless 后端(AWS API Gateway + Lambda + Aurora Serverless)。

从 Vertica 切换到 Aurora 是最后一步,从我们的集成测试来看,一切看起来都很好。我们面临的唯一问题是这些测试“有时”会失败。

我们从一开始就非常确定它与**Aurora Serverless DB“冷启动”**有关。我们已经应用了一些解决方法来避免 Lambda“睡着”,但现在 VPC + DB Cluster 需要很长时间才能启动。

睡着了

检查日志我们发现 Lambda 在 5 秒后超时。简单的。只需增加 serverless.yml 中的超时时间:

timeout: 30 # vcp + paused Aurora cluster can take a while

我们设置了一个非常高的值来排除 lambda 本身的任何超时。

现在日志告诉我们 MySQL 驱动程序正在超时。我们查看了mysql2的文档,发现默认是10秒。

我们也增加了它,但由于休眠的 Aurora 数据库集群可能需要 25 秒才能被唤醒......我们达到了网关 API 端点的硬性限制。

尖叫

为什么硬限制?因为AWS 告诉我们API 网关在 29 秒后超时,并且无法增加超时(这很有意义 - 你绝对不希望你的 RestAPI 挂起这么久 - 如果他们真的需要的话很多时候可能是改变架构并转向更异步的东西)

所以..我们能做什么?

我们已经进行了预热,但这只是用来生成容器:处理程序在检查上下文后立即返回(正如我在此处描述的)。

我们可以简单地修改逻辑,以便在热身时 ping 数据库唤醒它。

但更好的解决方案是禁用 Aurora Serverless 上的“暂停”功能并将容量单位减少到 1,这样您的数据库集群就永远不会进入休眠状态,并且您始终至少有一个可用的 ACU,如果是这种情况,AWS 会对其进行扩展自动地。

当然,这似乎以某种方式违背了无服务器数据库的目的——您将数据库配置为在需要时自动缩放,并且只需为其使用付费:

如果我因为启动时间太长而必须让一个实例始终打开,那么在 EC2 上安装 Aurora 有什么好处?

好吧,好处正是自动扩展功能(在多个可用区上)

如果您不需要多个可用区并且您对成本非常敏感,那么您绝对可以只使用预配置的极光而不是无服务器。

在这里您可以找到一篇关于 与 EC2 上的 Aurora 相比,Aurora Serverless 的成本的精彩而详细的文章。

在我们的例子中,花更多的欧元来获得更稳定的服务并不是什么大不了的事,并且不要疯狂地跟上 cronjobs 和热身,因此我们决定让 1 ACU 在生产中始终处于活跃状态并忍受staging 和 dev 的冷启动(任何 QA 测试人员只需刷新 ReactApp 页面以使连接运行 - 集成测试也可以这样做 - 重试或 ping 数据库 - 等待然后执行它们)

如何在 serverless 中设置此配置?

在 AWS UIconsole 中,这很容易。只需单击配置选项卡 - 更改 ACU 和 Autopause 字段即可。

[AWS UI 控制台 RDS 配置](https://res.cloudinary.com/practicaldev/image/fetch/s--WvNnVhVJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev .s3.amazonaws.com/i/q1dcaeykofxfv6h6192r.png)

使用无服务器框架,最困难的部分始终是找到正确的属性来描述代码中的堆栈并浏览大量的 AWS 文档。

您可以在 API 参考页面](https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_ModifyCurrentDBClusterCapacity.html)或AWS SDK 文档中阅读有关数据库集群容量的[扩展配置的信息,但要在 yml 文件中找到正确的配置,您必须转到Cloud Formation 文档。

一旦你在那里,你会意识到它确实非常简单。

在资源下放:

 RDSCluster:
      Type: AWS::RDS::DBCluster
      Properties:
        MasterUsername: YOUR_DB_USERNAME
        MasterUserPassword: YOUR_DB_PSW
        DatabaseName: YOUR_DB_NAME
        Engine: aurora
        EngineMode: serverless
        ScalingConfiguration:
          AutoPause: false
          MaxCapacity: 64
          MinCapacity: 1
        DBSubnetGroupName: YOUR_SUBNET_NAME
        BackupRetentionPeriod: 1
        DeletionProtection: true

进入全屏模式 退出全屏模式

这将创建一个 Aurora Serverless 数据库集群,该集群无法删除、永不休眠,并且至少具有 1 个 ACU。

不过,在我们的案例中,我们希望为每个不同的环境提供不同的配置。我们不想在始终可用的 QA 和 DEV 实例上浪费金钱,我们也不需要这些环境的快照和备份。

所以 - 由于 yml 中并不真正存在条件 - 我们创建了一堆自定义属性并根据阶段引用它们:

在 Custom 下,只需声明它们:

autopause:
    production: false
    default: true

进入全屏模式 退出全屏模式

并在 DBCluster 配置中像这样引用它们:

AutoPause: ${self:custom.autopause.${self:provider.stage}, self:custom.autopause.default}

进入全屏模式 退出全屏模式

这就是在无服务器中您可以基于阶段获取属性的方式,并且如果属性中不存在阶段名称,则回退到默认值。


当您使用配置时,一个很好的提示是使用

sls print -s YOUR_STAGENAME

进入全屏模式 退出全屏模式

看看所有最终的 yml 将如何解决所有变量。

您对 Aurora Serverless 有任何问题,或者您对该主题有什么有趣的建议吗?

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐