Google App Engine可以保存并避免提取陈旧数据

时间:2014-09-04 22:36:25

标签: google-app-engine

我已经使用App Engine几年了,似乎一次又一次出现HDR的问题就是当你在一个屏幕上更新数据时,你有时会检索到旧的数据。如果在更新的第二个或两个内进行只读请求,则该屏幕的只读版本。我知道这已被讨论过herehere。我知道问题是什么,但我想知道适当的解决方案是什么?这是我可以获得过时数据的示例。

假设您构建了一个购物清单应用。

Entity 1: ShoppingList
Entity 2: ShoppingListItem

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

  1. 查询数据库并计算ShoppingListItem表中的项目数。
  2. 自动递增缓存的总字段数+/- 1,而不计算数据库。
  3. 使用这两种解决方案,您最终都会得到过时的数据。 #1可能已过期,因为添加/删除的原始保存可能尚未传播。因此查询将错过新记录。当您快速连续添加或删除多个项目时,#2将具有过时数据。总计更新为保存1,但在保存2时,保存1可能仍在传播,保存2的ShoppingList总计查询仍将反映保存1之前的原始状态。

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

    1. 使用缓存总计时,始终使用memcached实体。保存不会清除内存缓存,而是将更新的实体直接注入其中。这使memcache保持最新状态。这当然意味着没有访问memcache的查询(比如获取所有ShoppingList实体的列表)仍然可能返回过时数据。但至少在完成所有保存后,数据库中的缓存总数将是正确的。
    2. 处理这样一个事实,即您将要获得过时的数据,然后找出一种方法来在将来的某个时间清理它。安排TaskQueue重新查询ShoppingList并在10-30秒内更新总计,或者安排一个每30秒运行一次的Cron作业,并查找已更新的所有ShoppingList实体。
    3. 我倾向于解决方案#1。想法?

2 个答案:

答案 0 :(得分:4)

答案 1 :(得分:0)

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

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