通过反应流

时间:2017-02-19 14:26:43

标签: spring stream akka reactive-programming akka-stream

我正在编写的部分应用程序需要从客户端到服务器任意传输大量(对于此问题,我将假设100-200 GB)文件。重要的是,接收器(服务器)不存储此文件 - 它只是读取/检查流并将其发送到下一个点。因为在任何时候我都不需要整个文件,但是期望同时进行多次传输,我希望最大限度地减少RAM使用并消除磁盘​​使用。我想以1 MB的块为单位处理文件。

现在,服务器使用Spring Boot和Akka。

我的第一次尝试是在客户端打开缓冲文件输入流,以1 MB的块读取它,并在单独的线程中将它们发送到消息中。它有效,但问题是客户端一个接一个地发送消息而不用担心服务器是否有缓冲区来存储它(缺乏背压)。

我的第二个想法是使用像这样的akka​​-stream:

How to use Reactive Streams for NIO binary processing?

使用ActorPublisher,如下所示:

akka-streams with akka-cluster

然而,如上所述:

http://doc.akka.io/docs/akka/2.4.16/scala/stream/stream-integrations.html#Implementing_Reactive_Streams_Publisher_or_Subscriber

"警告 在未来的Akka版本中,可能会弃用ActorPublisher和ActorSubscriber。

警告 ActorPublisher和ActorSubscriber不能与远程actor一起使用,因为如果Reactive Streams协议(例如请求)的信号丢失,则流可能会死锁。"

它看起来不是一个好主意。

我不想将其保存在任何存储提供商(dropbox,google drive,...)中,因为我想在运行中分析数据。我有Spring 5和Akka,但我可以使用任何其他软件来解决这个问题。原始套接字将缺乏背压,并且种子不保证顺序/有序读写(我需要)。

主要问题是:如何将大文件从客户端流式传输到服务器,假设服务器无法在磁盘上或ram中同时存储文件?

奖金问题是:如何计算"正确"这种转移中大块的大小?

我一直在寻找答案,看起来我不是唯一一个有这样问题的人,但是没有答案或答案,例如"不要这样做"没有指出其他适当的替代解决方案。

1 个答案:

答案 0 :(得分:3)

Akka流专门为此用例提供了功能:streaming File IO。来自文档:

import akka.stream.scaladsl._
val file = Paths.get("example.csv")

val foreach: Future[IOResult] = 
  FileIO.fromPath(file)
        .to(Sink.ignore)
        .run()

关于"正确尺寸"的奖金问题大块这在很大程度上取决于您的硬件和软件配置。你最好的选择是编写一个测试客户端并调整块大小,直到找到一个最佳位置"为您的服务器。