Отправка файла между системами A-> B-> C без сохранения всего файла в B
У меня есть 3 отдельных веб-приложения spring
- A использует spring 4.x
- B использует spring 3.2.0
- C использует spring 4.x
B и C предоставляет контроллеры REST для загрузки файлов
- A читает файл и загружает его в B
- B отправляет запрос C без необходимости читать содержимое файла
- а затем C делает все, что захочет, с файлом.
Таким образом, поток будет A- > B- > C
Мой вопрос: возможно ли установить B таким образом, чтобы B не сохранял весь файл в памяти, но читал бы входящий поток и переместите его на C?
Что мне удалось сделать:
А
public void sendFileFromA() throws FileNotFoundException {
final InputStream fis = new FileInputStream(new File("someFile"));
final RequestCallback requestCallback = new RequestCallback() {
@Override
public void doWithRequest(final ClientHttpRequest request) throws IOException {
request.getHeaders().add("Content-type", "application/octet-stream");
IOUtils.copy(fis, request.getBody());
}
};
final RestTemplate restTemplate = new RestTemplate();
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
requestFactory.setBufferRequestBody(false);
restTemplate.setRequestFactory(requestFactory);
final HttpMessageConverterExtractor<String> responseExtractor = new HttpMessageConverterExtractor<>(
String.class, restTemplate.getMessageConverters());
restTemplate.execute("http://b_url/upload", HttpMethod.POST, requestCallback, responseExtractor);
}
В
@RequestMapping(value = "/upload", method = RequestMethod.POST)
public @ResponseBody String handleFileUpload(HttpServletRequest request) throws IOException {
final ServletInputStream input = request.getInputStream();
final RequestCallback requestCallback = new RequestCallback() {
@Override
public void doWithRequest(final ClientHttpRequest request) throws IOException {
request.getHeaders().add("Content-type", "application/octet-stream");
try (OutputStream body = request.getBody()) {
IOUtils.copy(input, body);
}
}
};
final RestTemplate restTemplate = new RestTemplate();
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
requestFactory.setBufferRequestBody(false);
restTemplate.setRequestFactory(requestFactory);
final HttpMessageConverterExtractor<String> responseExtractor = new HttpMessageConverterExtractor<>(
String.class, restTemplate.getMessageConverters());
restTemplate.execute("http://c_url/upload", HttpMethod.POST, requestCallback, responseExtractor);
return "success";
}
С
@RequestMapping(value = "/upload", method = RequestMethod.POST)
public @ResponseBody String handleFileUpload(HttpServletRequest request) throws IOException {
ServletInputStream input = request.getInputStream();
try (BufferedOutputStream output = new BufferedOutputStream(new FileOutputStream("zibiTest"))) {
IOUtils.copy(input, output);
}
return "success";
}
Я могу легко копировать файлы более > 10 ГБ с A на C с помощью B.
С таким решением мы можем попытаться остановить A во время передачи, B и C должны быть уведомлены об ошибке, но иногда бывает так, что сообщение об ошибке не достигает C - он закрывается с исключением тайм-аута сокета, любая идея почему это происходит и как правильно его реализовать?
Является ли этот подход действительным или его можно обработать лучше?
Ответы
Ответ 1
Я попытался бы установить меньший тайм-аут сокета на C, чем у вас на B. В настоящее время кажется, что оба имеют значение по умолчанию, поэтому, если A зависает, оба B и C перестанут получать данные почти в одно и то же время. Оба запускают тайм-аут, и, возможно, это состояние гонки, где это зависит от точности таймаута, которая в первый раз заканчивается.
Ответ 2
Вы думали о Flume? Из того, что я вижу, проблема заключается в том, чтобы не хранить его в B и файлах, я полагаю, что они могут быть большими. В таких случаях, почему бы не использовать поток Apache Flume для потоковой передачи файлов непосредственно на канал, а затем в ваш приемник, который будет вашим B, и выгрузите его в конечный пункт назначения "C". Однако большой файл, эта арка помогает.
Как сказал кто-то: "Если мои знания ограничены проблемой, которую только вы видите, я могу быть только средством для решения, а не самим решением"