Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/14.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
用于文件上传的Spring引导API的Tomcat性能_Spring_Spring Boot_Performance_Tomcat_Amazon S3 - Fatal编程技术网

用于文件上传的Spring引导API的Tomcat性能

用于文件上传的Spring引导API的Tomcat性能,spring,spring-boot,performance,tomcat,amazon-s3,Spring,Spring Boot,Performance,Tomcat,Amazon S3,我有一个SpringBootAPI,其中一个端点允许用户上传视频。现在,我的控制器基本上将该文件作为一个多部分文件,然后将其存储在tomcat可以访问的临时文件夹中。一旦我将它存储在磁盘上,我就会将视频推送到S3存储桶中 现在对我来说,这似乎不是最理想的,比如如果我想让100或1000个用户同时上传,那么首先将文件写入磁盘似乎真的没有什么效果 作为一个小背景,我将它存储在磁盘上,目的是如果有问题推到S3,我可以重试 下面的代码可能会显示我比上面做得更好的地方: public Video addV

我有一个SpringBootAPI,其中一个端点允许用户上传视频。现在,我的控制器基本上将该文件作为一个多部分文件,然后将其存储在tomcat可以访问的临时文件夹中。一旦我将它存储在磁盘上,我就会将视频推送到S3存储桶中

现在对我来说,这似乎不是最理想的,比如如果我想让100或1000个用户同时上传,那么首先将文件写入磁盘似乎真的没有什么效果

作为一个小背景,我将它存储在磁盘上,目的是如果有问题推到S3,我可以重试

下面的代码可能会显示我比上面做得更好的地方:

public Video addVideo(@RequestParam("title") String title,
    @RequestParam("Description") String Description,
    @RequestParam(value = "file", required = true) MultipartFile file) {         
           this.amazonS3ClientService.uploadFileToS3Bucket(file, title, description));
}
用于存储视频文件的方法:

String fileNameWithExtenstion = awsS3FileName + "." + FilenameUtils.getExtension(multipartFile.getOriginalFilename());

//creating the file in the server (temporarily)
File file = new File(tomcatTempDir + fileNameWithExtenstion);FileOutputStream fos = new FileOutputStream(file);

fos.write(multipartFile.getBytes());

fos.close();PutObjectRequest putObjectRequest = new PutObjectRequest(this.awsS3Bucket, awsS3BucketFolder + UnigueId + "/" + fileNameWithExtenstion, file);

if (enablePublicReadAccess) {
    putObjectRequest.withCannedAcl(CannedAccessControlList.PublicRead);
}

// Upload a file as a new object with ContentType and title 

specified.amazonS3.putObject(putObjectRequest);
//removing the file created in the server
file.delete();
所以我的问题是……在Tomcat中有没有更好的方法:


A) 通过控制器接收文件b)推送到S3

使用multipart没有其他方法。multipart的问题是,为了正确地将零件与需求分开,有时需要跳过或重复。在没有内存爆炸的内存中,这是不可能的。因此,Commons FileUpload会在达到某个阈值后将其缓存到磁盘上。 多部分请求是最糟糕的方式。我强烈建议对内容类型
application/octet-stream
使用
PUT
POST
。您可以获取裸请求输入流,并将其传递给HttpClient,以流式传输到后端服务器。我在5年前就这样做了,它可以工作千兆字节。我已经在ApacheHttpClient邮件列表中发布了解决方案

在特定条件下,这有一种可能会起作用:

  • 所有零件都符合您想要阅读的正确物理顺序
  • 您对后端的写入速度足以支持前端的读取

使用根部分,然后转到下一个物理部分,惰性地处理请求主体。JAX-WSRI(Metro)可以很好地处理XOP/MTOM的多部分请求。从中学习,因为您无法使它变得更好。

也许您可以尝试将输入流从
多部分文件
定向到S3

考虑以下
uploadFileToS3Bucket
方法:

public PutObjectResult uploadFileToS3Bucket(InputStream输入,长码,字符串标题,字符串描述){
//指示信息的长度,以避免AWS SDK计算信息
//见:https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/s3/model/PutObjectRequest.html#PutObjectRequest-java.lang.String-java.lang.String-java.io.InputStream-com.amazonaws.services.s3.model.ObjectMetadata-
ObjectMetadata ObjectMetadata=新的ObjectMetadata();
objectMetadata.setContentLength(size);//依赖于Spring实现。也许您也可以使用input.available()
//根据需要计算对象名称
字符串键=“…”;
PutObjectRequest PutObjectRequest=新建PutObjectRequest(
this.awsS3Bucket、key、input、objectMetadata
);
//代码的其余部分
如果(启用PublicReadAccess){
putObjectRequest.withCannedAcl(CanneDaccessController.PublicRead);
}
//将文件作为具有ContentType和标题的新对象上载
返回指定的.amazonS3.putObject(putObjectRequest);
}
当然,您需要为服务提供从与
multipartfile
对象关联的客户端请求中获得的输入流:

公共视频添加视频(
@RequestParam(“标题”)字符串标题,
@RequestParam(“描述”)字符串描述,
@RequestParam(value=“file”,required=true)多部分文件(file){
尝试(InputStream输入=file.getInputStream()){
this.amazonS3ClientService.uploadFileToS3Bucket(输入,file.getSize(),title,description));
}
}
您可能还可以使用
MultipartFile
getBytes
方法,创建一个
ByteArrayInputStream
来执行该操作

添加视频中

byte[]bytes=file.getBytes();
上传文件到3bucket

ObjectMetadata ObjectMetadata=new ObjectMetadata();
objectMetadata.setContentLength(bytes.length);
PutObjectRequest PutObjectRequest=新建PutObjectRequest(
this.awsS3Bucket,key,new ByteArrayInputStream(字节),objectMetadata
);

我更喜欢第一种解决方案,但请尝试确定哪个选项为您提供了最佳性能。

您能找到邮件列表的链接吗?这听起来很有趣。@nanomader它需要一个自定义/包装的输入流。如果您想这样做(例如,如果您需要同时上载文档和其他表单数据),您仍然可以执行多部分操作,但您必须阻止Tomcat为您处理解析。相反,您必须自己解析请求,直接读取请求的
InputStream
,并根据需要进行流式处理。问题是,您无法保证元数据(例如文件名)在有效负载(文件字节)之前到达,因此您可能必须编写大量“异常”处理代码(在异常工作流的意义上,而不是抛出的异常)而我的评论只是对如何做到这一点的一般性解释。但正如他所建议的:如果你不需要的话,为什么要重新发明轮子呢。从JAX-WSRI学习并使用MIME解析器依赖项,与SOAP没有任何关系。