谷歌应用程序引擎保存和避免获取过时数据



我已经使用应用程序引擎几年了,HDR似乎一次又一次地出现一个问题,那就是当你在一个屏幕上更新数据时,如果在更新后的一两秒内发出只读请求,有时你会在该屏幕的只读版本上检索旧数据。我知道这里和这里都在谈论这个问题。我知道问题出在哪里,但我想知道合适的解决方案是什么?下面是一个示例,说明了我可能有过时数据的地方。

假设你建立了一个购物清单应用程序。

Entity 1: ShoppingList
Entity 2: ShoppingListItem

ShoppingList实体上有一个字段,用于保存列表中项目的总数。第二个实体是您的ShoppingListItem。添加或删除ShoppingListItem时,需要更新ShoppingList上的总数。有两种方法可以更新总数。

  1. 查询数据库并统计ShoppingListItem表中的项目数
  2. 自动递增缓存的总字段+/-1,而不计算数据库

使用这两种解决方案,最终都会得到过时的数据#1可能已过期,因为添加/删除的原始保存可能尚未传播。因此,查询将错过新记录#当您连续快速添加或删除多个项目时,2将具有过时的数据。已更新存储1的合计,但在存储2上,存储1可能仍在传播,并且对存储2的ShoppingList合计的查询仍将反映存储1之前的原始状态。

所以我的问题是,解决这个问题的正确方法是什么?对我来说,你似乎有两个选择:

  1. 当使用缓存的总数时,总是关闭memcached实体。Save不会清除memcache,而是直接将更新后的实体注入其中。这会使memcache保持最新。当然,这意味着没有命中memcache的查询(比如获取所有ShoppingList实体的列表)可能仍然会返回过时的数据。但至少在完成所有保存后,数据库中缓存的总数是正确的
  2. 处理这样一个事实,即你将拥有过时的数据,但在未来某个时候想办法清理它。安排一个TaskQueue重新查询ShoppingList并在10-30秒内更新总数,或者安排一个每30秒运行一次的Cron作业,查找所有已更新的ShoppingList实体

我倾向于解决方案#1。想法?

选项3是https://developers.google.com/appengine/docs/java/datastore/structuring_for_strong_consistency和https://developers.google.com/appengine/docs/java/datastore/structuring_for_strong_consistency仔细阅读。你所遇到的是"最终一致性"的典型表现。请特别注意实体组和祖先查询。

我认为在大多数情况下@david-w-shmith的答案是正确的。然而,我在对他的回答的评论中提到,使用实体组有很大的局限性。该限制是实体组每秒只能处理一次写入。这对于只有少数用户的应用程序来说可能很好,但对于社交网络来说是不可接受的。

正如谷歌文档所建议的那样(https://developers.google.com/appengine/docs/java/datastore/structuring_for_strong_consistency),我已经使用memcache实现了一个相当极端的缓存实现。所有shoppingList查询结果都存储在缓存中,当列表被更新、添加或删除时,我也会更新缓存中查询结果的状态。我担心维护两个数据副本(数据库和memcache)的自然复杂性,但这正是UnitTest的作用所在。正确的

最新更新