【问题标题】:AppEngine achieving strong consistencyAppEngine 实现强一致性
【发布时间】:2016-08-25 08:48:56
【问题描述】:

我正在努力实现强一致性。让我们叫我的模型PVPPlayer

class PVPPlayer(ndb.Model):
    points = ndb.IntegerProperty()

模型的每个键都是这样创建的:

pvp_player = PVPPlayer(key=ndb.Key(Profile, "test_id", PVPPlayer, "test_id"))

Profile 是父模型:

class Profile(ndb.Model):
    def build_key(cls, some_id):
        return ndb.Key(cls, some_id)

我有 2 个 REST api 网址:

1) update_points
2) get_points

在 1) 我愿意:

# I use transaction because I have to update all the models in single batch 
@ndb.transactional(xg=True, retries=3)
def some_func(points):
    pvp_player = ndb.Key(Profile, "test_id", PVPPlayer, "test_id").get()
    pvp_player.points += points 
    pvp_player.put()
    # update other models here`

在 2) 我愿意:

pvp_player = ndb.Key(Profile, "test_id", PVPPlayer, "test_id").get()
return pvp_player.points`

我的流程如下所示:

1) update_points()
2) get_points()
3) update_points()
4) get_points()`
...

问题

使用get() 保证了强一致性,所以我不明白为什么有时get_points() 的结果是我得到过时的数据,比如点根本没有更新。

示例

POST get_points -> 0
POST sleep 1-3 sec
POST update_points -> 15
POST sleep 1-3 sec
POST get_points -> 15
POST sleep 1-3 sec
POST update_points -> 20
POST sleep 1-3 sec
POST get_points -> 15 !!!`

【问题讨论】:

  • 你的#2函数是否也用@ndb.transactional装饰?另外,我认为#1 中的update_points 函数名确实是update_points,对吧?
  • >你的#2 函数是否也用@ndb.transactional 装饰?我尝试为#2 添加@ndb.transactional 但没关系-它仍然不时给我陈旧的数据>#1 中的update_points 函数名称确实是update_points,对吗?绝对
  • 抱歉,我的意思是some_funcupdate_points? :)
  • 你可以调用 some_func "commit" 函数。它更新了 PVPPlayer 点并保存了一些其他模型,例如 PVPMatch(some_func 最多可以在 3 个实体组中运行),但我在这个请求中只更新了一次 PVPPlayer 模型。

标签: python google-app-engine eventual-consistency


【解决方案1】:

首先检查您的日志,其中一个更新一定是失败并出现错误,因为您的逻辑基本上是正确的。

还要仔细检查所有更新都包含在事务中以避免竞争。 Cloud Datastore: ways to avoid race conditions


此案例可能不是关于一致性问题,而是踩踏更新,请查看此链接以了解一些有趣的案例:

http://engineering.khanacademy.org/posts/transaction-safety.htm http://engineering.khanacademy.org/posts/user-write-lock.htm

【讨论】:

  • 我刚刚了解到我的一个请求与 update_points() 同时更新了我的父模型(即配置文件)。这看起来像个问题
  • 我必须分配不同的父键来避免这个问题吗?
  • 所有共享父键(包括父键)的东西都在同一个实体组中。
  • @PeterLeontev 将所有更新包装在事务中以避免竞争条件
【解决方案2】:

是否存在超出每个实体组的写入限制的情况,即每秒一次更新?我认为这可能会破坏文档中提到的实体组的强一致性。

【讨论】:

  • 物理播放器是唯一更新PVPPlayer模型的。根据游戏逻辑,根本不可能发生有人同时对同一个模型进行 2 个 update_points() 请求的情况
  • 实际上更奇怪的是,有时两个连续的 update_points() 之间有 15-20 秒的间隔,但数据仍然是陈旧的,所以它的行为与最终一致性完全一样,但我不明白为什么
猜你喜欢
  • 2013-03-25
  • 1970-01-01
  • 1970-01-01
  • 2015-06-05
  • 2021-09-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多