如何将 Linux cron 作业转换为“ Amazon 方式”?

无论好坏,我们已经将整个 台灯 Web 应用程序从专用机器迁移到了云(Amazon EC2机器)。到目前为止进展很顺利,但是我们做 老年痴呆症的方法是次优的。我有一个亚马逊特有的问题,关于如何使用“亚马逊方式”最好地管理云中的 cron 作业。

问题 : 我们有多个 Web 服务器,需要运行 crons 来完成批处理任务,比如创建 RSS 提要、触发电子邮件等等。但是 cron 作业是 只需要在一台机器上运行,因为它们经常写入数据库,所以如果在多台机器上运行,结果会重复。

到目前为止,我们指定了一个网络服务器作为“主-网络服务器”,它有一些其他网络服务器没有的“特殊”任务。云计算的代价是可靠性——我们不想要一个“主网络服务器”,因为它是单点故障。我们希望它们都是相同的,并且能够进行升级和降级,而不用记得不把主网络服务器从集群中拿出来。

我们如何重新设计应用程序,将 Linux cron 作业转换为没有单点故障的临时工作项?

到目前为止,我的想法是:

  • 有一个专门用于运行 crons 的机器。这样会更容易管理一些,但仍然是单点故障,并且会浪费一些钱来创建额外的实例。
  • 可以想象,有些作业可以从 Linux crons 转移到 MySQL 事件,但是我不太喜欢这个想法,因为我不想把应用程序逻辑放到数据库层。
  • 也许我们可以在所有计算机上运行所有 cron,但是需要更改 cron 脚本,以便它们都从一个实现锁机制的逻辑开始,这样只有一个服务器实际采取行动,其他服务器只是跳过。我不是这个想法的粉丝,因为它听起来可能有问题,我宁愿使用亚马逊的最佳实践,而不是我们自己的。
  • 我在想象这样一种情况: 工作被安排在某个地方,添加到一个队列中,然后网络服务器可能每个都是一个工作人员,这个工作人员可以说“嘿,我要这个工作人员”。亚马逊简单工作流服务听起来正是这样的东西,但我目前不知道很多关于它,所以任何细节将是有益的。对于像 cron 这样简单的东西来说,它似乎有点重量级?这是正确的服务,还是有一个更合适的亚马逊服务?

