我们有一个用例,我们必须通过http将大数据文件从环境A传输到环境B.我们想要实现的是发送方以块的形式发送数据,接收方开始以块的形式将其写入文件中。因此我们决定使用MTOM。
网络服务代码:
@MTOM(enabled = true, threshold=1024)
@WebService(portName = "fileUploadPort", endpointInterface = "com.cloud.receiver.FileUploadService", serviceName = "FileUploadService")
@BindingType(value = SOAPBinding.SOAP12HTTP_MTOM_BINDING)
public class FileUploadServiceImpl implements FileUploadService {
@Override
public void uploadFile(FileUploader Dfile) {
DataHandler handler = Dfile.getFile();
try {
InputStream is = handler.getInputStream();
OutputStream os = new FileOutputStream(new File(absolutePath));
byte[] b = new byte[10000000];
int bytesRead = 0;
while ((bytesRead = is.read(b)) != -1) {
os.write(b, 0, bytesRead);
}
os.flush();
os.close();
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
客户代码:
public static void main(String args[]) throws Exception {
URL url = new URL("http://localhost:8080/CloudReceiver/FileUploadService?wsdl");
QName qname = new QName("http://receiver.cloud.com/", "FileUploadService");
Service service = Service.create(url, qname);
FileUploadService port = service.getPort(FileUploadService.class);
// enable MTOM in client
BindingProvider bp = (BindingProvider) port;
SOAPBinding binding = (SOAPBinding) bp.getBinding();
binding.setMTOMEnabled(true);
FileUploader f = new FileUploader();
DataSource source = new FileDataSource(new File("G:\\Data\\Sender\\temp.csv"));
DataHandler dh = new DataHandler(source);
Map<String, Object> ctxt = ((BindingProvider) port).getRequestContext();
// Marking Chunk size at Client.
ctxt.put(JAXWSProperties.HTTP_CLIENT_STREAMING_CHUNK_SIZE, 100);
f.setFile(dh);
port.uploadFile(f);
}
当我们传输小于100MB的数据时,每件事都可以正常工作。 超过(100MB +)的数据文件应用服务器(JBoss 8.2)在接收端结束时抛出异常。
java.io.IOException: UT000020: Connection terminated as request was larger than 104857600
我认为这个错误是因为standalone.xml中的属性
<http-listener name="default" socket-binding="http" max-post-size="104857600"/>
这意味着数据不会写入Chunks中的文件,而是保存在内存中,而不是在传输完成后写入文件。
我们如何在Chunks中实现将数据写入文件?我们不希望后期内存增加。文件大小可以达到1 TB的范围。
环境: JBoss 8.2 Wild Fly,Java 8
答案 0 :(得分:0)
首先,提到的限制
<http-listener name="default" socket-binding="http" max-post-size="104857600"/>
表示服务器将接受的整个POST请求的最大大小。
无论是否使用MTOM,是否使用大块-您在此处仅发送一个POST请求即可发送文件。使用块不会改变这一点-所有带有文件数据的块都是同一POST请求的一部分。
因此,它可以按预期的方式工作:100M +个文件因限制而过大。
那我很确定这个结论
这意味着数据不会以块的形式写入文件,而是会保存在内存中,而不会在传输完成后写入文件。
完全是错误的。在内存中保留潜在的大卷并不安全,因此服务器通常不这样做,而是将这些卷放入一些临时文件中。
答案 1 :(得分:0)
Sudeep :这意味着数据不会以块的形式写入文件,而是会保存在内存中,然后在传输完成后写入文件。
-> 那肯定不是真的。
以下限制:
<http-listener name="default" socket-binding="http" max-post-size="104857600"/>
..表示单个(最终成块的)POST请求的最大正文大小不能超过104857600字节。这与 HTTP content-length 标头和JBoss自身功能(如缓冲区)的配置有关。
Cf。 https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html The Content-Length entity-header field indicates the size of the entity-body, in decimal number of OCTETs, sent to the recipient or, in the case of the HEAD method, the size of the entity-body that would have been sent had the request been a GET.
我建议执行Wireshark分析以说服自己。
。
Sudeep :我们要实现的是,发送方以块的形式发送数据,接收方开始以块的形式将其写入文件。因此,我们 决定使用MTOM。
-> 我认为这是一个错误的决定。
MTOM并非专门用于分块数据。 SOAP Message Transmission Optimization Mechanism (MTOM)
主要定义了两个优化:
总而言之,MTOM不能解决您的问题。
HTTP协议并非旨在交换非常大的数据文件。正如您提到的1TB(!)数据,我建议采取完全不同的策略。
原因是与更合适的协议相比,HTTP协议具有大量开销(即使可以说,如果从A到Z最佳使用(即具有较大的MTU和块大小),开销比率将显着降低)。但是请求-响应模型也不适用于文件传输。如果没有有效的请求和恢复方法的并行化,您可能还会遇到非常大的文件传输问题。甚至没有考虑防火墙,(反向)代理服务器和其他工具,这些工具可能会认为这种流量特别异常或“越界”。
我的建议实际上是找到使用方式 (S)FTP 进行大型文件传输。该协议的目的是。如果您的用例匹配,最终考虑使用对等替代方案。
但是绝对不要在此用例中使用HTTP。除非您决定进行切片(因此要进行多个请求),否则请使用压缩方法(最终进行堆叠)并优化整个传输链。
祝你好运。