2011-09-04 28 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數,這可能是非常具有誤導性的。 –

相關問題