2011-09-04 27 views
1

我正在写一个使用谷歌应用程序引擎的错误数据库,我遇到了问题得到的错误的唯一编号。每个错误都需要一个唯一的编号,以便用户可以轻松地引用它们,并且编号应该尽可能简单和尽可能小。 “嘿,我修正了错误27”或“我重新打开了错误1867”。错误编号也应该增加,以便用户可以粗略地了解哪个错误后发生了哪些错误。谷歌应用程序引擎碎片计数器不工作,获取倍数

App Engine没有像SQL这样的真正的计数器,所以我实现了以下基本上是Google推荐的代码的函数,但它并不是一直工作。

我偶尔会看到重复的错误号。目前,我是唯一使用错误数据库的人(标志性地说,这个错误在我的错误数据库中),并且我不会更快地输入错误,然后每5秒或10秒输入一次错误(如果我输入更快)。虽然最终会有多个用户可能同时进入错误。

class SimpleCounterShard(db.Model): 
    count = db.IntegerProperty(required=True, default=0) 

def getNewID(): 
    def txn(): 
     index = random.randint(0, NUM_SHARDS - 1) 
     shard_name = "shard" + str(index) 
     counter = SimpleCounterShard.get_by_key_name(shard_name) 
     if counter is None: 
      counter = SimpleCounterShard(key_name=shard_name) 
     counter.count += 1 
     counter.put() 
    db.run_in_transaction(txn) 

    total = 0 
    for counter in SimpleCounterShard.all(): 
     total += counter.count 

    return total 

我在做什么错(或不理解)?或者,有更好的理由来获得唯一的数字,这些数字不仅仅是密钥或ID在生产服务器上的某些情况下似乎是随机的。

回答

1

分片计数器将具有完全相同的问题 - 如果您可以这样称呼它 - 内置的自动生成的ID具有:它们不保证单调性。分片计数器的目的是让你计算的东西,而不是让你分配数字的东西;结果,你不能以事务方式获得所有分片的总和,并且你的结果是错误的。

你真的应该只使用内置的自动编号;我怀疑用户是否认真关注相互之间的bug数量级别,如果您希望它们能够扩展到高写入率,那么您可以提出的大多数解决方案都会遇到类似的问题。

如果您绝对必须有序列号,您可以使用单个计数器实体,并且允许每秒最大插入速率为1-10,或者您可以启动一个“计数器”后端,从数据存储区批量分配ID并将它们发送出去以响应来自前端的RPC请求。如果后者听起来很熟悉,那是因为这就是自动生成的ID所做的事情,只能在多台机器上分割。

+0

感谢您的回复。就bug数而言,在一个包含数千和数千个bug的巨大项目中可能并不重要,但对于一个拥有几百个bug的小型独立项目而言,当最后一个bug是71时,将10201看作bug数,确实会导致一些人恐慌。当涉及到这样的东西时,我也是OCD。 :-) –

0

您的代码并非真正线程安全。是的,你使用交易来增加一个计数器,但是你不用它来读取计数器。还有其他碎片,您没有锁定在该事务中(因为它们位于不同的实体组中)。你可以想象有两个请求增加计数器,然后在事务之外读取值(获得相同的值)。 你基本上需要在交易中做所有事情,只需要一个分片。这意味着阻止多次调用新的id(序列化它们)。我会建议使用不同的计数器为每个项目/标签/上下文/任何更好地扩展写入。

阅读更多关于交易here

老实说,我只是使用自动生成的模型ID,如果我是你。

+0

模型ID的问题是它们反弹很多。我会得到几个14,15和9007的数据。为了跟踪面向用户的bug数,这可能是非常具有误导性的。 –

相关问题