首页 > 解决方案 > 组合 cron 作业以减少实例数量

问题描述

假设我有 3 个请求:

@app.route('/schedulejob1/')
def schedulejob1():
   for pram in prams1:
     deferred.defer(scheduletjob1Task,pram)
   return 'Running'
@app.route('/schedulejob1/')
def schedulejob1():
   for pram in prams2:
     deferred.defer(scheduletjob1Task,pram)
   return 'Running'
@app.route('/schedulejob1/')
def schedulejob1():
   for pram in prams3:
     deferred.defer(scheduletjob1Task,pram)
   return 'Running'

所以我的 cron.yaml 是

cron:
- description: Run schedule job1
  url: /schedulejob1/
  schedule: every 1 minutes
- description: Run schedule job2
  url: /schedulejob2/
  schedule: every 1 minutes
- description: Run schedule job3
  url: /schedulejob3/
  schedule: every 1 minutes

这种方法每分钟将有 3 个请求,因此 gae 很有可能会动态创建更多实例,这会增加(实例 x 前端/后端小时数)的成本。

我的计划是将 3 个请求放入一个请求中:

@app.route('/schedulejobs/')
def schedulejobs():
   for pram in prams1
     deferred.defer(scheduletjob1Task,pram)
   for pram in prams2  
     deferred.defer(scheduletjob2Task,pram)
   for pram in prams3 
     deferred.defer(scheduletjob3Task,pram)

接着

 cron:
    - description: Run schedule jobs
      url: /schedulejobs/

第二种方法是否有助于减少请求数量?因此降低成本?

我的目标是将一个请求分成多个任务队列,每个任务队列在不到 1 分钟的时间内运行,并且它可以永久失败(或者可以重试 1 次)。我还将在后端实例上放置一半的 cron 作业,以利用 9 小时的空闲时间。

如果您有任何想法如何减少实例时间,请提供建议。

标签: google-app-engine

解决方案


是的,具有重叠计划的 cron 作业可能会导致潜在的不必要的活动高峰,这可能会增加实例时间。不仅您平均每分钟有 3 个请求,而且在那一分钟开始时,您的应用程序的请求队列中同时有 3 个请求。如果您使用自动/基本扩展配置,GAE 可能会决定生成额外的实例以保持较低的请求延迟,即使单个实例可以轻松处理平均每分钟 3 个请求。

旁注:您已经有 cron 请求进入以触发作业,您有点不必要地创建另一个(任务队列)请求来实际执行作业(因此在您的情况下相当于每分钟 6 个请求),为什么不只是直接从 cron 处理程序执行作业?

现在,如果每个请求都需要将近 1 分钟才能完成交错,那么它们将无济于事 - @MatrixTai 的评论适用。

但是,如果所有 3 个作业的总执行时间低于 1 分钟,则错开它们将有助于降低成本。在这种情况下,也许更好的方法是不要再创建 3 个请求 - 缺点是您仍然需要仔细配置延迟以确保它们不会重叠,而只需按顺序执行 3 个作业,而不将新请求排队(这就是我所做的):

@app.route('/per_minute_jobs/')
def handle_per_minute_jobs():  # OK if the combined execution time is < 1 min
     execute_job_1()
     execute_job_2()
     execute_job_3()

使用这种方法,您每分钟恰好有 1 个请求,它本身不能像其他方法那样触发产生新实例。

现在,组合作业执行可能需要比典型(非 cron)请求处理更长的时间。如果您在同一个 GAE 服务中同时处理它们,您最终仍然会运行至少 2 个实例,即使总体而言您的应用程序的平均流量足够低,显然可以仅使用一个实例来处理。

更新:

好的,既然你必须在后续任务中拆分工作,只需使用deferred.defer()'s optionalcountdownetaargs 及时错开这些任务并平滑那些活动峰值。


推荐阅读