2012-03-14 96 views
0

我有一个设计问题,我的应用程序有一个成长的流量,我有很多“交易冲突。重试...”。我不知道如何避免他们。避免数据存储竞争

介绍: 这个应用程序中的每个演员都可以访问另一个演员。

这是我的实际设计(它可以有错误,它只是一个例子)

class Actor(object): 
    name = db.StringProperty() 

class ActorVisits(object): 
    """Store a list of all actors has visited the parent of this kind 

    Note: Has an ancestor an Actor 
    """ 
    visits = db.ListProperty(db.Key) 

class Visit(object): 
    """A new visit by actor on the parent of this kind. 
    Each time a same actor visits the parent of this kind, this kind is updated 
    with the new datetime for the visit. 

    Note: Has an ancestor an Actor 
    """ 
    actor = db.ReferenceProperty(collection_name=Actor) 
    visited_at = db.datetimeProperty() 

也就是说使用情况的一个例子:

foo = Actor(name="foo") 
bar = Actor(name="bar") 

db.put([foo, bar]) 

def trx(): 
    """Store a new visite from 'bar' to 'foo' """ 

    av = ActorVisits.get_bey_keys_name(key_name="v/foo", parent=foo) 
    if av is None: 
    av = ActorVisits(key_name="v/foo", parent=foo) 

    v = Visit.get_bey_keys_name(key_name="v/foo/bar", parent=foo, actor=bar) 
    if v is None: 
    v = Visit(key_name="v/foo/bar", parent=foo, actor=bar) 
    v.visited_at = datetime.datetime.utcnow() 
    async = db.put_async(v) 

    if not v.key() in av.visits: 
    av.visits.append(v.key()) 
    av.put() 

    async.get_result() 

db.run_in_transaction(trx, bar, foo) 

如果有人有一个想法对我来说,让这个模型更好。谢谢

+0

我假设你没有实际使用硬编码的key_name字符串,当你搜索你的ActorVisits和Vist?这意味着你总是只修改一个ActorVisits对象。 – dragonx 2012-03-14 14:13:33

+0

@dragonx:是的,这只是我写得很快的一个例子。 – sahid 2012-03-14 14:17:43

回答

2

通过将访问移出Actor的EntityGroup,使访问最终保持一致。如果每次访问都是根实体,则不会遇到任何写入速率问题,您可以轻松查询它们。

如果您不想创建大量访问实体,但只需更新一个访问实体,则可以通过将访问实体与演员和访问者区分开来,确定访问确定性的关键。

所以演员有123标识, 位访客(其他演员)有888标识,

你让类型访问的关键,用 “123_888”(无父),你把ID()的使用此密钥访问并更新时间,并覆盖以前的访问。你也可以在键上做一个get(),并且它会非常一致(如果你保持一个计数说)。

然后,您可以使用最终一致的查询来构建ActorVisits。

+0

请注意,根实体也可能存在争用问题 – systempuntoout 2012-05-27 19:47:15