java: Apache dampens the tomcat responses and closes the connection with tomcat when the size of the request exceeds 10397232 bytes

I have implemented a web service application as a Docker container based on tomee: 8-jre-7.0.4-plume that is behind an apache instance httpd: 2.4 that runs in another Docker container that runs on the same machine .

The problems are that a) apache is buffering the response, which creates significant latency and b) if the amount of data is too large (10397232 bytes) apache closes the connection with TomEE that informs org.apache.catalina.connector .ClientAbortException: java .net.SocketTimeoutException. I think this corresponds to a message I see in apache error_log (LogLevel trace6) output_filter: flushing due to THRESHOLD_MAX_BUFFER. This happens regardless of whether I use https or http.

If I send requests directly to TomEE, a response buffer does not occur or errors occur with large requests.

I include a code that can reproduce the problem. You will notice that I am basically channeling the request entry to & # 39; cat & # 39 ;, and then channeling your output to another & # 39; cat & # 39; cat. then copy the output of the final output & # 39; cat & # 39; to the response output flow. In the real & # 39; application, I'm not using cat and I'm doing something much more interesting, but this example illustrates the crux of the problem. Also, if I modify my code to write the output of the & # 39; cat & # 39; end in a local file, then simply copy the contents of that file into the response output sequence, then the problems disappear, however, this introduces the same type of latency as the buffer of the entire response.

I tried a series of configuration changes in apache httpd.conf

    ProxyPass "/" "http: // localhost: 8080 /" timeout = 18000
TimeOut 18000

I tried several combinations of the following:

                ProxyPass "/" "http: // localhost: 82 /" timeout = 18000 flushpackets = on receivebuffersize = 8192 iobuffersize = 8192

I also tried to explicitly establish a series of TomEE / Tomcat configuration settings as mentioned in the documentation. I am not using the ajp protocol at this time.

The only server.xml change that is currently in effect is:

<Connector port = "8080" allowTrace = "true" ajpFlush = "false" maxPostSize = "- 1" maxSavePostSize = "- 1" proxyName = "" protocol = "HTTP / 1.1"

I include the representative web service code here:

com.spike package

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;

@Path ("test")
public class MinTestingResource {
Private end ExecutorService execSvc = Executors.newFixedThreadPool (10);
canceled public publication
Request @Context HttpServletRequest,
Answer from @Context HttpServletResponse) throws IOException, InterruptedException, ExecutionException {
InputStream on = request.getInputStream ();
OutputStream out = response.getOutputStream ();
convertStream (input, output);
private void convertStream (InputStream in, OutputStream out) throw 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 copyInThread (String nameToLog, InputStream in, OutputStream out) {
AtomicBoolean copierStarted = new AtomicBoolean (false);
final future future = execSvc.submit (() -> {copierStarted.set (true); return copy (nameToLog, in, out);});
waitForStart (nameToLog, copierStarted);
future return
the private long copy (String nameToLog, InputStream in, OutputStream out) throws IOException {
long copy = 0;
try {
byte[] buf = new byte[8192];
for (int bytesRead = 0; (bytesRead = (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 empty pause (long milis) {
try {
Thread.sleep (millis);
} catch (InterruptedException ignore) {