批量更新队列

时间:2013-01-04 03:54:59

标签: google-app-engine

我看到更新特定实体类型的所有行的字段或值的一个非常常见的要求,它通常超过10分钟的队列限制。

那么,使用可以完成所有行更新的任务队列来运行cron作业的最佳方法是什么?

我尝试的方法之一是在cron作业中触发查询,然后创建多个大小相同的ID列表,比如说每个列表包含100个ID。然后通过传递id列表,为每个列表生成一个任务。然后在使用

创建实体行的任务代码中

pm.getObjectId然后处理它。

我仍然认为这种方法有点手动且不聪明。有没有更好的方法来处理它?<​​/ p>

2 个答案:

答案 0 :(得分:2)

如果您有现金可以燃烧,请使用后端;它们没有限制(虽然使用后端处理单个大型请求是浪费的......只有在你有其他工作可以卸载它时才考虑这个。)

更有可能的是,你真正想做的是分片。也就是说,将一个大的线性任务分解为一堆较小的,可并行化的任务。

一旦常见的模式,我经常使用一个请求就是调度......也就是说,查询你需要做的工作,收集一系列要操作的密钥,然后启动批量工作比方说,一次100个任务(发送尽可能多的数据,以避免重新查询,如果你不需要)。

这样,只有调度员必须导航整个数据集,而不执行任何耗时的更新,并且只要花费不到10分钟,您就应该是金色的。

现在,根据您的实体祖先设置,您可能会遇到尝试并行更新数千个实体的争用(如果您的调度程序太快,可能会发生这种情况)。简单的解决方案是设置.withCountDownMillis((延迟+ = 1000))来为每个请求提供大约一秒的呼吸空间(可能更多,具体取决于您的实体的大小和每个请求的索引数)。使用appstats对应用程序进行基准测试,看看每个实际需要多长时间,并为他们额外提供500左右的毫秒来覆盖标准偏差。

现在......我还想知道你在10分钟内工作的实体数量不够长......你使用的是异步api吗?批处理请求怎么样?如果您一次在一个实体上操作,并且每个实体阻止获取/放置,您将很容易达到限制。

相反,查看异步请求。使用异步,我能够触发一个看跌期权,藏匿未来,开除更多,然后当我最终确定未来时,操作已经完成,我基本上支付了0milli的墙上时间阻止请求。 / p>

即使您不能使用低级别异步(仍然强烈推荐),请至少考虑使用批次。也就是说,不是一次放置一个,而是使用一个列表并且每隔50个实体执行一次put + clear(如果它们很小则更多)。这允许appengine内部后端并行化所有50个,因此您需要为每个实体序列化开销支付1+的时间。

将异步和批处理与非争议实体相结合,我通常能够每分钟处理大约4000个实体。如果你必须做40,000多个实体,那么你需要研究正确的分片。为此,每个(任意选择)1000个实体获取一个密钥,并启动从先前密钥(或null)查询下一个密钥的任务。这使您可以在很短的时间内通过占用大量工作并将其转换为更小的工作来运行尽可能多的实体。

答案 1 :(得分:1)

我用它来更新任务队列10分钟限制内的数百万条记录:

  1. 创建一个循环,在每次迭代中运行query with cursor(不要使用offset())。在每次迭代中使用下一个游标。这样您就可以有效地遍历所有目标实体。每次使用limit(1000)获取一批1000个实体。同样set the prefetch size到1000以最小化网络往返。

  2. 对于每个批次,请更新属性,然后执行async put