grpc 流式传输_编写下载服务器。 第一部分:始终流式传输,永远不要完全保留在内存中...
grpc 流式傳輸
下載各種文件(文本或二進制文件)是每個企業應用程序的生死攸關的事情。 PDF文檔,附件,媒體,可執行文件,CSV,超大文件等。幾乎每個應用程序遲早都必須提供某種形式的下載。 下載是通過HTTP來實現的,因此完全包含此協議并充分利用它很重要。 特別是在面向Internet的應用程序中,諸如緩存或用戶體驗之類的功能值得考慮。 本系列文章提供了實現各種下載服務器時可能要考慮的各個方面的列表。 請注意,我避免使用“ 最佳做法 ”一詞,這些只是我認為有用的準則,但不一定總是適用。
最大的可伸縮性問題之一是在流傳輸之前將整個文件加載到內存中。 將完整文件加載到byte[]以便稍后從Spring MVC控制器返回它,這是無法預測的,并且無法縮放。 服務器將消耗的內存量與并發連接數乘以平均文件大小成線性關系,而您實際上并不想太依賴這些因素。 將文件的內容從服務器直接逐字節流傳輸到客戶端(使用緩沖)非常容易,實際上有很多技術可以實現。 最簡單的一種是手動復制字節:
@RequestMapping(method = GET) public void download(OutputStream output) throws IOException {try(final InputStream myFile = openFile()) {IOUtils.copy(myFile, output);} }您的InputStream甚至不必緩沖, IOUtils.copy()會解決這個問題。 但是,此實現相當底層,并且很難進行單元測試。 相反,我建議返回Resource :
@RestController @RequestMapping("/download") public class DownloadController {private final FileStorage storage;@Autowiredpublic DownloadController(FileStorage storage) {this.storage = storage;}@RequestMapping(method = GET, value = "/{uuid}")public Resource download(@PathVariable UUID uuid) {return storage.findFile(uuid).map(this::prepareResponse).orElseGet(this::notFound);}private Resource prepareResponse(FilePointer filePointer) {final InputStream inputStream = filePointer.open();return new InputStreamResource(inputStream);}private Resource notFound() {throw new NotFoundException();} }@ResponseStatus(value= HttpStatus.NOT_FOUND) public class NotFoundException extends RuntimeException { }創建了兩個抽象以使Spring控制器與文件存儲機制脫鉤。 FilePointer是一個文件描述符,與該文件的獲取位置FilePointer 。 目前,我們使用一種方法:
public interface FilePointer {InputStream open();//more to come}open()允許讀取實際文件,無論它來自何處(文件系統,數據庫BLOB,Amazon S3等)。我們將逐步擴展FilePointer以支持更多高級功能,例如文件大小和MIME類型。 查找和創建FilePointer的過程由FileStorage抽象控制:
public interface FileStorage {Optional<FilePointer> findFile(UUID uuid); }流式傳輸使我們能夠處理數百個并發請求,而不會顯著影響內存和GC( IOUtils僅分配了一個小緩沖區)。 順便說一句,我正在使用UUID來識別文件,而不是名稱或其他形式的序列號。 這使得猜測單個資源名稱變得更加困難,因此更加安全(晦澀)。 下一篇文章將對此進行更多介紹。 有了此基本設置,我們可以可靠地為大量并發連接提供服務,而對內存的影響最小。 請記住,Spring框架中的許多組件和其他庫(例如Servlet過濾器)可能會在返回完整響應之前對其進行緩沖。 因此,進行集成測試以下載巨大的文件(以數十個GiB格式)并確保應用程序不會崩潰非常重要。
編寫下載服務器
- 第一部分:始終流式傳輸,永遠不要完全保留在內存中
- 第二部分:標頭:Last-Modified,ETag和If-None-Match
- 第三部分:標頭:內容長度和范圍
- 第四部分:有效地執行HEAD操作
- 第五部分:油門下載速度
- 第六部分:描述您發送的內容(內容類型等)
- 這些文章中開發的示例應用程序可在GitHub上找到。
翻譯自: https://www.javacodegeeks.com/2015/06/writing-a-download-server-part-i-always-stream-never-keep-fully-in-memory.html
grpc 流式傳輸
總結
以上是生活随笔為你收集整理的grpc 流式传输_编写下载服务器。 第一部分:始终流式传输,永远不要完全保留在内存中...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: spring boot注释_使用Spri
- 下一篇: 鞋头挤脚怎么办 鞋头挤脚处理方法