Я развернул приложение веб-службы в качестве контейнера Docker на основе tomee: 8-jre-7.0.4-plume, который находится за экземпляром apache httpd: 2.4, запущенным в другом контейнере Docker, запущенном на том же компьютере.
У меня возникают следующие проблемы: a) apache буферизует ответ, который создает значительную задержку, и b) если объем данных слишком велик (10397232 байта), apache закрывает соединение с TomEE, которое сообщает org.apache.catalina.connector. ClientAbortException: java.net.SocketTimeoutException. Я думаю, это соответствует сообщению, которое я вижу в apache error_log (LogLevel trace6) output_filter: flushing из-за THRESHOLD_MAX_BUFFER. Это происходит независимо от того, использую я https или http.
Если я отправляю запросы непосредственно в TomEE, то буферизация ответов не происходит и ошибок с большими запросами не возникает.
Я включаю код, который может воспроизвести проблему. Вы заметите, что я в основном передаю ввод запроса в «cat», а затем передаю его вывод другому «коту». затем скопируйте вывод заключительного вывода «cat» в поток вывода ответа. В «реальном» приложении я не использую cat и делаю что-то гораздо более интересное, но этот пример иллюстрирует суть проблемы. Кроме того, если я модифицирую свой код, чтобы записать вывод окончательного `` кота '' в локальный файл, а затем просто скопирую содержимое этого файла в поток вывода ответа, тогда проблемы исчезнут, однако это вводит тот же вид задержка как буферизация всего ответа.
Я пробовал несколько изменений конфигурации в apache httpd.conf
<IfModule proxy_ajp_module>
ProxyPass "/" "http://localhost:8080/" timeout=18000
TimeOut 18000
</IfModule>
Я пробовал различные комбинации из следующего:
ProxyPass "/" "http://localhost:82/" timeout=18000 flushpackets=on receivebuffersize=8192 iobuffersize=8192
Я также попытался явно установить ряд параметров конфигурации TomEE / Tomcat, как указано в документации. В настоящее время я не использую протокол ajp.
Единственное изменение server.xml, которое в настоящее время существует:
<Connector port="8080" allowTrace="true" ajpFlush="false" maxPostSize="-1" maxSavePostSize="-1" proxyName="mycustomhost.com" protocol="HTTP/1.1"
Я включаю здесь репрезентативный код веб-сервиса:
package com.spike
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.Context;
@Path("test")
public class MinTestingResource {
private final ExecutorService execSvc = Executors.newFixedThreadPool(10);
@POST
public void post(
@Context HttpServletRequest request,
@Context HttpServletResponse response) throws IOException, InterruptedException, ExecutionException {
InputStream in = request.getInputStream();
OutputStream out = response.getOutputStream();
convertStream(in, out);
}
private void convertStream(InputStream in, OutputStream out) throws ExecutionException, IOException, InterruptedException {
Process p1 = new ProcessBuilder("cat").start();
Process p2 = new ProcessBuilder("cat").start();
copyInThread("in-p1", in, p1.getOutputStream());
copyInThread("p1-p2", p1.getInputStream(), p2.getOutputStream());
copy("p2-out", p2.getInputStream(), out);
}
private Future<Long> copyInThread(String nameToLog, InputStream in, OutputStream out) {
AtomicBoolean copierStarted = new AtomicBoolean(false);
final Future<Long> future = execSvc.submit(() -> {copierStarted.set(true); return copy(nameToLog, in, out);});
waitForStart(nameToLog, copierStarted);
return future;
}
private long copy(String nameToLog, InputStream in, OutputStream out) throws IOException {
long copied = 0;
try {
byte[] buf = new byte[8192];
for (int bytesRead = 0; (bytesRead = in.read(buf)) > 0;) {
out.write(buf, 0, bytesRead);
copied += bytesRead;
}
return copied;
} finally {
out.close();
}
}
private void waitForStart(String nameToLog, AtomicBoolean copierStarted) {
pause(5);
while (!copierStarted.get()) {
pause(5);
}
}
private void pause(long millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException ignore) {
}
}
}
Я обнаружил следующую проблему в apache bugzilla Ошибка 61616 - mod_proxy_connect: остановка и потеря соединения при двунаправленном трафике но я не уверен, что это та же проблема, и неясно, доступно ли решение в виде контейнера Docker.