我正在尝试在数据存储区中实现强一致性,不知道任何其他方式来处理我的要求。我有一个用户随机连接的应用程序。所以基本上在'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)。
我想知道我在这里是否遗漏了任何明显的东西,或者有更好的方法来解决这个问题。
答案 0 :(得分:1)
这段代码完全没有意义,也没有做你想要的。抱歉。我建议删除所有代码,只包括这个问题:
我有一个用户随机连接的应用程序。 所以基本上就是连接&#39; api调用,它查询QueueUser实体, 如果它没有找到任何,它将推动队列中的呼叫用户。
假设您需要大规模(每秒多次)执行此操作,这对数据存储区来说实际上很难。数据存储区不喜欢快速变异的状态。你真正拥有的不是一个队列而是一个单一的位置;每当有人连接时,他们要么被置于现场(如果它是空的),要么与现场的人配对(使该地点为空)。
我会使用不同的工具。对于像匹配这样短暂的东西存储持久状态真的没有意义。无论如何,客户端都需要重试逻辑。
Memcache是一个不错的选择 - 使用getIdentifiable
和putIfUntouched
使其成为事务性的,并结合一些重试逻辑。唯一的问题是GAE的Memcache偶尔会变得不可用(它不像数据存储那样可靠)。如果您正在为热门游戏构建匹配引擎,您可能希望在GCE中运行自己的memcached。
老实说,构建自己的内存服务并将其作为单例运行可能更容易。一个简单的版本可能是10行代码。