如何将Linux cron作业转换为“亚马逊方式”?

How to convert Linux cron jobs to “the Amazon way”?

无论好坏,我们都将整个LAMP Web应用程序从专用机器迁移到了云(AmazonEC2机器)。到目前为止进展不错,但是我们处理crons的方式是次优的。我有一个亚马逊特有的问题,关于如何使用"亚马逊方式"来最好地管理云中的cron作业。

问题是:我们有多个WebServer,需要运行cron来执行批处理作业,比如创建RSS提要、触发电子邮件,实际上还有许多不同的事情。但是cron作业只需要在一台机器上运行,因为它们通常会写入数据库,因此如果在多台机器上运行,结果会重复。

到目前为止,我们将其中一个Web服务器指定为"主Web服务器",它有一些其他Web服务器没有的"特殊"任务。云计算的权衡是可靠性——我们不需要"主Web服务器",因为它是单一故障点。我们希望它们都是相同的,并且能够在不记住不将主Web服务器从集群中取出的情况下进行上下扩展。

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

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

  • 有一台专门用来运行cron的机器。这将是一个更容易管理,但仍将是一个单一的失败点,并将浪费一些钱有一个额外的实例。
  • 有些作业可以从Linux crons迁移到MySQL事件,但是我不太喜欢这个想法,因为我不想将应用程序逻辑放入数据库层。
  • 也许我们可以在所有的机器上运行所有的cron,但要更改cron脚本,以便它们都从实现锁定机制的一点逻辑开始,这样只有一个服务器实际执行操作,而其他服务器则跳过。我不喜欢这个想法,因为它听起来可能有问题,我宁愿使用亚马逊的最佳实践,而不是滚动我们自己的。
  • 我在想象这样一种情况:工作安排在某个地方,添加到一个队列中,然后WebServer可以每个人都是一个工人,可以说"嘿,我要这个"。亚马逊简单的工作流服务听起来正是这样,但我目前对它知之甚少,所以任何细节都会有帮助。对于像克罗恩这样简单的人来说,这似乎有点重?这是正确的服务还是有更合适的亚马逊服务?

