【发布时间】:2017-10-02 19:07:01
【问题描述】:
我开发了一个提供 REST 的 Spring MVC 项目。 其中一种方法返回数据的 zip 文件。如果数据包很小(小于 10MB)或者我们收到的连接很少,响应时间还可以,但是如果我有一个 20MB 的文件或一百个请求,它就会很慢。这是我的代码:
@RequestMapping(value = "{venue}/packet", method = RequestMethod.GET)
public ResponseEntity getPackage(@PathVariable("venue") int id,
@RequestParam(value = "reqid", required = false) int reqid,
@RequestParam(value = "version", required = false, defaultValue = "1.0") String version,
@ModelAttribute("user") Developer user, HttpServletRequest request, HttpServletResponse resp) {
String req_code = "[" + Thread.currentThread().getId() + "] ";
long start = System.currentTimeMillis();
// Check if the version of the client is already updated
if (!version.equals(venue.getVersion())) {
//Returns a file from File System
File zipped = venueService.getPacket(venue);
resp.setContentType("application/zip");
resp.setContentLength((int) zipped.length());
resp.setHeader("Content-Disposition", "attachment;filename=" + zipped.getName());
try {
InputStream is = new BufferedInputStream(new FileInputStream(zipped));
long copytime = System.currentTimeMillis();
packet_log.info(req_code + "Start copy req:" + reqid);
IOUtils.copy(is, resp.getOutputStream());
resp.flushBuffer();
is.close();
packet_log.info(req_code + "End copy req:" + reqid + " in " + (System.currentTimeMillis() - copytime));
} catch (IOException e) {
e.printStackTrace();
}
long dur = System.currentTimeMillis() - start;
packet_log.info(req_code + "Send to client req:" + reqid + " in " + dur / 1000);
packet_log.info("");
return new ResponseEntity<Object>("", headers, HttpStatus.OK);
}
我插入了很多日志和一个由客户端和服务器共享的“reqid”参数来监控每个请求。
当我有多个并发请求时,命令IOUtils.copy(is, resp.getOutputStream()); 变得非常慢。如果我发送 80 个请求,复制一个 20MB 的文件需要一分钟以上的时间。
我认为我的代码没有问题。也许这取决于 Spring MVC 如何管理 @RestController bean?还是访问磁盘的 I/O 问题?该系统位于 AWS EC2 虚拟机上。
【问题讨论】:
-
对网速有什么衡量标准吗?一切都在本地主机上吗?它的慢是什么意思?现在几点了?你知不知道,100*20MB 就是 2GB,即使没有网络因素也需要一些时间?
-
你试过
copyLarge方法而不是copy -
@AjitSoman 来自 IOUtils 文档 (commons.apache.org/proper/commons-io/javadocs/api-2.5/org/…):各种复制方法都将实际复制委托给以下方法之一:copyLarge(InputStream, OutputStream, byte[]) copyLarge(InputStream, OutputStream, long, long, byte[]) 例如 copy(InputStream, OutputStream) 调用 copyLarge(InputStream, OutputStream) 再调用 copy(InputStream, OutputStream, int)
-
@mlecz 就像我说的,系统在AWS上,时间记录在远程机器上,所以没有网络问题。我还意识到 Amazon EBS 通用 SSD 的吞吐量为 160 MB/s
-
@zuno 同样的问题,三年后。你终于找到解决办法了吗?
标签: java spring spring-mvc tomcat optimization