我为博客/新闻网站编写代码。主页有 10 篇最新文章,还有一个存档部分,所有文章按修改时间降序排列。在存档部分,我使用基于游标的分页,并且我从第二页开始缓存结果,因为仅当新文章发布或现有文章出于某种原因进入草稿时页面才会更改。每页有 10 篇文章。因此,当用户访问带有某个编号(不是第一个)的存档页面时,首先会检查内存缓存以获取该页码结果。如果页面不存在,则检查内存缓存以查找该页面的游标,然后使用该游标从数据存储中获取结果:
class archivePage:
def GET(self, page):
if not page:
articles = memcache.get('archivePage')
if not articles:
articles = fetchArticles()
memcache.set('archivePage', articles)
else:
if int(page) == 0 or int(page) == 1:
raise web.seeother('/archive')
articles = memcache.get('archivePage'+page)
if not articles:
pageCursor = memcache.get('ArchivePageMapping'+page)
if not pageCursor:
pageMapping = ArchivePageMapping.query(ArchivePageMapping.page == int(page)).get()
pageCursor = pageMapping.cursor
memcache.set('ArchivePageMapping'+page, pageCursor)
articles = fetchArticles(cursor=Cursor(urlsafe=pageCursor))
memcache.set('archivePage'+page, articles)
每次创建新文章或更改现有文章的状态(草稿/已发布)时,我都会刷新存档页面结果和游标的缓存。我在将文章保存到数据存储后执行此操作:
class addArticlePage:
def POST(self):
formData = web.input()
if formData.title and formData.content:
article = Article(title=formData.title,
content=formData.content,
status=int(formData.status))
key = article.put()
if int(formData.status) == 1:
cacheArchivePages()
raise web.seeother('/article/%s' % key.id())
def cacheArchivePages():
articles, cursor, moreArticles = fetchArticlesPage()
memcache.set('archivePage', articles)
pageNumber=2
while moreArticles:
pageMapping = ArchivePageMapping.query(ArchivePageMapping.page == pageNumber).get()
if pageMapping:
pageMapping.cursor = cursor.urlsafe()
else:
pageMapping = ArchivePageMapping(page=pageNumber,
cursor=cursor.urlsafe())
pageMapping.put()
memcache.set('ArchivePageMapping'+str(pageNumber), cursor.urlsafe())
articles, cursor, moreArticles = fetchArticlesPage(cursor=cursor)
memcache.set('archivePage'+str(pageNumber), articles)
pageNumber+=1
问题来了。有时(没有规律,它是随机发生的)刷新缓存后,我得到与刷新前相同的存档页面结果和游标。例如我添加了一篇新文章。它保存在数据存储中,并出现在首页和存档的第一页上(存档的第一页未缓存)。但是其他存档页面没有更新。我已经测试了我的 cacheArchivePages() 函数,它按预期工作。会不会是在我对数据存储区进行 put() 更新之后和在 cacheArchivePages() 函数中的 fetchArticlesPage() 之前耗时太少?也许写事务还没有完成,所以我得到了旧的结果?我尝试使用 time.sleep() 并在调用 cacheArchivePages() 之前等待几秒钟,在那种情况下我无法重现该行为,但在我看来 time.sleep() 不是一个好主意。无论如何,我需要知道该行为的确切原因以及如何处理它。
最佳答案
您很可能会遇到“最终一致的查询”。当使用 HR 数据存储时,查询可能会使用稍旧的数据,并且需要一段时间才能让 put() 写入的数据对查询可见(对于 get() by key 或 id 则没有这样的延迟)。延迟通常以秒为单位,但我认为我们不能保证上限——我想,如果您遇到不幸的网络分区,可能需要数小时。
有各种各样的部分解决方案,从最近写入的作者查看查询结果时作弊到使用祖先查询(它们有自己的局限性)。您可以简单地为您的缓存提供一个有限的生命周期,并在读取而不是写入时更新它。
祝你好运!
关于python - put() 后 App Engine 数据存储中的读取延迟,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11063597/