【问题标题】:Force strong consistency with objectify on GAE在 GAE 上使用 objectify 强制强一致性
【发布时间】:2017-05-27 13:46:09
【问题描述】:

我正在尝试在数据存储中实现强一致性,不知道有什么其他方法可以满足我的要求。我有一个用户随机连接的应用程序。所以基本上在 'connect' api 调用中,它会查询 QueueUser 实体,如果没有找到,它将把调用用户推送到队列中。

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

我知道这不会获取最新的实体键,因为索引可能不是最新的。所以我通过键进行交互并通过它的键获取每个实体。如果我得到一个非空实体,我会尝试删除它。如果我成功了,我认为这是用户的匹配。这个 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)。

我想知道我是否在这里遗漏了任何明显的东西,或者有没有更好的方法来处理这个问题。

【问题讨论】:

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


    【解决方案1】:

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

    我有一个用户随机连接的应用程序。 所以基本上在 'connect' api 调用中,它查询 QueueUser 实体, 如果没有找到,它将把主叫用户推入队列。

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

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

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

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

    【讨论】:

    • 感谢您的回答。我了解数据存储不适合我的要求。是的,不需要持久存储。我会试试内存缓存。我认为 memcache 仅与数据存储一起使用,如果在 memcache 中找不到 @cached 实体,它会从数据存储中获取它。
    • Memcache 与 getIdentifiableputIfUntouched 成功了。延迟大大减少。非常感谢@stickfigure!顺便说一句,在极少数情况下,两个请求在精确的毫秒内执行putIfUntouched,它返回true
    猜你喜欢
    • 2015-06-20
    • 1970-01-01
    • 2013-07-25
    • 2015-06-05
    • 1970-01-01
    • 2015-02-04
    • 1970-01-01
    • 2018-06-17
    • 1970-01-01
    相关资源
    最近更新 更多