Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala 如何使用Akka持久性保存流数据_Scala_Akka_Akka Stream_Akka Persistence - Fatal编程技术网

Scala 如何使用Akka持久性保存流数据

Scala 如何使用Akka持久性保存流数据,scala,akka,akka-stream,akka-persistence,Scala,Akka,Akka Stream,Akka Persistence,我使用StreamRefs在集群中的参与者之间建立流连接。目前,在writing节点中,我手动将传入消息保存到日志文件中,但我想知道是否可以将其替换为persistentSink,用于写入,而persistentSource用于在actor启动时读取 来自Akka持久性杂志。我一直在考虑用Persistent-actor的Persistent{evt=>…}替换日志文件接收器,但由于它是异步执行的,我将失去反压力。那么,有没有可能将背压流数据写入Akka持久性日志,并在actor recover

我使用StreamRefs在集群中的参与者之间建立流连接。目前,在writing节点中,我手动将传入消息保存到日志文件中,但我想知道是否可以将其替换为persistent
Sink
,用于写入,而persistent
Source
用于在actor启动时读取 来自Akka持久性杂志。我一直在考虑用Persistent-actor的
Persistent{evt=>…}
替换日志文件接收器,但由于它是异步执行的,我将失去反压力。那么,有没有可能将背压流数据写入Akka持久性日志,并在actor recover上以流方式读取这些数据

目前的执行情况:

object Writer {
  case class WriteSinkRequest(userId: String) 
  case class WriteSinkReady(userId: String, sinkRef: SinkRef[ByteString])
  case class ReadSourceRequest(userId: String)
  case class ReadSourceReady(userId: String, sourceRef: SourceRef[ByteString])
}

class Writer extends Actor {

    // code omitted

    val logsDir = "logs"

    val path = Files.createDirectories(FileSystems.getDefault.getPath(logsDir))

    def logFile(id: String) = {
        path.resolve(id)
    }

    def logFileSink(logId: String): Sink[ByteString, Future[IOResult]] = FileIO.toPath(logFile(logId), Set(CREATE, WRITE, APPEND))
    def logFileSource(logId: String): Source[ByteString, Future[IOResult]] = FileIO.fromPath(logFile(logId))

    override def receive: Receive = {
        case WriteSinkRequest(userId) => 
            // obtain the source you want to offer:
            val sink = logFileSink(userId)
            // materialize the SinkRef (the remote is like a source of data for us):
            val ref: Future[SinkRef[ByteString]] = StreamRefs.sinkRef[ByteString]().to(sink).run()
            // wrap the SinkRef in some domain message, such that the sender knows what source it is
            val reply: Future[WriteSinkReady] = ref.map(WriteSinkReady(userId, _))
            // reply to sender
            reply.pipeTo(sender())

        case ReadSourceRequest(userId) =>
            val source = logFileSource(userId)
            val ref: Future[SourceRef[ByteString]] = source.runWith(StreamRefs.sourceRef())
            val reply: Future[ReadSourceReady] = ref.map(ReadSourceReady(userId, _))
            reply pipeTo sender()

    }
}
注意:是否可以不创建“保存到日记账”接收器,而是创建流:
要写入的传入数据~>保存到持久性日志~>写入的数据

以背压方式将数据流式传输到持久性参与者的一个想法是:让参与者在持久化消息时发送确认消息。这将类似于以下内容:

// ...
case class WriteSinkReady(userId: String, sinkRef: SinkRef[MyMsg])    
// ...

def receive = {
  case WriteSinkRequest(userId) =>
    val persistentActor: ActorRef = ??? // a persistent actor that handles MyMsg messages
                                        // as well as the messages used in persistentSink

    val persistentSink: Sink[MyMsg, NotUsed] = Sink.actorRefWithAck[MyMsg](
      persistentActor,
      /* additional parameters: see the docs */
    )

    val ref: Future[SinkRef[MyMsg]] = StreamRefs.sinkRef[MyMsg]().to(persistentSink).run()
    val reply: Future[WriteSinkReady] = ref.map(WriteSinkReady(userId, _))
    reply.pipeTo(sender())

  case ReadSourceRequest(userId) =>
    // ...
}
上面的示例使用名为
MyMsg
的自定义case类,而不是
ByteString

在发送者中,假设它是演员:

def receive = {
  case WriteSinkReady(userId, sinkRef) =>
    source.runWith(sinkRef) // source is a Source[MyMsg, _]

  // ...
}
发送方中的物化流将向持久参与者发送消息