如何将Linux定时任务转换为“亚马逊方式”?

117
我们已将整个LAMP Web应用程序从专用机器迁移到云端(Amazon EC2机器),这或许是好事,但我们处理crons的方式不够优秀。我有一个关于如何使用“亚马逊方式”在云中最佳管理cron作业的问题。
问题:我们有多个Web服务器,并需要运行批处理作业的cron,例如创建RSS提要,触发电子邮件等很多不同的任务。但是cron作业只需要在一台机器上运行,因为它们经常写入数据库,如果在多台机器上运行,会导致结果重复。
到目前为止,我们指定其中一台Web服务器为“主Web服务器”,并且它有一些其他Web服务器没有的“特殊”任务。云计算的权衡是可靠性-我们不想要“主Web服务器”,因为它是单点故障。我们希望它们都是相同的,并且能够升级和降级,而无需记住不将主Web服务器从集群中删除。
如何重新设计我们的应用程序以将Linux cron作业转换为临时工作项,从而消除单点故障?
到目前为止,我的想法有:
  • 有一台专门运行cron的机器。这会更容易管理,但仍然存在单点故障,并且会浪费一些额外的实例。
  • 一些工作可以从Linux crons移动到MySQL Events,但我不太喜欢这个想法,因为我不想将应用程序逻辑放入数据库层。
  • 也许我们可以在所有机器上运行所有的crons,但更改我们的cron脚本,让它们都以实现锁定机制的一小段逻辑开始,这样只有一个服务器实际上采取行动,其他服务器则跳过。我不太喜欢这个想法,因为它听起来可能存在漏洞,我更愿意使用Amazon最佳实践而不是自己编写。
  • 我想象一种情况,工作被安排在某个地方,加入队列,然后Web服务器可以成为工作者之一,可以说“嘿,我会处理这个”。Amazon Simple Workflow Service听起来像这种东西,但我目前对此了解不多,因此任何具体信息都会有所帮助。它似乎对于像cron这样简单的东西来说有点重量级?它是正确的服务还是有更合适的Amazon服务?