更新:自从问到这个问题后,我在YouTube上观看了亚马逊简单工作流服务网络研讨会,并在34:40(http://www.youtube.com/watch)时注意到了这个问题。v=lbuqiek8jqk t=34m40s)我看到一张幻灯片,上面提到cron jobs是一个示例应用程序。在他们的文档页面"亚马逊SWF的AWS流框架示例"中,亚马逊说他们有crons的示例代码:

...
> Cron jobs In this sample, a long running workflow periodically
executes an activity. The ability to continue executions as new
executions so that an execution can run for very extended periods of
time is demonstrated.
...

我为Java下载了AWS SDK(HTTP:/AWS.Ax.On.COM/SDKFojava/),并且确实隐藏在一个荒谬的文件夹层中,有一些Java代码(EDOCX1,0)。

问题是,如果我诚实的话,这真的没有帮助,因为这不是我可以用我的技能轻松消化的东西。PHP SDK中缺少相同的示例,并且似乎没有一个教程可以指导整个过程。所以,基本上,我仍在寻求建议或小费。


我报名参加亚马逊黄金支持,问他们这个问题,这是他们的回答:

Tom

I did a quick poll of some of my colleagues and came up empty on the
cron, but after sleeping on it I realised the important step may be
limited to locking. So I looked for"distributed cron job locking"
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

Also I have seen reference to using memcached or a similar caching
mechanism as a way to create locks with a TTL. In this way you set a
flag, with a TTL of 300 seconds and no other cron worker will execute
the job. The lock will automatically be released after the TTL has
expired. This is conceptually very similar to the SQS option we
discussed yesterday.

Also see; Google's chubby
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
aware that our services can be complex and daunting to both beginners
and seasoned developers alike. We are always happy to offer
architecture and best practice advice.

Best regards,

Ronan G. Amazon Web Services


我认为这段视频回答了你的确切问题——cronjobs的AWS方式(可扩展和容错):

在云端使用cron和Amazon简单工作流

视频描述了使用实现cronjobs的特定用例的SWF服务。

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


对于cronjobs使用sqs要小心,因为它们不能保证"一台机器只能看到一个作业"。他们保证"至少有一个"会收到消息。

发件人:http://aws.amazon.com/sqs/faqs/我将收到多少条信息?

Q: How many times will I receive each message?

Amazon SQS is engineered to provide"at least once" delivery of all messages in its queues. Although most of the time each message will be delivered to your application exactly once, you should design your system so that processing a message more than once does not create any errors or inconsistencies.

到目前为止,我可以考虑一个安装了gearman job server实例的解决方案:http://gearman.org/。在同一台机器上,您配置生成命令的cron作业,以便在后台执行cronjob任务。然后,您的一个Web服务器(工作人员)将开始执行此任务,它保证只有一个服务器会执行此任务。你有多少员工并不重要(尤其是当你使用自动缩放时)。

此解决方案的问题是:

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


亚马逊刚刚发布了弹性豆茎的新功能。从文档中:

AWS Elastic Beanstalk supports periodic tasks for worker environment
tiers in environments running a predefined configuration with a solution stack that contains"v1.2.0" in the container name."

现在,您可以创建一个环境,其中包含配置调度任务的cron.yaml文件:

1
2
3
4
5
6
7
8
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有许多消息要处理,那么执行可能会延迟。


2016年2月12日,Amazon写了一篇关于使用aws lambda调度ssh作业的博客。我想这回答了问题。


我第三次碰到这个问题,以为我会插嘴。我们已经有一段时间进退两难了。我仍然觉得AWS在这里缺少一个特性。

在我们的案例中,在研究了可能的解决方案后,我们决定我们有两种选择:

  • 设置一个cronjob服务器,运行一次只能运行一次的作业,自动缩放它,并确保当某些cloudwatch统计数据不符合它们的要求时,替换它。我们使用cloud-init脚本来运行cronjobs。当然,这会导致停机,导致错过cronjobs(像我们一样,在每分钟运行某些任务时)。
  • 使用rcron使用的逻辑。当然,魔力并不在rcron本身,而是在你用来检测一个失败节点(我们在这里使用keepalived并"升级"另一个要控制的节点的逻辑中。

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

当然,这个解决方案专门用于替换传统的单节点cronjob方法,其中时间是决定因素(例如,"我希望作业A每天早上5点运行一次",或者在我们的示例中,"我希望作业B每分钟运行一次")。如果您使用cronjobs来触发批处理逻辑,那么您真的应该看看SQS。没有主动-被动的两难选择,这意味着您可以使用单个服务器或整个劳动力来处理您的队列。我也建议你考虑一下SWF来扩大你的劳动力规模(尽管auto scaling在大多数情况下也能做到这一点)。

我们要避免依赖于另一个第三方。


如果您已经开通了Redis服务,这看起来是一个很好的解决方案:

https://github.com/kvz/cronlock

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


"Amazon"的方式是分布式的,这意味着大块头的cron应该被分割成许多小的工作,然后交给合适的机器。使用SQS将其粘合在一起,确保每个作业只被一台机器看到。它还可以容忍失败,因为队列将缓冲,直到机器重新启动。

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

批处理作业是在处理资源有限且"实时"服务优先的情况下进行的。在云中,情况并非如此。


我们要做的是,我们有一个特定的服务器,它是ELB后面的Web应用程序集群的一部分,还分配了一个特定的DNS名称,以便我们可以在该特定的服务器上运行作业。这样做的好处是,如果该作业导致服务器速度减慢,ELB会将其从集群中删除,然后在作业结束并再次恢复健康后将其返回。

像冠军一样工作。


你为什么要自己建造?为什么不使用Quartz之类的东西(使用集群调度)。参见文档。

http://quartz-scheduler.org/documentation/quartz-2.x/configuration/configjdbcjobstore集群


由于没有人提到CloudWatch事件,我想说这是AWS做cron工作的方式。它可以运行很多操作,比如lambda函数、ecs任务。


如果您愿意使用非AWS服务,那么您可以查看Microsoft Azure。Azure提供了一个很好的作业调度程序。