Amazon ElasticBeanstalk

时间:2017-02-23 11:24:57

标签: symfony amazon-web-services elastic-beanstalk autoscaling

我最近将我的Symfony项目从手动扩展的EC2环境转移到Elastic Beanstalk,我偶然发现了一个问题。

我有一个Cron作业,它抓住了一堆已过期的订阅,并尝试创建订单并对其进行收费,这项作业只能在一台服务器上运行,这是非常重要的,因为它会批量抓取它们,如果有一个重复的Cron运行,它将导致相同订阅的多个费用。

在手动扩展环境中,我只有一个主服务器,它有一个crontab并运行了sub,但这似乎不可行。

有关如何在没有主服务器的自动缩放环境中进行设置的任何建议吗?

我已经研究过JMSJobQueueBundle,但它似乎依赖于仅运行crontab的单个实例的supervisor,这在自动缩放环境中会重复。

我最好的选择是让外部服务器每X分钟ping一次我的API并在它ping的单个实例上启动作业吗?这似乎引入了另一个失败点。

1 个答案:

答案 0 :(得分:2)

正如警告一样,您试图解决的问题并非微不足道。

一些选择:

  1. 如果连接到MySQL数据库,请在事务开始时获取锁(https://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html#function_get-lock)并在结束时释放锁。这将阻止多个cronjobs同时运行代码。只有在SQL内部处理所有内容时才有效。

  2. 正如您所提到的,您可以使用AWS Lambda + CloudWatch Events每x分钟触发一次Lambda函数,而Lambda可以通过http触发您的脚本。但是lambda并不能保证一次这样做,所以这不安全。

  3. 使用可以获取分布式锁定的服务(例如etcd,consul,redis,...),并以与1不在MySQL数据库中的方式类似的方式实现。你仍然可以用这个完全一次。

  4. 将cronjob放在一个单独的ec2实例上,你知道它只存在一次(如果这个ec2实例出现故障,将无法运行,但据我了解你的要求,这不是问题,因为脚本可以在15分钟后运行,并且仍能完成所有工作。

  5. 分布式系统中更“现代”的方法是使您的行为具有幂等性。