GAE 数据存储的模式迁移
首先,这是我在Stack Overflow上的第一篇帖子,请原谅我可能犯的任何新手错误。如果我在提问时可以更清楚,请告诉我。
我在Google App Engine上运行一个大型应用程序,最近添加了一些新功能,这让我不得不修改旧的数据类并添加新的类。为了清理我们的数据库并更新旧的条目,我一直在尝试写一个脚本,可以遍历一个类的实例,进行修改,然后重新保存它们。问题是,当你对服务器的调用超过几秒钟时,Google App Engine会超时。
我为这个问题挣扎了好几周。我找到的最佳解决方案在这里:http://code.google.com/p/rietveld/source/browse/trunk/update_entities.py?spec=svn427&r=427
我为自己的网站创建了一个版本的代码,你可以在这里看到:
def schema_migration (self, target, batch_size=1000):
last_key = None
calls = {"Affiliate": Affiliate, "IPN": IPN, "Mail": Mail, "Payment": Payment, "Promotion": Promotion}
while True:
q = calls[target].all()
if last_key:
q.filter('__key__ >', last_key)
q.order('__key__')
this_batch_size = batch_size
while True:
try:
batch = q.fetch(this_batch_size)
break
except (db.Timeout, DeadlineExceededError):
logging.warn("Query timed out, retrying")
if this_batch_size == 1:
logging.critical("Unable to update entities, aborting")
return
this_batch_size //= 2
if not batch:
break
keys = None
while not keys:
try:
keys = db.put(batch)
except db.Timeout:
logging.warn("Put timed out, retrying")
last_key = keys[-1]
print "Updated %d records" % (len(keys),)
奇怪的是,这段代码在处理100到1000个实例的类时运行得非常好,脚本通常需要大约10秒。但当我尝试在数据库中处理大约10万个实例的类时,脚本运行了30秒,然后我收到了这个错误:
“错误:服务器错误
服务器遇到错误,无法完成你的请求。如果问题持续存在,请报告你的问题,并提到这个错误信息和导致它的查询。”
你知道为什么GAE在正好30秒后会超时吗?我该怎么解决这个问题?
谢谢你!
Keller
2 个回答
你解决问题的第一步是使用GAE的任务队列。这个功能可以让你把一些工作放到后面再做。
不过,这样做并不能立刻解决问题,因为任务队列也有时间限制。你可以把你的循环展开,每次处理数据库中的几行数据。每处理完一批数据,就可以检查一下运行了多久,如果时间够了,就可以在队列里启动一个新任务,继续从当前任务停止的地方接着做。
另外一种解决方案是不迁移数据。你可以改变实现逻辑,让每个实体知道自己是否已经迁移。新创建的实体或者被更新的旧实体会采用新的格式。因为GAE不要求所有实体都有相同的字段,所以这样做很简单,而在关系型数据库中,这样做就不太实际了。
听起来你遇到了第二个DeadlineExceededError错误。AppEngine的请求每次只能运行30秒。当出现DeadlineExceededError错误时,你需要停止处理并整理一下,因为时间快用完了。下次再出现这个错误时,你就无法再捕捉到它了。
你可以考虑使用Mapper API,把你的迁移任务分成几个小批次,然后通过任务队列来运行每个批次。