为非紧急工作配置任务队列和实例

时间:2018-03-06 23:19:00

标签: google-app-engine

我正在使用F4实例(因为内存需要)和自动调度来进行一些后台处理。它从任务队列运行。完成每次调用需要40到60秒。由于内存需求很高,每个实例一次只能处理一个请求。

需要采取的行动并不紧急。如果没有安排30分钟这不是问题。甚至60分钟是可以接受的,我宁愿利用那个时间而不是更多的实例。但是,如果服务变得流行并且每小时收到超过60个请求,我想调整更多实例以确保等待时间不超过60分钟。

我无法弄清楚如何配置实例和队列参数以降低成本但能够以这种方式扩展。我最初的想法是这样的:

<queue>
    <name>non-urgent-queue</name>
    <target>slow-service</target>
    <rate>1/m</rate>
    <bucket-size>1</bucket-size>
    <max-concurrent-requests>1</max-concurrent-requests>
</queue>


<automatic-scaling>
    <min-idle-instances>0</min-idle-instances>
    <max-idle-instances>0</max-idle-instances>
    <min-pending-latency>20m</min-pending-latency>
    <max-pending-latency>1h</max-pending-latency>
    <max-concurrent-requests>1</max-concurrent-requests>
</automatic-scaling>

首先,这些延迟设置无效,但我找不到有效范围或单位的文档。任何人都可以指导我这个信息吗?

其次,如果我正确理解了队列设置,那么即使任务队列有60多个作业在等待,此配置也会将其限制为每小时进入服务的60次调用。

感谢您的帮助!

2 个答案:

答案 0 :(得分:1)

实际上,在队列级别进行限制基本上会失去在需要时进行扩展的能力。因此,您无法使用您现在拥有的值在队列配置中使用<rate>,您需要使用与您愿意接受的最大费率相匹配的值(最大值为实例同时运行):

  • 可以通过队列限制为1 / min的最大请求率意味着您无法超过60 / h

  • 设置为<bucket-size>的{​​{1}}表示无法处理高于此速率的峰值(只要一个任务启动令牌桶清空)。

  • 设置为1的{​​{1}}基本上可以防止多个实例同时处理排队的工作负载。由于请求延迟,它们可能由自动缩放器启动,但由于一次只能处理一个队列任务,因此无法提供帮助。

<max-concurrent-requests>部分中1设置为<automatic-scaling>是好的 - 这可确保一次不会有多个实例处理多个请求 - 这就是您想要的。

坏消息是延迟的最大值似乎是15秒。至少在使用<max-concurrent-requests>配置python时(但我认为它不太可能因语言沙箱而异):

1

app.yaml

这也可能解释了为什么您的Error 400: --- begin server output --- automatic_scaling.min_pending_latency (30s), must be in the range [0.010000s,15.000000s]. --- end server output --- Error 400: --- begin server output --- automatic_scaling.max_pending_latency (60s), must be in the range [0.010000s,15.000000s]. --- end server output --- 值未被接受 - 我使用了5m1h并得到了上述错误。

这意味着您无法使用自动缩放参数来调整此类缓慢移动的处理。

我能想到的唯一选择是拥有2个队列:

  • 快速提供只会触发慢速服务作业的任务,但您的服务会拦截并保存在数据存储中。也许通过一些更快的服务来执行(你不希望这些服务器执行缓慢的服务执行,因为它可能会导致不必要的实例启动。也许,根据你实现的其余部分,你可以完全替换这个队列,只需要存储数据存储区中的作业信息,而不是快速队列中的任务。
  • 实际的慢服务作业执行任务的慢速

您还需要每分钟执行一次cron作业,检查数据存储区中待处理的触发器数量,确定在慢速队列中扩展和排队相应数量的慢速服务作业任务的数量。自动缩放器只会调出相应数量的实例(如果需要)。在这种情况下,需要低延迟自动缩放配置 - 您已经决定了如何扩展应用程序。

答案 1 :(得分:0)

这就是我最终这样做的方式。我使用慢速队列和像这样配置的快速队列:

<queue>
    <name>slow-queue</name>
    <target>pdf-service</target>
    <rate>2/m</rate>
    <bucket-size>1</bucket-size>
    <max-concurrent-requests>1</max-concurrent-requests>
  </queue>
<queue>
    <name>fast-queue</name>
    <target>pdf-service</target>
    <rate>10/m</rate>
    <bucket-size>1</bucket-size>
    <max-concurrent-requests>5</max-concurrent-requests>
</queue>

慢队列中的max-concurrent-requests确保一次只运行一个任务,因此只有一个实例处于活动状态。

在我发布到慢队列之前,我检查队列中已经有多少项目。结果可能不完全可靠,但就我的目的而言,这已经足够了。在java中:

QueueStatistics queueStats = queue.fetchStatistics();
if(queueStats.getNumTasks()<30) { 
   //post to slow queue
} else {
   //post to fast queue
}

因此,当我的慢速队列过满时,我会发送到允许并发请求的快速队列。

实例配置如下:

<automatic-scaling>
   <min-idle-instances>0</min-idle-instances>
   <max-idle-instances>automatic</max-idle-instances>
   <min-pending-latency>15s</min-pending-latency>
   <max-pending-latency>15s</max-pending-latency>
   <max-concurrent-requests>1</max-concurrent-requests>
</automatic-scaling>

因此它将尽可能慢地创建新实例(15秒是最大延迟)并确保一次只有一个进程在一个实例上运行。

使用这种配置,我一次最多可以有6个实例,但应该大约500 /小时。我可以提高速率和并发请求以做更多。

这种解决方案的负面影响是不公平的因素。在负载较重的情况下,某些任务将停留在慢队列中,而其他任务将在快速队列中更快地处理。

正因为如此,我已经将慢速队列中的最大项目减少到13,所以不公平不会那么极端,可能等待10分钟等待已满的慢队列的作业。