Akka 在特定时间可靠地处理消息

Akka 在特定时间可靠地处理消息,akka,cap-theorem,crdt,Akka,Cap Theorem,Crdt,假设我有一个聊天应用程序 客户端向聊天室发送消息,从而向某个参与者发送命令。现在,我想立即处理他写的内容,并将其提供给聊天室中的其他用户,因此我处理这个命令。同时,我想告诉自己(一个演员),我需要将这条消息存储在聊天历史数据库中,但不是现在。保存到数据库应每2分钟进行一次。如果发生崩溃,我无论如何都应该能够持久保存到数据库 我假设工作流是这样的: 用户发送消息 聊天室参与者收到带有此消息的命令 我们将此消息广播给每个人,并将此消息添加到某种队列中,以将其保存到聊天历史数据库中 一些persist

假设我有一个聊天应用程序

客户端向聊天室发送消息,从而向某个参与者发送命令。现在,我想立即处理他写的内容,并将其提供给聊天室中的其他用户,因此我处理这个命令。同时,我想告诉自己(一个演员),我需要将这条消息存储在聊天历史数据库中,但不是现在。保存到数据库应每2分钟进行一次。如果发生崩溃,我无论如何都应该能够持久保存到数据库

我假设工作流是这样的:

  • 用户发送消息
  • 聊天室参与者收到带有此消息的命令
  • 我们将此消息广播给每个人,并将此消息添加到某种队列中,以将其保存到聊天历史数据库中
  • 一些persist命令在超过2分钟超时时运行。它收集所有传入的聊天信息,这些信息尚未按到达顺序保留
  • 使用所有消息运行事务,然后将其从队列中删除
  • 如果3点以后某个地方发生了崩溃,并且消息没有被持久化,那么我应该再次尝试持久化它们。如果他们坚持下去,我就再也不会坚持下去了

  • 如何在阿克卡建造这样的东西?我应该使用哪些功能/哪些模式?

    您可能需要两个参与者:一个(协调员)将向客户端发送有关聊天命令的通知。另一个(节流器)-将每隔2分钟将数据推送到数据库。您的队列将只是节流器的内部状态:

    class Coordinator extends Actor {
       def receive = {
         case command: Record => 
              broadcast(command)
              throttler ! command
       }
    }
    
    
    class Throttler extends Actor {
    
      import system.dispatcher
    
      val queue = mutable.List[Record] //it may be a cache instead
    
      def schedule = system.scheduler.scheduleOnce(2 minutes, self, Tick) // http://doc.akka.io/docs/akka/snapshot/scala/scheduler.html
    
    
      def receive = {
           case Start => schedule
           case command: Record =>
               queue ++= command
           case Tick => 
              schedule
              try {
                //---open transaction here---
                for (r <- queue) push(r)
                //---close transaction here---
                queue.clear //will not be cleared in case of exception
              } catch {...}
      }
    }
    
    类协调器扩展了Actor{
    def接收={
    case命令:Record=>
    广播(命令)
    节流阀!指令
    }
    }
    类节流器扩展了Actor{
    导入system.dispatcher
    val queue=mutable.List[Record]//它可能是一个缓存
    def schedule=system.scheduler.scheduleOnce(2分钟,self,勾选)//http://doc.akka.io/docs/akka/snapshot/scala/scheduler.html
    def接收={
    案例开始=>时间表
    case命令:Record=>
    queue++=命令
    案例勾号=>
    日程
    试一试{
    //---在这里打开交易---
    
    对于(r)请看一看-这实际上是您用例中的4-5有没有任何方法可以利用现有的Akka持久性(事件等)来保护队列状态?您可以使用Akka持久性(saveSnapshot),但问题与DB相同-速度可能相当慢。此外,您必须同步保存每个记录以避免丢失状态,并且可能必须将其发送到DB或缓存(本地文件对您来说可能不可靠),因此实际上没有太大区别。请注意,这不会解决潜在的可用性问题(您仍然需要群集进行此操作)。我是否可以使用deleteMessages,这样它就不会重做所有操作?这样我就不需要saveSnapshot。或者使用事件源原样,通过自定义SnapshotStore实现数据库保存,并每隔2分钟保存快照。问题仍然是一样的-您必须在接收时准确保存每条消息(而不是批量保存),因此您不能使用DB:在第一种情况下,每条消息都将由
    persist
    保存(并且您应该仅在发件人(异步)提交数据时通知发件人),因此在此之后使用批量事务是没有意义的。在第二种情况下,您不能每2分钟保存一次快照,因为如果失败,您将丢失未保存的数据(您的客户端不能等待2分钟等待确认,否则根本不需要队列持久性)。