我在CXF列表中发布了这个问题,但没有得到任何帮助。所以我们来试试吧。我正在尝试将大文件上传到远程服务器(将它们视为虚拟机磁盘)。所以我有一个接受上传请求的restful服务。上传处理程序如下:
@POST
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Path("/doupload")
public Response receiveStream(MultipartBody multipart) {
List<Attachment> allAttachments = body.getAllAttachments();
Attachment att = null;
for (Attachment b : allAttachments) {
if (UPLOAD_FILE_DESCRIPTOR.equals(b.getContentId())) {
att = b;
}
}
Assert.notNull(att);
DataHandler dh = att.getDataHandler();
if (dh == null) {
throw new WebApplicationException(HTTP_BAD_REQUEST);
}
try {
InputStream is = dh.getInputStream();
byte[] buf = new byte[65536];
int n;
OutputStream os = getOutputStream();
while ((n = is.read(buf)) > 0) {
os.write(buf, 0, n);
}
ResponseBuilder rb = Response.status(HTTP_CREATED);
return rb.build();
} catch (IOException e) {
log.error("Got exception=", e);
throw new WebApplicationException(HTTP_INTERNAL_ERROR);
} catch (NoSuchAlgorithmException e) {
log.error("Got exception=", e);
throw new WebApplicationException(HTTP_INTERNAL_ERROR);
} finally {}
}
这段代码的客户端非常简单:
public void sendLargeFile(String filename) {
WebClient wc = WebClient.create(targetUrl);
InputStream is = new FileInputStream(new File(filename));
Response r = wc.post(new Attachment(Constants.UPLOAD_FILE_DESCRIPTOR,
MediaType.APPLICATION_OCTET_STREAM, is));
}
代码在功能方面运行良好。但在性能方面,我注意到在我的处理程序(receiveStream()方法)获取流的第一个字节之前,整个流实际上会被持久化到一个临时文件中(使用CachedOutputStream)。不幸的是,这对我的目的来说是不可接受的。
- 我的处理程序只需将传入的字节传递给后端存储系统(虚拟机磁盘库),等待整个磁盘被写入缓存再次读取需要很长时间,占用了大量资源,降低了吞吐量。
- 写入块并再次读取它们是有成本的,因为应用程序在云中运行,云提供商按块读/写收费。
- 由于每个字节都被写入本地磁盘,我的服务VM必须有足够的磁盘空间来容纳所有上传的流的总大小(即,如果我有10个100GB的上传,我必须有1TB的磁盘来缓存内容)。这又是额外的开销,因为服务VM的大小会急剧增加,云提供商也会按所提供的磁盘大小收费。
我在这里发现了一个类似的问题。解决方案说使用CXF 2.2.3或更高版本,但我使用的是2.4.4(并尝试过2.7.0),但没有成功。
谢谢。