如何使用akka

时间:2016-03-22 17:08:00

标签: scala akka

我试图找出如何使用akka管理用户游戏状态。

游戏状态将持久保存到mysql,这不会改变,因为我们有其他需要此服务的服务。

游戏中发生的任何事情都被视为"事件"。

然后你我有"级别"哪个人可以实现。当您完成所有"事件时,将达到一个级别。与之相关。

所以你有:

Level
 - event1  e.g. reach a point in the game
 - event2  e.g. pickup a sword
 - event3  e.g. defeat a monster

所以在游戏中有很多级别,以及与级别相关的100个事件。

所有"事件"通过HTTP发送到我的后端,我将事件保存在数据库中。

然后我必须在内存中加载用户游戏配置文件,然后重新计算自发生新事件以来所达到的等级。 注意:这个计算不能在数据库级别完成,因为我在这里写的比较复杂。

我看到的问题是,如果我使用akka,我就无法让多个actor为同一个用户处理事件,因为数据可能会过时。

为了清楚起见,所以当一个新事件到来时,我必须在内存中加载游戏配置文件,遍历各个级别并查看是否已经实现了任何一个,如果有,则更新数据库

e.g. update levels set achieved=true where level_id = 123 and user_id=234

e.g。 actor1加载配置文件(此用户的所有级别和事件),然后处理刚到达收件箱的新事件。      同时,actor2加载配置文件(与actor1相同),然后处理新事件。当它持续更改mysql时,数据将不在sych中。

如果我使用线程,我必须在游戏配置文件计算期间锁定并持久保存到数据库。

我如何使用Akka执行此操作并能够并行处理,或者这个场景是不允许的?

1 个答案:

答案 0 :(得分:5)

让我们思考如何在没有演员的情况下管理它。因此,简而言之,您有以下问题场景:

  1. 两个(或更多)更新请求同时到达,两者都是 要修改相同的数据
  2. 两个请求都读取了一些稳定的数据 state,然后以自己的方式更新它并持久保存到DB
  3. 首先签入的请求的修改将丢失,更准确地说 - 被后来的请求覆盖。
  4. 这是一个经典问题。它至少有两种经典的解决方案:

    1. Optimistic locking
    2. 悲观锁定:通常通过对事务应用Serializable隔离级别来实现。
    3. 值得一读this answer并对两个世界进行比较。

      当您使用Akka时,您可能希望更喜欢更好的并发性和偶然的故障,这些故障很容易恢复。它与Akka座右铭let it crash相提并论。

      所以,你需要做下面的步骤:

      1. version列添加到您的表格中。它可以是数字或字符串(带哈希)。数字是最简单的。
      2. 插入新记录时 - 初始化版本。
      3. 更新记录时 - 检查version值未更改。那么,这是您的更新策略:
        1. 阅读记录及其version
        2. 更新内存中的记录。
        3. 使用条件where rec_id=$id and version=$version执行更新查询。
        4. 如果更新的记录数为1 - 那你很好。如果为0 - 抛出OptimisticLockException或smth就像这样。
      4. 最后,是Akka完成工作的时候了:提出适当的监督策略(我选择try again in 1 second之类的东西)。在actor的preRestart方法中,将更新消息返回到actor的邮箱(参见Akka文档中的Restart Hooks章节)。
      5. 使用此策略,即使两个请求尝试一次更新同一条记录,其中一条会失败并会立即再次处理。