Amazon ElasticBeanstalk 中的单实例 cronjob
Single instance cronjob in Amazon ElasticBeanstalk
我最近将我的 Symfony 项目从手动扩展的 EC2 环境移动到 Elastic Beanstalk,我偶然发现了一个问题。
我有一个 Cron 作业可以抓取一堆过期的订阅,并尝试创建订单并向它们收费,非常重要的是这个作业只能在单个服务器上运行,因为它会批量抓取它们,如果有重复的 Cron 运行,将导致对同一订阅进行多次收费。
在手动扩展环境中,我只有一个主服务器,它有一个 crontab 和 运行 子程序,但这在这里似乎不可行。
关于如何在没有主服务器的自动缩放环境中设置它的任何建议?
我查看了 JMSJobQueueBundle,但它似乎也只依赖主管 运行 crontab 的单个实例,这在自动缩放环境中是重复的。
让外部服务器每 X 分钟 ping 我的 API 并在它 ping 的单个实例上启动作业是我最好的选择吗?这似乎引入了另一个失败点。
作为警告,您要解决的问题并不简单。
几个选项:
如果连接到MySQL数据库,在事务开始时获取锁(https://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html#function_get-lock)并在事务结束时释放锁。这将防止多个 cronjobs 同时 运行 代码。仅当所有内容都在 SQL.
内处理时才有效
如您所述,您可以使用 AWS Lambda + CloudWatch Events 每 x 分钟触发一次 Lambda 函数,然后 Lambda 可以通过 http(s) 触发您的脚本。但是 lambda 不保证只执行一次,所以这是不安全的。
使用可以获取分布式锁的服务(例如 etcd、consul、redis 等)并以与 1 类似的方式实施,只是不在您的 MySQL 数据库中.你仍然不能用这个来强制执行一次。
将 cronjob 放在一个单独的 ec2 实例上,你知道它只存在一次(如果这个 ec2 实例出现故障,什么都不会 运行,但据我了解你的要求 这不是问题,因为脚本可以 运行 15 分钟后仍然赶上所有工作。
分布式系统中更 "modern" 的方法是使您的操作幂等。
我最近将我的 Symfony 项目从手动扩展的 EC2 环境移动到 Elastic Beanstalk,我偶然发现了一个问题。
我有一个 Cron 作业可以抓取一堆过期的订阅,并尝试创建订单并向它们收费,非常重要的是这个作业只能在单个服务器上运行,因为它会批量抓取它们,如果有重复的 Cron 运行,将导致对同一订阅进行多次收费。
在手动扩展环境中,我只有一个主服务器,它有一个 crontab 和 运行 子程序,但这在这里似乎不可行。
关于如何在没有主服务器的自动缩放环境中设置它的任何建议?
我查看了 JMSJobQueueBundle,但它似乎也只依赖主管 运行 crontab 的单个实例,这在自动缩放环境中是重复的。
让外部服务器每 X 分钟 ping 我的 API 并在它 ping 的单个实例上启动作业是我最好的选择吗?这似乎引入了另一个失败点。
作为警告,您要解决的问题并不简单。
几个选项:
如果连接到MySQL数据库,在事务开始时获取锁(https://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html#function_get-lock)并在事务结束时释放锁。这将防止多个 cronjobs 同时 运行 代码。仅当所有内容都在 SQL.
内处理时才有效
如您所述,您可以使用 AWS Lambda + CloudWatch Events 每 x 分钟触发一次 Lambda 函数,然后 Lambda 可以通过 http(s) 触发您的脚本。但是 lambda 不保证只执行一次,所以这是不安全的。
使用可以获取分布式锁的服务(例如 etcd、consul、redis 等)并以与 1 类似的方式实施,只是不在您的 MySQL 数据库中.你仍然不能用这个来强制执行一次。
将 cronjob 放在一个单独的 ec2 实例上,你知道它只存在一次(如果这个 ec2 实例出现故障,什么都不会 运行,但据我了解你的要求 这不是问题,因为脚本可以 运行 15 分钟后仍然赶上所有工作。
分布式系统中更 "modern" 的方法是使您的操作幂等。