我有一个在EC2上的AWS上运行的(golang web服务器)服务(没有自动扩展)。该服务有几个cron作业,这些作业在服务启动时启动。
我想在AWS上以某种形式利用自动扩展的优势。一直在看ECS和Beanstalk
当我添加自动缩放时,由于外部api的速率限制,我需要cron作业只在一个缩放的服务上执行。现在,cron作业在服务中是紧密耦合的,我正在寻找一个不需要将cron作业移动到自己的服务中的选项。
如何使用AWS以良好的方式实现这一目标?
在crons不能/不应该多次运行的任何可扩展应用程序中,您都会遇到这个问题。它并不是AWS特有的。我不确定你想在多大程度上保持事物耦合,或者你的crons目前是如何运行的,但这里有一些建议可能对你有用:
创建"cron runner"限制在上运行crons的实例
你可以创建一个单独的ECS服务,它没有自动伸缩,并且固定值为1个实例。此实例将运行与"正常"代码相同的代码副本。实例,并运行crons。你会在你的"正常"状态下关掉crons。实例。你可能会发现这是一个非常小的实例,因为它不处理任何网络流量。
创建"cron触发器";远程触发crons的实例
在这里创建一个"触发器"实例,它通过ALB向普通实例发送请求。因为您的ALB会将请求路由到它后面的一个服务器,所以cron只运行一次。需要注意的是,如果cron长时间运行,可能需要考虑请求超时。您还必须考虑重试等,但我假设您已经有一个可以适应的过程。
上述解决方案可以与消息队列等一起使用,但两者的基础是存在另一个启动cron的实例,并且与普通服务器分开。根据您的cron运行的时间,您可能每天只需要运行这个cron实例几个小时,因此这样做可以节省成本。
就我个人而言,我在一个多租户应用程序中使用了这两种方法,由于租户的数量和一次为所有租户运行cron所需的时间/资源,我不得不选择像这样运行cron:
- Cloudwatch schedule触发一个lambda,该lambda向SQS发送消息,为每个租户单独排队。
- Cron服务器(完全独立于主web服务器,但运行相同/类似的代码)提取消息并为每个租户单独运行Cron。在redis中为crons存储一个键,这些crons只运行一次,以停止"至少一次"的问题。
这也可以帮助处理在SQS中管理的重试策略和死信队列的失败。
最终你需要从一个地方踢开这些crons。如果可能的话,更改您的代码,这样即使它们运行两次也没关系。它使处理重试和类似的事情更容易。