无论好坏,我们已将整个 LAMP Web 应用程序从专用机器迁移到云(Amazon EC2 机器)。到目前为止进展顺利,但我们做 crons 的方式不是最佳的。我有一个亚马逊特有的问题,关于如何使用“亚马逊方式”最好地管理云中的 cron 作业。
问题:我们有多个网络服务器,并且需要为批处理作业运行 crons,例如创建 RSS 提要、触发电子邮件,实际上还有许多不同的事情。但是 cron 作业只需要在一台机器上运行,因为它们经常写入数据库,因此如果在多台机器上运行会重复结果。
到目前为止,我们将其中一个网络服务器指定为“主网络服务器”,它有一些其他网络服务器没有的“特殊”任务。云计算的权衡是可靠性——我们不想要“主网络服务器”,因为它是单点故障。我们希望它们都是相同的,并且能够在不记住不要将主网络服务器从集群中取出的情况下进行升级和降级。
我们如何重新设计我们的应用程序以将 Linux cron 作业转换为没有单点故障的临时工作项?
到目前为止我的想法:
有一台专门用于运行 crons 的机器。这将更易于管理,但仍然是单点故障,并且会浪费一些钱来获得额外的实例。
可以想象,一些工作可以从 Linux crons 转移到 MySQL Events,但是我不喜欢这个想法,因为我不想将应用程序逻辑放入数据库层。
也许我们可以在所有机器上运行所有的 cron,但是改变我们的 cron 脚本,使它们都从一些实现锁定机制的逻辑开始,这样只有一个服务器实际采取行动,而其他服务器只是跳过。我不喜欢这个想法,因为它听起来可能有问题,我更愿意使用亚马逊的最佳实践而不是自己动手。
我在想象这样一种情况,工作被安排在某个地方,添加到队列中,然后网络服务器每个都可以是一个工作人员,可以说“嘿,我会接受这个”。 Amazon Simple Workflow Service 听起来正是这种事情,但我目前对此了解不多,因此任何细节都会有所帮助。对于像 cron 这样简单的东西来说,它似乎有点重量级?它是正确的服务还是有更合适的亚马逊服务?
更新: 自从提出这个问题后,我在 YouTube 上观看了 Amazon Simple Workflow Service 网络研讨会,并在 34:40 (http://www.youtube.com/watch?v=lBUQiek8Jqk#t=34m40s) 注意到,我瞥见了一张幻灯片,其中提到了 cron 作业作为示例应用程序。在他们的文档页面“AWS Flow Framework samples for Amazon SWF”中,亚马逊说他们有 crons 的示例代码:
... > Cron 作业 在此示例中,长时间运行的工作流会定期执行活动。演示了将执行作为新执行继续执行的能力,以便执行可以运行很长时间。 ...
我下载了适用于 Java 的 AWS 开发工具包 (http://aws.amazon.com/sdkforjava/),果然埋在可笑的文件夹层中,有一些 java 代码 (aws-java-sdk-1.3.6/samples/AwsFlowFramework/src/com/amazonaws/services/simpleworkflow/flow/examples/periodicworkflow
)。
问题是,老实说,这并没有真正的帮助,因为这不是我可以用我的技能轻松消化的东西。 PHP SDK 中缺少相同的示例,并且似乎没有指导该过程的教程。所以基本上,我仍在寻找建议或提示。
我注册了 Amazon Gold 支持来问他们这个问题,这是他们的回答:
Tom 我对我的一些同事进行了一次快速调查,结果发现 cron 是空的,但在睡了之后我意识到重要的一步可能仅限于锁定。所以我找了“分布式 cron 作业锁定”,找到了一个 Apache 项目 Zookeeper 的引用。 http://zookeeper.apache.org/doc/r3.2.2/recipes.html http://highscalability.com/blog/2010/3/22/7-secrets-to-successfully-scaling-with-scalr-on -amazon-by-se.html 我还看到了使用 memcached 或类似的缓存机制作为使用 TTL 创建锁的方法的参考。通过这种方式,您设置了一个 TTL 为 300 秒的标志,并且没有其他 cron worker 将执行该作业。 TTL 过期后,锁会自动释放。这在概念上与我们昨天讨论的 SQS 选项非常相似。另见;谷歌的胖乎乎的 http://static.googleusercontent.com/external_content/untrusted_dlcp/research.google.com/en//archive/chubby-osdi06.pdf 让我知道这是否有帮助,并随时提出问题,我们非常清楚对于初学者和经验丰富的开发人员来说,我们的服务可能很复杂且令人生畏。我们总是乐于提供架构和最佳实践建议。最好的问候, Ronan G. Amazon Web Services
我认为这个视频回答了你的确切问题 - cronjobs aws 方式(可扩展和容错):
Using Cron in the Cloud with Amazon Simple Workflow
该视频使用实施 cronjobs 的特定用例描述了 SWF 服务。
如果您直接来自 crontab,则该解决方案的相对复杂性可能难以接受。最后有一个案例研究帮助我了解额外的复杂性会给你带来什么。我建议您观看案例研究并考虑您对可扩展性和容错性的要求,以决定是否应该从现有的 crontab 解决方案迁移。
将 SQS 用于 cronjobs 时要小心,因为它们不能保证“只有一台机器可以看到一个作业”。他们保证“至少一个”会收到消息。
来自:http://aws.amazon.com/sqs/faqs/#How_many_times_will_I_receive_each_message
问:每条消息我会收到多少次? Amazon SQS 旨在提供其队列中所有消息的“至少一次”传输。尽管大多数情况下每条消息都将只传递给您的应用程序一次,但您应该设计您的系统,以便多次处理消息不会产生任何错误或不一致。
到目前为止,我可以考虑一个安装了 Gearman 作业服务器实例的实例的解决方案:http://gearman.org/。在同一台机器上,您配置生成命令的 cron 作业以在后台执行您的 cronjob 任务。然后你的一个网络服务器(worker)将开始执行这个任务,它保证只有一个会接受它。你有多少工人并不重要(尤其是当你使用自动缩放时)。
这个解决方案的问题是:
Gearman 服务器是单点故障,除非您使用分布式存储对其进行配置,例如使用 memcached 或某些数据库
然后使用多个 Gearman 服务器,您必须选择一个通过 cronjob 创建任务的服务器,所以我们又回到了同样的问题。但是,如果您可以忍受这种单点故障,那么使用 Gearman 看起来是个不错的解决方案。特别是你不需要大实例(在我们的例子中微实例就足够了)。
Amazon 为 Elastic Beanstalk 提供了 released 个新功能。从 docs:
AWS Elastic Beanstalk 支持在运行预定义配置的环境中对工作线程环境层执行定期任务,该配置的解决方案堆栈在容器名称中包含“v1.2.0”。 "
您现在可以创建一个包含配置调度任务的 cron.yaml
文件的环境:
version: 1
cron:
- name: "backup-job" # required - unique across all entries in this file
url: "/backup" # required - does not need to be unique
schedule: "0 */12 * * *" # required - does not need to be unique
- name: "audit"
url: "/audit"
schedule: "0 23 * * *"
我想通过消息队列(SQS)使用在自动缩放环境中只运行一次的保险。当 cron 守护程序触发一个事件时,它会将调用放入 SQS 队列中,并且队列中的消息只被评估一次。文档说如果 SQS 有很多消息要处理,执行可能会延迟。
我现在第三次遇到这个问题,并认为我会参与进来。我们已经陷入困境有一段时间了。我仍然觉得 AWS 在这里缺少一个功能。
在我们的案例中,在查看了可能的解决方案后,我们决定有两种选择:
设置一个 cronjob 服务器,该服务器运行一次只能运行一次的作业,自动扩展它并确保在某些 CloudWatch 统计信息不应该是时替换它。我们使用 cloud-init 脚本来运行 cronjobs。当然,这会带来停机时间,从而导致错过 cronjobs(当每分钟运行某些任务时,就像我们一样)。
使用 rcron 使用的逻辑。当然,真正的魔力并不在于 rcron 本身,它在于您用来检测故障节点(我们在这里使用 keepalived)并将另一个节点“升级”为 master 的逻辑。
我们决定采用第二个选项,仅仅是因为它速度非常快,而且我们已经拥有运行这些 cronjobs 的网络服务器的经验(在我们之前的 AWS 时代)。
当然,此解决方案专门用于替换传统的单节点 cronjob 方法,其中时间是决定性因素(例如“我希望作业 A 每天早上 5 点运行一次”,或类似我们的案例“我希望作业 B 每分钟运行一次”)。如果您使用 cronjobs 来触发批处理逻辑,您应该真的看看 SQS
。没有主动-被动的困境,这意味着您可以使用单个服务器或整个劳动力来处理您的队列。我还建议查看 SWF
来扩展您的员工队伍(尽管在大多数情况下 auto scaling
可能也能做到这一点)。
依赖另一个第三方是我们想要避免的。
2016 年 2 月 12 日,亚马逊发布了关于 Scheduling SSH jobs using AWS Lambda 的博客。我认为这回答了这个问题。
如果您已经启动了 Redis 服务,这看起来是一个不错的解决方案:
https://github.com/kvz/cronlock
阅读更多:http://kvz.io/blog/2012/12/31/lock-your-cronjobs/
“亚马逊”方式是分布式的,这意味着庞大的 crons 应该被分成许多较小的作业并交给正确的机器。
使用类型设置为 FIFO 的 SQS 队列,将其粘合在一起以确保每个作业仅由一台机器执行。它还容忍失败,因为队列将缓冲直到机器重新启动。
FIFO Exactly-Once Processing:消息被传递一次并保持可用,直到消费者处理并删除它。不会将重复项引入队列中。
还要考虑您是否真的需要“批处理”这些操作。如果一晚的更新比预期的大得多,会发生什么?即使使用动态资源,您的处理也可能会延迟,等待足够多的机器启动。相反,将您的数据存储在 SDB 中,通过 SQS 通知机器更新,并动态创建您的 RSS 提要(使用缓存)。
批处理作业始于处理资源有限且“实时”服务优先的时代。在云中,情况并非如此。
你为什么要建立自己的?为什么不使用 Quartz 之类的东西(带有集群调度)。请参阅文档。
http://quartz-scheduler.org/documentation/quartz-2.x/configuration/ConfigJDBCJobStoreClustering
我们所做的是我们有一个特定的服务器,它是我们 Web 应用程序集群的一部分,位于 ELB 后面,还分配了一个特定的 DNS 名称,以便我们可以在该特定服务器上运行作业。这还有一个好处是,如果该作业导致该服务器变慢,ELB 会将其从集群中删除,然后在作业结束并再次恢复健康时将其返回。
像冠军一样工作。
验证您的 cron 表达式是否以 Amazon 方式工作的一种方法是通过 events 命令运行它。例如:
aws events put-rule --name "DailyLambdaFunction" --schedule-expression "<your_schedule_expression>
如果您的计划表达式无效,那么这将失败。
更多资源:https://docs.aws.amazon.com/cli/latest/reference/events/put-rule.html