更新:自从我提出这个问题后,我在YouTube上观看了Amazon Simple Workflow Service网络研讨会,并注意到在34:40(http://www.youtube.com/watch?v=lBUQiek8Jqk#t=34m40s),我瞥见一张幻灯片提到cron作业作为一个示例应用程序。在他们的文档页面“AWS Flow Framework samples for Amazon SWF”中,亚马逊表示他们有cron的示例代码:

... > Cron jobs 在这个示例中,一个长时间运行的工作流定期执行一个活动。演示了继续执行作为新执行的能力,以便执行可以运行非常长的时间。 ...

我下载了适用于Java的AWS SDK(http://aws.amazon.com/sdkforjava/),在一堆荒谬的文件夹中,确实有一些Java代码(aws-java-sdk-1.3.6/samples/AwsFlowFramework/src/com/amazonaws/services/simpleworkflow/flow/examples/periodicworkflow)。
问题是说实话,这并没有真正帮助我,因为它不是我可以轻松理解的技能范围内的东西。PHP SDK中缺少相同的示例,并且似乎没有教程可以详细介绍该过程。所以基本上,我仍在寻找建议或提示。

2
可能相关:https://dev59.com/UWoy5IYBdhLWcg3wCpsz - Ilmari Karonen
13个回答

39

我向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工作程序将执行该作业。锁将在TTL过期后自动释放。从概念上讲,这与我们昨天讨论的SQS选项非常相似。

还可以参见:Google的chubby http://static.googleusercontent.com/external_content/untrusted_dlcp/research.google.com/en//archive/chubby-osdi06.pdf

如果这有所帮助,请让我知道,并随时提出问题。我们非常清楚我们的服务可能对初学者和经验丰富的开发人员来说都很复杂和令人生畏。我们始终乐于提供架构和最佳实践建议。

最好的问候,

Ronan G. Amazon Web Services


1
“看到 Google 的 Chubby” 这个表达在 SO 上,说实话,我是没想到的。 - crthompson

13

我认为这个视频可以回答你的问题 - 用 AWS 的方式执行 cronjobs(可扩展和容错):

使用 Amazon Simple Workflow 在云中使用 Cron

视频介绍了SWF服务,以实现cronjobs为特定用例。

如果你直接从crontab过来,相对复杂的解决方案可能难以接受。在视频最后有一个案例研究,可以帮助你理解额外复杂度所带来的好处。我建议观看案例研究并考虑你的可扩展性和容错需求,以决定是否应该迁移到现有的crontab解决方案。


3
这是一个很好的答案,因为它使用了 AWS 的一个受支持很好的工具,SWF 是一个很强大的产品。唯一的缺点,在我看来,就是 SWF 有一个相当大的学习曲线,可能难以处理复杂的任务。至少在 Java 教程中,那是我的经验。 - Don Cheadle

12

使用SQS作为cronjobs需要小心,因为它们不能保证“一个任务仅被一个机器看到”。它们只能保证“至少有一个”会得到消息。

参考自:http://aws.amazon.com/sqs/faqs/#How_many_times_will_I_receive_each_message

问:每条消息将被接收多少次?

Amazon SQS被设计为在其队列中提供“至少一次”的所有消息交付。虽然大多数情况下,每个消息都将被准确地传递到您的应用程序一次,但您应该设计系统,使得对消息的处理多次不会创建任何错误或不一致性。

目前我想到的解决方案是,在一个已安装Gearman Job Server实例的服务器上进行配置: http://gearman.org/。在同一台机器上,您配置产生命令以在后台执行cronjob任务的cron jobs。然后,您的Web服务器(工作者)之一将开始执行此任务,并保证只有一个工作者将获取任务。无论您有多少工作者(特别是当您使用自动缩放时),这都没有关系。

这个解决方案的问题是:

  • Gearman服务器是单点故障,除非您使用分布式存储(例如使用memcached或某些数据库)进行配置
  • 然后使用多个Gearman服务器,您必须选择一个通过cronjob创建任务,因此我们又回到了同样的问题。但是,如果您可以接受这种单点故障,则使用Gearman看起来是相当不错的解决方案。特别是您不需要大型实例(在我们的情况下,微实例已足够)。

好的,这些消息在被接收后会留存在服务器上。删除它们的责任在于开发人员。在处理过程中,其他服务器无法访问它们。 - Frederik Wordenskjold
2
@FrederikWordenskjold 这是不正确的,即使消息已经被发送给一个客户端,它仍然可以被发送给另一个客户端,因为 SQS 状态的复制是异步的。你甚至可以在消息被删除后“再次”收到它的副本! - Chris Pitman
此答案已过时。现在有两种类型的队列。使用FIFO以获得精确一次处理:消息仅传递一次,并保持可用状态,直到消费者处理并删除它。不会向队列中引入重复项。https://aws.amazon.com/sqs/features/ - Lukas Liesis

11

亚马逊刚刚发布了 Elastic Beanstalk 的新功能。根据文档:

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有许多消息要处理,则执行可能会延迟。

能否在翻译中包含一些链接内容? - Robert

6

1
使用AWS Lambda是否可以添加动态cronjobs或计划任务? - Sanjay Kumar N S
是的,您可以通过Cloudwatch事件调用Lambda。根据需要进行时间设置。 - Michael Quale

6
我已经第三次遇到这个问题,想要提供一些帮助。我们一直在面临这个困境。我仍然真的认为AWS在这里缺少一个功能。
在我们的情况下,在查看可能的解决方案后,我们决定有两个选择:
  • 设置一个cronjob服务器,运行那些应该一次只运行一个作业的作业,自动扩展它,并确保在某些CloudWatch统计数据不正确时替换它。我们使用cloud-init脚本来启动cronjobs。当然,这会导致停机时间,从而导致错过cronjobs(例如每分钟运行某些任务,就像我们所做的那样)。
  • 使用rcron使用的逻辑。当然,魔法并不真正在于rcron本身,而是在于您用于检测失败节点的逻辑(我们在这里使用keepalived)并将另一个节点“升级”为主节点。
我们决定选择第二个选项,因为它非常快速,而且我们已经有了在我们的pre-AWS时代运行这些cronjobs的经验。
当然,此解决方案专门用于替换传统的单节点cronjob方法,其中时间是决定因素(例如“我希望任务A每天早上5点运行一次”,或者像我们的情况一样“我希望任务B每分钟运行一次”)。如果您使用cronjobs触发批处理逻辑,则应该真的查看SQS。没有主动-被动困境,这意味着您可以使用单个服务器或整个工作队伍来处理队列。我还建议查看SWF以扩展您的工作队伍(尽管在大多数情况下,auto scaling也可以胜任)。
依赖另一个第三方是我们想避免的事情。

4

4
“亚马逊”的方法是分布式的,这意味着笨重的 crons 应该被拆分成许多小作业并交给正确的机器处理。使用类型设置为 FIFO 的 SQS 队列将其粘合在一起,以确保每个作业仅由一台机器执行。它还容忍故障,因为队列将缓冲,直到机器重新启动。

FIFO 精确一次性处理:消息只传递一次,并保持可用状态,直到消费者处理并删除它。不会向队列中引入重复项。

此外,请考虑是否真的需要“批量”这些操作。如果某个晚上的更新比预期的大得多,会发生什么?即使使用动态资源配置,您的处理也可能会因等待足够的机器启动而延迟。相反,将数据存储在 SDB 中,通过 SQS 通知机器进行更新,并根据需要创建 RSS 源(带有缓存)。
批处理作业来自处理资源有限且“实时”服务优先的时代,在云中,情况并非如此。

谢谢 - 我喜欢你描述的方向。 - Tom
5
请注意,SQS仅保证消息最终会被某个机器看到,而不是只会被单个服务器看到。您放入SQS队列中的任何内容都应该具有幂等性。 - Richard Hurt
我的定时任务应该每天运行,而使用 SQS 只能延迟最多 15 分钟。一个选项是向消息添加自定义标签以指定执行目标时间,如果尚未到达该时间,则将其放回队列 - 但这看起来真的很愚蠢。此外,我仍然需要一个定时任务来最初填充队列。这似乎是一个鸡生蛋的问题 :) 但我仍然认为 SQS 是正确的选择,因为它保证了可扩展性和容错性。 - Raffaele Rossi
批处理作业源于处理资源有限且“实时”服务优先的时代。在云中,情况并非如此。这对某些活动是正确的,但并非所有活动都适用。例如,处理流量日志比实时处理更适合作为批处理过程。 - Jordan Reiter
我来晚了,但我认为更好的方法是使用预定的CloudWatch事件作为corn“ping”的行动。这可以发布一个SNS主题,由队列订阅,如果需要确切地传递一次,则队列本身可以是FIFO队列。当然还有一些复杂性,但对我来说,这看起来像一个不错的系统! - ankush981

1

验证您的cron表达式是否符合亚马逊的方式之一是通过events命令运行它。例如:

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

如果您的计划表达式无效,则此操作将失败。

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


1
我们所做的是,在ELB后面,有一台特定的服务器作为我们Web应用程序集群的一部分,并分配了一个特定的DNS名称,以便我们可以在该特定服务器上运行作业。这也有一个好处,即如果该作业导致该服务器变慢,ELB将从集群中删除它,然后在作业结束并且它再次变得健康时将其返回。
像冠军一样运作。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接