2013-07-29 21 views
0

我們正在開發iOS應用引擎的賽車遊戲作爲後端。然而在六月下旬發生了一些奇怪的事情(我剛剛從我的假期回來,因此我現在正在發佈)。如何依靠Google App Engine中的一致數據?

客戶端發佈分數並從服務器獲取高分列表,並且所有內容似乎都可以正常工作(我們已經測試了一個月沒有問題,代碼也非常簡單,只不過比put/get多) 。但在六月下旬,幾個小時後,舊數據被返還給客戶。它發生了一段時間,但數據修正了它自己。

但是這仍然讓我們陷入麻煩的,因爲比分上提交我們檢查服務器只有每個玩家一個高分,但這個應用程序引擎的bug(?)導致服務器有多個得分一些球員。玩家B提交得分,當只有玩家A存在時數據被恢復,玩家B提交新得分(它被存儲爲服務器不會看到玩家B),服務器修正數據的問題,現在我們要播放器B.

應該如何你去,如果你希望能夠依靠App Engine的後臺?這可能是一個交易斷路器。

更具體的(如在意見中的要求)

我simplyfying我們在做什麼了一下。但基本上是一樣的。所以我們不僅僅存儲高分,還有玩家的鬼魂數據。這是代碼(但刪除了一些與現在不相關的額外字段)。

這裏的模型(與剝離一些非重要的字段):

class Highscore(db.Model): 
    player = db.StringProperty() 
    track = db.IntegerProperty() 
    track_time = db.FloatProperty() 
    ghost_data = blobstore.BlobReferenceProperty() 

和存儲,我首先做一個:

class GhostPrepareHandler(webapp2.RequestHandler): 
    def get(self): 
     self.response.headers['Content-Type'] = 'application/json' 
     self.response.out.write(json.dumps({ 'add_highscore_url' : blobstore.create_upload_url('/api/highscore') })) 

然後

class HighscoreUploadHandler(blobstore_handlers.BlobstoreUploadHandler): 
    def post(self): 
     # Check any previous highscore 
     track = self.request.get('track') 
     player = self.request.get('player') 

     hs = Highscore.all().filter('track =', track).filter('player =', player).get() 

     # Check if a previous ghost exists with a worse time, if so remove it, 
     # else if previous time is better, do not store this highscore 
     if hs is not None: 
      if hs.track_time < float(self.request.get('track_time')): 
       self.response.headers['Content-Type'] = 'application/json' 
       self.response.out.write(json.dumps({ 'success' : True })) 
       return 

      hs.delete() 

     # Store highscore 
     hs = Highscore() 
     hs.player = self.request.get('player') 
     hs.track = int(self.request.get('track')) 
     hs.track_time = float(self.request.get('track_time')) 

     upload = self.get_uploads()[0] 
     hs.ghost_data = upload.key() 

     # Store 
     hs.put() 

     self.response.headers['Content-Type'] = 'application/json' 
     self.response.out.write(json.dumps({ 'success' : True })) 

而且然後我們拿到了讀部分

def get(self): 
    player = self.request.get('player') 
    track = self.request.get('track') 

    highscores = HighScore.all().filter('track =', track).order('track_time').fetch(limit=4) 

    highscores_json = [] 

    hs_count = 0 
    for hs in highscores: 
     # Filter out player or last ghost 
     if hs.player == player or hs_count > 2: 
      continue 

     hs_obj = { 
      'player' : hs.player, 
      'track_time' : hs.track_time, 
      'ghost_data_url' : 'http://' + host + '/api/highscore/download?ghost_key=' + str(hs.ghost_data.key()) 
     } 

     highscores_json.append(hs_obj) 
     hs_count += 1 

    self.response.headers['Content-Type'] = 'application/json' 
    self.response.out.write(json.dumps(highscores_json)) 

而且它一直工作正常,但由於某些原因,一兩個小時就返回舊的數據(如天數據)。

+0

請問您是否可以添加您用於查詢的代碼,以查看是否存在某個玩家和得分模型的任何現有高分?你在使用memcache嗎? –

+0

是的,至少展示你的模型和你用來設置/閱讀你的高分和用戶實體的代碼。如果你不使用交易和祖先,肯定有機會發生這種情況。 – dragonx

+0

我添加了一些代碼(但刪除了幾個部分)。不使用memcache,這將解釋它。這是一個令人討厭的問題,我們遭受了。謝謝。 – Nixarn

回答

0

如果您是通過檢索查詢分數,那麼你也遇到eventual consistency OD HRD數據存儲。發生這種情況是因爲索引(用於查詢)是異步構建的(=在構建索引之前寫入操作返回)。

+0

但是現在它將幾天的舊數據返回了幾個小時。難道它真的是同樣的問題嗎?如果真是太棒了,那我們就會知道該怎麼做。 – Nixarn

0

您使用的查詢來獲取一個玩家對更新記錄?對不起,只是有時間快速閱讀,但似乎是這樣。我認爲可以肯定地說,你絕對不應該爲這種類型的更新使用查詢。你會碰到問題的最終一致性,並且每一個get()的方式都比不必要的低效率(延遲)和高成本(讀/寫操作)。爲什麼不用每個球員的高分紀錄都用他/她的特定信息塑造出獨特的身份?然後get_by_id()和put()。您保證一致性,唯一的限制是每條記錄每秒寫入一次寫入的限制,在這種情況下不應該成爲問題。另外,我會非常吝惜依賴delete()和你一樣。如果您使用get_by_id()過程,則只需使用每個put()替換舊hs。再說一次,如果你正在使用這個過程來保持每個球員獨特的高分記錄,你必須重新設計它。

相關問題