2017-01-09 36 views
0

我正在开发基于MySQL的多人游戏匹配系统。我有三个表:对接,游戏GameScores实现SQL匹配

当玩家做一个牵线搭桥的要求,我们尝试从对接会求n对手,然后我们创建一个游戏游戏GameScore行与引用播放器和游戏 N个。

  1. 选择对接会 LEFT JOIN GameScores ON 对接会 .player = GameScores .player和GameScores .player IS NULL ...(玩家不GameScore
  2. INSERT 游戏
  3. INSERT GameScore
  4. 当比赛结束后,GameScores被删除这样的球员是在步骤1中找到再次

GameScore是玩家唯一的。当系统得到高频率的请求时,这会导致很多错误,因为其他人已经将此播放器添加到GameScore

所以第1步是由多个客户端同时进行的,他们试图在第3步

我试图做牵线搭桥之前锁定表添加相同的玩家不同的游戏,但是这导致服务器速度变慢太多了。

对接是一个临时表,包含对玩家数据和上次ping时间的引用。也许这个数据应该在MySQL之外以获得更好的性能?

有没有其他方法可以做得更好?可能memcached或类似的共享内存多个进程和/或服务器?

服务器运行在多个内核(NodeJS)上,未来甚至可能是多个服务器。

+2

请阅读[我可以问什么主题](http://stackoverflow.com/help/on-topic) 和[如何提出一个好问题](http://stackoverflow.com/help/how - 问) 和[完美的问题](http://codeblog.jonskeet.uk/2010/08/29/writing-the-perfect-question/) 以及如何创建[最小,完整和可验证示例](http://stackoverflow.com/help/mcve) – RiggsFolly

+0

最终,我认为这样做的正确方法是摆脱Matchmaking表并为匹配请求使用适当的消息队列。然后,您可以使用消息代理(如RabbitMQ)将匹配处理正确分发到多个核心。 –

回答

0

下面是使用SQL表跨内核分配工作任务的技术:

  1. 分配一个唯一的ID给每个核心
  2. 列ProcessingByCore添加到婚介
  3. 修改你的第一个SQL查询看起来更像这样:

    UPDATE dbo.Matchmaking 
    SET ProcessingByCore = @coreId 
    FROM Matchmaking m 
    LEFT JOIN GameScores gs 
    ON m.player = gs.player 
    WHERE gs.player IS NULL 
    AND m.ProcessingByCore IS NULL 
    
  4. 您现在可以通过ProcessingCoreId进行选择。

这是可行的,因为UPDATE是原子的,所以本质上它只是锁定表,尽管它的范围较小。

当然,这种方法的主要问题是当核心在没有释放Matchmaking行的情况下死亡时会发生什么。这些球员将永远留在比赛队列中。您可以添加另一个进程,该进程至少验证所有ProcessingByCore ID是否都有关联且运行正常的核心。

就像我在评论中所说的那样,使用SQL表来分发工作对于工作来说是错误的工具。你需要一个消息队列。

+0

FROM必须是拉取一行(限制1)的子查询,然后在主键上匹配,否则将更新整个表而不是单个行,除非更新所有匹配的行是您的愿望。 –

+0

从我对这个问题的理解中提取所有匹配的行是期望的行为,尽管这看起来似乎是矫枉过正。我认为人们只想在一场比赛中尽可能多地吸引球员。如果涉及MMR,问题会变得更加复杂,但这些细节都不包含在问题中。 –