2017-05-27 12 views
0

データストアで強力な一貫性を達成しようとしていますが、私の要件を処理する方法は他にありません。ユーザーがランダムに互いに接続するアプリケーションを持っています。ので、基本的に '接続' API呼び出しでは、QueueUserエンティティを照会し、それが見つからなければ、キュー内の呼び出し元のユーザーをプッシュします。GAEでobjectifyと強固な整合性を強制します

ofy().load().type(QueueUser.class) 
    .filterKey("!=", KeyFactory.createKey("QueueUser", caller.id)) 
    .order("__key__") 
    .order("-time") 
    .limit(5) 
    .keys(); 

インデックスが最新でない可能性があるため、最新のエンティティキーを取得しないことを理解します。だから私はキーを介して介入し、それによって各エンティティを取得します。 null以外のエンティティを取得した場合は、削除しようとします。私がそれに成功すれば、それはユーザーのマッチであると仮定します。このget-by-keyとdelete()はTransaction内部にあります。

  while(keyIterator.hasNext()) { 
       QueueUser queueUser = null; 
       try { 
        final Key<QueueUser> key = keyIterator.next(); 
        queueUser = ofy().transactNew(1, new Work<QueueUser>() { 
         public QueueUser run() { 
          QueueUser queueUser = ofy().load().key(key).now(); 
          if(queueUser == null) { 
           logger.log(Level.WARNING, "queue user was already deleted"); 
           return null; 
          } 
          else 
           ofy().delete().key(key).now(); 
          return queueUser; 
         } 
        }); 
       } catch (ConcurrentModificationException e) { 
        logger.log(Level.WARNING, "exception while deleting queue user. err: " + e.getMessage()); 
       } 
       if (queueUser != null) { 
       // we have a match here 
       // delete calling user from the queue if it's there 
       ofy().delete().entity(new QueueUser(caller.id, null, null, null, null, null, null, null, null)).now(); 
       break; 
       } 
      } 

これはほとんどの場合動作しますが、ユーザーがキューにプッシュされてすぐには取得されないことがあります。リクエストの待ち時間は最大15秒です。照会は多くのエンティティーを戻しますが、ほとんどは削除され、一部はピア要求(予期されるConcurrentModificationException)によって削除されます。

私はここに何かが欠けているかどうか知りたいのですが、これを処理するにはより良い方法があります。

答えて

1

このコードは絶対に意味をなさないもので、あなたが望むことをしません。ごめんなさい。すべてのコードを削除してこの質問を含めることをおすすめします。

ユーザーがランダムに接続するアプリケーションを持っています。 これは基本的に '接続' API呼び出しで、QueueUserエンティティを照会します。 見つからない場合は、キュー内で呼び出し元のユーザーをプッシュします。

これをスケール(毎秒何回も)で行う必要があると仮定すると、これは実際にはデータストアでは難しい作業です。データストアは急速に変化する状態を好まない。あなたが本当に持っているのは待ち行列ではなく一つの単一のスポットです。誰かが接続するたびに、それらはスポットに置かれる(空の場合)か、現場の人とペアになって(スポットが空になる)。

私は別のツールを使用します。マッチメイキングのような一時的なものとして永続的な状態を保存することは本当に意味がありません。クライアントはリトライロジックを必要とします。

Memcacheは良い選択です。getIdentifiableputIfUntouchedを使用すると、トランザクションを再試行ロジックと組み合わせて使用​​できます。唯一の問題は、GAEのMemcacheが時には利用できなくなることです(データストアほど信頼性がありません)。一般的なゲームのためのマッチメーキングエンジンを構築する場合は、GCEでmemcachedを実行することができます。

正直なところ、自分のインメモリサービスを構築してシングルトンとして実行する方が簡単です。単純なバージョンはおそらく10行のコードです。

+0

ありがとうございます。私はデータストアが私の要求に適していないことを理解しています。そして、はい、永続的なストレージの必要はありません。私はmemcacheを試してみます。私はmemcacheがデータストアでのみ使用されていると考えました。もし@cachedエンティティがmemcacheに見つからなければ、データストアから取得します。 – sandeepd

+0

Memcacheに 'getIdentifiable'と' putIfUntouched'がありました。レイテンシは大幅に減少しました。ありがとう@stickfigure!まれに、2つのリクエストが正確なミリ秒で 'putIfUntouched'を実行している場合、' true'を返します。 – sandeepd

関連する問題