2017-02-19 130 views
1

我寫的應用程序的一部分需要從客戶端向服務器傳輸任意大的(對於此問題,我將假設100-200 GB)的文件。重要的是,接收器(服務器)不存儲這個文件 - 它只是讀取/檢查流並將其發送到下一個點。因爲在任何時候我都需要整個文件,但是希望同時進行多次傳輸,所以我想盡量減少內存使用量並消除磁盤​​使用量。我想以1 MB大塊處理文件。通過反應流發送大文件

現在,服務器使用Spring Boot和Akka。

我的第一次嘗試是在客戶端打開緩衝的文件輸入流,以1 MB的塊爲單位讀取它,並以單獨的線程在消息中發送它們。它可以工作,但問題在於客戶端一個接一個地發送消息,而不必擔心服務器是否有緩衝區來存儲消息(缺乏背壓)。

我的第二個想法是用阿卡流是這樣的:

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

「Warning ActorPublisher和ActorSubscriber可能會在未來版本的Akka中被棄用。

警告 ActorPublisher和ActorSubscriber不能與遠程參與者使用,因爲如果反應流協議(例如請求)的信號丟失的流可能死鎖。」

它不像好主意。

我不想將它保存在任何存儲提供程序(dropbox,谷歌驅動器,...),因爲我想動態分析數據。我有彈簧5和Akka在船上,但我可以使用任何其他軟件,這將解決此問題。原始插座將缺乏背壓和山洪不保證順序/有序的讀寫(我需要)。

主要問題是:如何將大文件從客戶端傳輸到服務器,假設服務器無法一次將文件存儲在磁盤或ram中?

獎金的問題是:如何計算在這種轉移中的「正確」大塊大小?

我一直在尋找答案的日子,看起來像我不是唯一一個這樣的問題,但沒有指出其他適當的替代解決方案沒有答案或答案像「不這樣做」。

+1

目前尚不清楚您的問題到底是什麼。Akka流提供了你所需要的所有工具 - TCP套接字周圍有流封裝(當然還有背壓),並且有'GraphStage'(這是你可以用來實現處理的ActorSubscriber和ActorPublisher的預期替代品)如果沒有默認的組合器適合你,則爲邏輯。你只需要合併它們。 –

+0

你會如此友善並向我展示一些遠程流的最小例子嗎? – spam

+1

當然,這是:https://gist.github.com/netvl/1245564b106c02691dd0808fe98d07eb。它非常骯髒(特別是在服務器關機處理時),但它應該傳達基本的想法。它使用原始的TCP套接字進行通信;你也可能想使用akka-http,因爲它也給你更簡單的TLS配置(儘管也可以用原始TCP流來完成)。 TCP流被記錄[在這裏](http://doc.akka.io/docs/akka/2.4/scala/stream/stream-io.html#streaming-tcp),並且akka-http記錄在[這裏](http ://doc.akka.io/docs/akka-http/current/scala.html)。 –

回答

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() 

關於你的獎勵問題的「大小正確的大塊;這高度依賴於您的硬件和軟件配置。最好的辦法是編寫一個測試客戶端並調整塊大小,直到找到服務器的「最佳位置」。