更新: 自从提出这个问题以来,我在 YouTube 上观看了 亚马逊简单工作流服务的网络研讨会,并注意到在34:40(http://www.youtube.com/watch?v=lBUQiek8Jqk#t=34m40s) ,我瞥见了一张幻灯片,其中提到了 cron Jobs 作为样本应用程序。在他们的文档页面“ Amazon SWF 的 AWS 流框架示例”中,亚马逊说他们有 crons 的示例代码:

在这个示例中,周期性地运行一个长时间的工作流 executes an activity. The ability to continue executions as new 执行,以便执行可以运行非常长的时间 时间被证明。 ...

I downloaded the AWS SDK for Java (http://aws.amazon.com/sdkforjava/) and sure enough buried within a ridiculous layers of folders there is some java code (aws-java-sdk-1.3.6/samples/AwsFlowFramework/src/com/amazonaws/services/simpleworkflow/flow/examples/periodicworkflow).

问题是,如果我诚实的话,这并没有真正的帮助,因为这不是我可以轻易消化我的技能。PHP SDK 中缺少相同的示例,似乎没有一个教程来完成这个过程。所以基本上,我还在寻求建议或者小费。

33622 次浏览

“ Amazon”的方式是分布式的,这意味着庞大的 cron 应该被分割成许多更小的作业并交给正确的机器。

Using SQS queue with type set to FIFO, glue it together to ensure each job is executed by only one machine. It also tolerates failure since the queues will buffer until a machine spins back up.

FIFO 精确-一次处理 : 消息传递一次并保留 available until a consumer processes and deletes it. Duplicates are not introduced into the queue.

还要考虑是否真的需要“批处理”这些操作。如果一个晚上的更新比预期的大得多,会发生什么?即使使用动态资源,您的处理也可能会延迟,等待足够多的机器运行起来。相反,将数据存储在 SDB 中,通过 SQS 通知计算机更新,并动态创建 RSS 提要(使用缓存)。

批处理作业来自于处理资源有限且“实时”服务优先的时代。在云中,情况并非如此。

我注册了亚马逊黄金支持来问他们这个问题,这是他们的回答:

汤姆

我对我的一些同事做了一个简单的民意调查,结果一无所获 但是睡了一觉之后,我意识到重要的一步可能是 所以我查找了“分布式 cron 作业锁定” and found a reference to Zookeeper, an Apache project.

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 或类似的缓存的参考资料 mechanism as a way to create locks with a TTL. In this way you set a 标记,其 TTL 为300秒,并且不会执行其他 cron 工作程序 锁将在 TTL 完成任务之后自动释放 expired. This is conceptually very similar to the SQS option we 我们昨天讨论过了。

也可以看到,谷歌的胖乎乎的 Http://static.googleusercontent.com/external_content/untrusted_dlcp/research.google.com/en//archive/chubby-osdi06.pdf

Let me know if this helps, and feel free to ask questions, we are very 意识到我们的服务对于初学者来说是复杂和令人畏惧的 和经验丰富的开发商一样。我们总是乐于提供 架构和最佳做法建议。

Best regards,

亚马逊网络服务

小心使用 SQS 进行错误作业,因为它们不能保证“只有一台机器看到一个作业”。他们保证“至少有一个”会得到这个信息。

发信人: http://aws.amazon.com/sqs/faqs/#How_many_times_will_I_receive_each_message

问: 每条信息我会收到多少次?

AmazonSQS 被设计为在其队列中提供所有消息的“至少一次”传递。尽管在大多数情况下,每条消息只会传递到应用程序一次,但是您应该设计系统,以便多次处理一条消息不会产生任何错误或不一致。

到目前为止,我可以考虑这样一种解决方案: 安装了 GearmanJobServer 实例的一个实例: http://gearman.org/。在同一台机器上,您可以配置生成命令的 cron 作业来在后台执行 cronjob 任务。然后您的一个 Web 服务器(worker)将开始执行此任务,它保证只有一个 Web 服务器执行此任务。不管你有多少工人(特别是当你使用自动伸缩的时候)。

这种解决方案的问题是:

  • Gearman 服务器是单点故障,除非您将其配置为分布式存储,例如使用 memcached 或某个数据库
  • 然后使用多个 Gearman 服务器,你必须选择一个通过 cronjob 创建任务,所以我们又回到了同样的问题。但是如果你能忍受这种单点故障,使用 Gearman 看起来是个不错的解决方案。特别是你不需要大实例(在我们的例子中微实例就足够了)。

这是我第三次碰到这个问题了,我想我应该出一份力。我们已经进退两难了。我仍然觉得 真的 AWS 在这里缺少一个特性。

在我们的案例中,在考虑了可能的解决方案之后,我们决定有两个选择:

  • 建立一个 cronjob 服务器,它运行一次只能运行一次的作业,自动缩放它,并确保在某些 CloudWatch 统计数据不符合要求时替换它。我们使用 cloud-init脚本来运行 cronjob。当然,这会带来停机时间,导致错过 cronjob (当每分钟运行某些任务时,就像我们做的那样)。
  • Use the logic that rcron uses. Of course, the magic is not really in rcron itself, it's in the logic you use to detect a failing node (we use keepalived here) and "upgrade" another node to master.

我们决定采用第二种选择,仅仅是因为它非常快,而且我们已经有了运行这些 cronjob 的 Web 服务器的经验(在我们的 AWS 时代之前)。

Of course, this solution is meant specifically for replacing the traditional one-node cronjob approach, where timing is the deciding factor (e.g. “我希望作业 A 每天早上5点运行一次”, or like in our case “我希望作业 B 每分钟运行一次”). If you use cronjobs to trigger batch-processing logic, you should 真的 take a look at SQS. There's no active-passive dilemma, meaning you can use a single server or an entire workforce to process your queue. I'd also suggest looking at SWF for scaling your workforce (although auto scaling might be able to do the trick as well in most cases).

我们不想依赖第三方。

为什么要自己构建呢? 为什么不使用类似 Quartz (带有集群调度)的东西呢? 请参阅文档。

http://quartz-scheduler.org/documentation/quartz-2.x/configuration/ConfigJDBCJobStoreClustering

If you already have a Redis service up, this looks like a good solution:

Https://github.com/kvz/cronlock

阅读更多: http://kvz.io/blog/2012/12/31/lock-your-cronjobs/

我认为这个视频回答了你的确切问题-骗局的方式(可扩展和容错) :

在 Amazon 简单工作流中使用云中的 Cron

视频描述了使用实现 cronjob 的特定用例的 主权财富基金服务。

如果您直接使用 crontab,那么解决方案的相对复杂性可能难以接受。最后有一个案例研究帮助我理解了额外的复杂性给你带来了什么。我建议观察案例研究,并考虑您对可伸缩性和容错性的需求,以决定是否应该从现有的 crontab 解决方案迁移。

我们所做的是,我们有一个特定的服务器,是我们的网络应用程序集群的一部分后面的一个 ELB 也分配了一个特定的 DNS 名称,以便我们可以运行的一个特定的服务器上的作业。这样做的好处还有,如果这个作业导致服务器速度变慢,ELB 将从集群中删除它,然后在作业结束并恢复正常后返回它。

干得不错。

亚马逊刚刚为弹性豆茎增加了 释放的新功能:

AWS 弹性豆茎支持工作环境的周期性任务
运行预定义配置的环境中的层,该解决方案堆栈在容器名称中包含“ 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 有许多消息要处理,执行可能会延迟。

亚马逊在2月12日的博客中谈到了 使用 AWS Lambda 调度 SSH 作业,我认为这回答了这个问题。

如果您愿意使用非 AWS 服务,那么您可以查看 微软 Azure

因为没有人提到过 CloudWatch 事件,所以我认为它是 AWS 做 cron 作业的方式。它可以运行许多操作,如 Lambda 函数,ECS 任务。

验证 cron 表达式是否按 Amazon 方式工作的一种方法是通过 events 命令运行它。例如:

aws events put-rule --name "DailyLambdaFunction" --schedule-expression "<your_schedule_expression>

If your schedule expression is invalid, then, this will fail.

更多资源: https://docs.aws.amazon.com/cli/latest/reference/events/put-rule.html