强调与GAE客观化的一致性

时间:2017-05-27 13:46:09

标签: java google-app-engine google-cloud-datastore objectify

我正在尝试在数据存储区中实现强一致性,不知道任何其他方式来处理我的要求。我有一个用户随机连接的应用程序。所以基本上在'connect'api调用时,它会查询QueueUser实体,如果找不到,它会将调用用户推送到队列中。

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 个答案:

答案 0 :(得分:1)

这段代码完全没有意义,也没有做你想要的。抱歉。我建议删除所有代码,只包括这个问题:

  

我有一个用户随机连接的应用程序。   所以基本上就是连接&#39; api调用,它查询QueueUser实体,   如果它没有找到任何,它将推动队列中的呼叫用户。

假设您需要大规模(每秒多次)执行此操作,这对数据存储区来说实际上很难。数据存储区不喜欢快速变异的状态。你真正拥有的不是一个队列而是一个单一的位置;每当有人连接时,他们要么被置于现场(如果它是空的),要么与现场的人配对(使该地点为空)。

我会使用不同的工具。对于像匹配这样短暂的东西存储持久状态真的没有意义。无论如何,客户端都需要重试逻辑。

Memcache是​​一个不错的选择 - 使用getIdentifiableputIfUntouched使其成为事务性的,并结合一些重试逻辑。唯一的问题是GAE的Memcache偶尔会变得不可用(它不像数据存储那样可靠)。如果您正在为热门游戏构建匹配引擎,您可能希望在GCE中运行自己的memcached。

老实说,构建自己的内存服务并将其作为单例运行可能更容易。一个简单的版本可能是10行代码。