Java Spring多部分文件的高延迟
我目前正在从事一个SpringBoot项目,在该项目中,我必须通过RESTWeb服务将文件(一次一个)发送到服务器,服务器将文件发送到Cassandra集群 这部分是可行的,但当我开始对我的项目进行压力测试(与Gatling一起)时,我的问题就出现了 在这里:Java Spring多部分文件的高延迟,java,spring,spring-boot,Java,Spring,Spring Boot,我目前正在从事一个SpringBoot项目,在该项目中,我必须通过RESTWeb服务将文件(一次一个)发送到服务器,服务器将文件发送到Cassandra集群 这部分是可行的,但当我开始对我的项目进行压力测试(与Gatling一起)时,我的问题就出现了 在这里: -当我在不发送文件的情况下测试我的工作时,我有大约10-15毫秒的延迟 -当我测试在请求主体中发送文件的工作时,我也有大约10-15毫秒的延迟(我不记得可能会稍微高出5或10毫秒) -但是,我的问题就出现在这里,当我通过使用输入发送文件并
-当我在不发送文件的情况下测试我的工作时,我有大约10-15毫秒的延迟
-当我测试在请求主体中发送文件的工作时,我也有大约10-15毫秒的延迟(我不记得可能会稍微高出5或10毫秒)
-但是,我的问题就出现在这里,当我通过使用
输入发送文件并使用MultipartFile获取文件来测试Web服务时,延迟非常多变,从最快的请求的10毫秒到最长的12000毫秒(!!)
我试图将内存中的文件限制设置为1Go(最初是~10ko),但没有改变任何东西。
我在执行测试时没有收到任何错误,只是很长
另外,这个项目是为了使现有的Web服务现代化,它以JAX-WS的形式运行,并使用WSDL和其他工具。处理旧项目的团队(我们正在从一个DBMS切换到另一个DBMS)平均响应时间为~10
这是我的配置(这是用于POC的,机器很便宜):
-Web服务器:Wildfly 9-0-1.FINAL开箱即用,在CentOS服务器7.1上
-压力测试机:Gatling 2.1.7,与Wildfly在同一CentOS版本上,但在另一台机器上
-一个8节点的Cassandra集群
这是我的pom(没有公司的秘密|关于spring启动依赖性,它不是我的项目的父项目,它已经有了一个):
WS.java(仅相关函数):
我做错了什么
谢谢你的帮助:)我知道你在比较苹果和桔子。。。您正在将SOAP WS与普通web方法进行比较。那些是不同的动物。另外,如果您想要性能,您可能希望进行流式上载,而不是解析多部分文件
。这还取决于文件的大小。是的,但我认为REST方法比SOAP信封更快,后者会向请求中添加大量数据。如何流式上传?我的文件大小为100-150kB。编辑:你的意思是把文件放在请求的主体中?使用SOAP,你已经有了完全准备好的XML,现在你正在上传一个文件。如果它很大,则需要一段时间,因为它在内存中,部分在磁盘上,被解析为一个多部分文件
。XML不需要的所有东西。对于流媒体,请禁用多部分文件处理,并在控制器方法中执行。好的,我按照您所说的做了(我想),但我的响应时间仍然很高(最大245ms,平均154ms)。也许我错过了什么?我的代码就在这里(我试过使用@EnableAutoConfiguration,但没有它)(如果你想让我把它放在其他地方让它更可读,就说出来吧,我只是不知道通过回答我的问题把它放在旁边的什么地方)这并不能真正禁用多部分文件
解析,你仍然需要排除自动配置。还要确保在调试时不记录所有内容。在它上面加一个分析器,看看它是从哪里来的(延迟)。或者将multipart.enabled=false
添加到您的应用程序.properties
。还有,你为什么自己解析URL?foo
和bar
已经作为@PathVariable
s出现,并且可以自动注入到您的方法中。在比较苹果和橙子时。。。您正在将SOAP WS与普通web方法进行比较。那些是不同的动物。另外,如果您想要性能,您可能希望进行流式上载,而不是解析多部分文件
。这还取决于文件的大小。是的,但我认为REST方法比SOAP信封更快,后者会向请求中添加大量数据。如何流式上传?我的文件大小为100-150kB。编辑:你的意思是把文件放在请求的主体中?使用SOAP,你已经有了完全准备好的XML,现在你正在上传一个文件。如果它很大,则需要一段时间,因为它在内存中,部分在磁盘上,被解析为一个多部分文件
。XML不需要的所有东西。对于流媒体,请禁用多部分文件处理,并在控制器方法中执行。好的,我按照您所说的做了(我想),但我的响应时间仍然很高(最大245ms,平均154ms)。也许我错过了什么?我的代码就在这里(我试过使用@EnableAutoConfiguration,但没有它)(如果你想让我把它放在其他地方让它更可读,就说出来吧,我只是不知道通过回答我的问题把它放在旁边的什么地方)这并不能真正禁用多部分文件
解析,你仍然需要排除自动配置。还要确保在调试时不记录所有内容。在它上面加一个分析器,看看它是从哪里来的(延迟)。或者将multipart.enabled=false
添加到您的应用程序.properties
。还有,你为什么自己解析URL?foo
和bar
已经作为@PathVariable
存在,并且可以自动注入到方法中。
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>1.3.0.RELEASE</version>
<exclusions>
<exclusion>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-websocket</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<version>1.3.0.RELEASE</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-io</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
</dependencies>
<properties>
<java.version>1.8</java.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.6</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-releases</id>
<url>https://repo.spring.io/libs-release</url>
</repository>
<repository>
<id>oss-jfrog-artifactory</id>
<name>oss-jfrog-artifactory-releases</name>
<url>http://oss.jfrog.org/artifactory/oss-release-local</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-releases</id>
<url>https://repo.spring.io/libs-release</>
</pluginRepository>
</pluginRepositories>
<dependencyManagement>
<dependencies>
<dependency>
<!-- Import dependency management from Spring Boot -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>1.3.0.RELEASE</version>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
package foo.bar;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.web.MultipartAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.web.SpringBootServletInitializer;
import org.springframework.context.annotation.Bean;
import org.springframework.web.multipart.MultipartResolver;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
@SpringBootApplication
@EnableAutoConfiguration(exclude = MultipartAutoConfiguration.class)
public class StartApp extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(
SpringApplicationBuilder application) {
return application.sources(StartApp.class);
}
public static void main(String[] args) {
SpringApplication.run(StartApp.class, args);
}
@Bean(name = "multipartResolver")
public MultipartResolver multipartResolver() {
CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
multipartResolver.setMaxInMemorySize(1024 * 1024 * 1024); // 1Go
return multipartResolver;
}
}
import static org.springframework.web.bind.annotation.RequestMethod.POST;
import java.io.IOException;
import java.io.InputStream;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;
import service.DaoException;
import service.ErrCode;
import service.IService;
...
@Inject IService service;
...
@RequestMapping(path = "/insert/{foo}/{bar}", method = POST)
public ResponseEntity<Void> insert(@PathVariable String foo,
@PathVariable String bar,
@RequestParam MultipartFile document) {
HttpStatus httpCode = HttpStatus.CREATED;
try (InputStream is = document.getInputStream()) {
service.insert(foo, bar, is);
} catch (DaoException e) {
logger.error("Problème lors de l'insertion du document : "
+ e.getMessage());
httpCode = handleError(e.getCode());
} catch (IOException e1) {
logger.error("Problème lors du traitement du document envoyé : "
+ e1.getMessage());
httpCode = handleError(ErrCode.PB_TECHNIQUE);
}
return ResponseEntity.status(httpCode).build();
}
import io.gatling.core.Predef._
import io.gatling.http.Predef._
import scala.concurrent.duration._
import java.nio.file.Files
import java.nio.file.Paths
import java.nio.file.Path
import java.util.Base64
import java.io.File
import java.lang.String
class RestSimulation1 extends Simulation {
val DEBIT = 30 //Clients per second
val DUREE = 300 //Duration
val httpConf = http
.baseURL("http://myserver:8080") // Here is the root for all relative urls
.acceptHeader("text/html,application/xhtml+xml,application/json,application/xml;q=0.9,*/*;q=0.8") // Here are the common headers
.doNotTrackHeader("1")
.acceptLanguageHeader("en-US,en;q=0.5")
.acceptEncodingHeader("gzip, deflate")
.userAgentHeader("Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0")
//Feeders creation
val feeder = csv("9k_rest.csv").queue
object Insert {
val insert = feed(feeder)
.exec(http("insertion")
.post("/webservice/ws/insert/${fooo}/${bar}")
.formUpload("document", "rest_insert_${format}.txt")
.check(status.is(201)))
}
val scn = scenario("").exec(Insert.insert)
setUp(scn.inject( constantUsersPerSec(DEBIT) during(DUREE seconds))).protocols(httpConf)
}