我正在使用基于MMR的Redis创建一个游戏配对系统,该数字几乎可以概括玩家的技能。因此,系统可以将他/她与其他具有相同技能的其他人相匹配。 例如,如果MMR为1000的玩家加入队列,系统将尝试查找MMR为950到1050的其他ppl与该玩家匹配。但是如果一分钟后找不到任何具有给定统计数据的球员,它将把范围扩大到900到1100(恒定阈值)。 我想通过关系数据库设计确实很容易,但是我不知道如何使用Redis。
队列表实现如下:
+----+---------+------+-------+
| ID | USER_ID | MMR | TRIES |
+----+---------+------+-------+
| 1 | 50 | 1000 | 1 |
| 2 | 70 | 1500 | 1 |
| 3 | 350 | 1200 | 1 |
+----+---------+------+-------+
因此,当一个新玩家排队时,如果发现阈值在5%阈值之间,它将与队列中的其他玩家进行对比,检查其MMR,如果匹配,则将与两个玩家匹配,否则会将新玩家添加到表中并等待新玩家排队比较或超过1分钟,而cronjob会增加尝试次数,然后重试以匹配玩家。
我能想象的唯一方法是像这样在队列中每个玩家的低位和高位使用两个单独的键
MatchMakingQueue:User:1:Low => 900
MatchMakingQueue:User:1:High => 1100
但是按键会有所不同,例如,我无法获得所有用户(介于900的低点到1100的高点之间!)
我希望我已经很清楚,任何帮助将不胜感激。
答案 0 :(得分:1)
正如 @Guy Korland 所建议的那样,排序集可用于根据其MMR跟踪和匹配玩家,我不同意OP的“不会扩展”评论。< / p>
基本上,当新玩家加入时,该ID将以MMR作为其得分添加到zset。
ZADD players:mmr 1000 id:50
对每个用户进行匹配,例如id:50,并执行以下查询:
ZREVRANGEBYSCORE players:mmrs 1050 950 LIMIT 0 2
如果返回了两个ID,并且至少其中一个与新玩家的ID不同,则会找到匹配项。要进行匹配,需要从集合中删除两个ID(新玩家的ID和与之匹配的ID)-我将使用Lua脚本来实现这一逻辑(匹配和删除),以减少原子性和通信量,但是也可以在客户端中完成。
有多种方法可以跟踪重试,但是最简单的方法可能是使用另一个排序集,其中的得分就是该度量。
以下伪Redis Lua代码是该方法的最小示例:
local kmmrs, kretries = KEYS[1], KEYS[2]
local id = ARGV[1]
local mmr = redis.call('ZSCORE', kmmrs, id)
local retries = redis.call('ZSCORE', kretries, id)
local min, max = mmr*(1-0.05*retries), mmr*(1+0.05*retries)
local candidates = redis.call('ZREVRANGEBYSCORE', kmmrs, max, min, 'LIMIT', 0, 2)
if #candidates < 2 then
redis.call('ZINCRBY', kretries, 1, id)
return nil
end
local reply
if candidates[1] ~= id then
reply = candidates[1]
else
reply = candidates[2]
end
redis.call('ZREM', kmmrs, id, reply)
redis.call('ZREM', kretries, id, reply)
return reply
答案 1 :(得分:0)
让我正确解决问题!您的问题是您要查找给定MMR值范围内的所有用户。如果您让其他用户说“我属于这个范围”,该怎么办。
了解有关Redis发布/订阅的信息。
您可以为所有用户创建一个频道(比方说MatchMMR),发布针对所有用户都应订阅的匹配请求的MMR。如果某人的MMR在计算的范围内,请设置用户专用频道。
您发布消息的表格,以便您可以发送“重试计数”,“匹配范围百分比”,“ MMR值”等所有信息,以便您的用户端代码可以计算出它是否适合MMR。
有关Redis发布/订阅的阅读模式,位于:https://redis.io/topics/pubsub