tomcat HTTP处理—— Request的生命历程和相应Connector配置解析

Request的生命历程,可以参见常量类org.apache.coyote.Constants.java

    // Request states
    public static final int STAGE_NEW = 0;
    public static final int STAGE_PARSE = 1;
    public static final int STAGE_PREPARE = 2;
    public static final int STAGE_SERVICE = 3;
    public static final int STAGE_ENDINPUT = 4;
    public static final int STAGE_ENDOUTPUT = 5;
    public static final int STAGE_KEEPALIVE = 6;
    public static final int STAGE_ENDED = 7;

 

和用到这些常量的地方 Http11Processor.java (代码贴的比较多,可以用浏览器的 查找功能来查找上面的常量)

 while (started && !error && keepAlive && !endpoint.isPaused()) {

            // Parsing the request header
            try {
                if (keptAlive) {
                    if (keepAliveTimeout > 0) {
                        socket.setSoTimeout(keepAliveTimeout);
                    }
                    else if (soTimeout > 0) {
                        socket.setSoTimeout(soTimeout);
                    }
                }
                inputBuffer.parseRequestLine();
                request.setStartTime(System.currentTimeMillis());
                keptAlive = true;
                if (disableUploadTimeout) {
                    socket.setSoTimeout(soTimeout);
                } else {
                    socket.setSoTimeout(timeout);
                }
                inputBuffer.parseHeaders();
            } catch (IOException e) {
                error = true;
                break;
            } catch (Throwable t) {
                if (log.isDebugEnabled()) {
                    log.debug(sm.getString("http11processor.header.parse"), t);
                }
                // 400 - Bad Request
                response.setStatus(400);
                adapter.log(request, response, 0);
                error = true;
            }

            if (!error) {
                // Setting up filters, and parse some request headers
                rp.setStage(org.apache.coyote.Constants.STAGE_PREPARE);
                try {
                    prepareRequest();
                } catch (Throwable t) {
                    if (log.isDebugEnabled()) {
                        log.debug(sm.getString("http11processor.request.prepare"), t);
                    }
                    // 400 - Internal Server Error
                    response.setStatus(400);
                    adapter.log(request, response, 0);
                    error = true;
                }
            }

            if (maxKeepAliveRequests > 0 && --keepAliveLeft == 0)
                keepAlive = false;

            // Process the request in the adapter
            if (!error) {
                try {
                    rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE);
                    adapter.service(request, response);
                    // Handle when the response was committed before a serious
                    // error occurred.  Throwing a ServletException should both
                    // set the status to 500 and set the errorException.
                    // If we fail here, then the response is likely already
                    // committed, so we can't try and set headers.
                    if(keepAlive && !error) { // Avoid checking twice.
                        error = response.getErrorException() != null ||
                                statusDropsConnection(response.getStatus());
                    }

                } catch (InterruptedIOException e) {
                    error = true;
                } catch (Throwable t) {
                    log.error(sm.getString("http11processor.request.process"), t);
                    // 500 - Internal Server Error
                    response.setStatus(500);
                    adapter.log(request, response, 0);
                    error = true;
                }
            }

            // Finish the handling of the request
            try {
                rp.setStage(org.apache.coyote.Constants.STAGE_ENDINPUT);
                // If we know we are closing the connection, don't drain input.
                // This way uploading a 100GB file doesn't tie up the thread 
                // if the servlet has rejected it.
                if(error)
                    inputBuffer.setSwallowInput(false);
                inputBuffer.endRequest();
            } catch (IOException e) {
                error = true;
            } catch (Throwable t) {
                log.error(sm.getString("http11processor.request.finish"), t);
                // 500 - Internal Server Error
                response.setStatus(500);
                adapter.log(request, response, 0);
                error = true;
            }
            try {
                rp.setStage(org.apache.coyote.Constants.STAGE_ENDOUTPUT);
                outputBuffer.endRequest();
            } catch (IOException e) {
                error = true;
            } catch (Throwable t) {
                log.error(sm.getString("http11processor.response.finish"), t);
                error = true;
            }

            // If there was an error, make sure the request is counted as
            // and error, and update the statistics counter
            if (error) {
                response.setStatus(500);
            }
            request.updateCounters();

            rp.setStage(org.apache.coyote.Constants.STAGE_KEEPALIVE);

            // Don't reset the param - we'll see it as ended. Next request
            // will reset it
            // thrA.setParam(null);
            // Next request
            inputBuffer.nextRequest();
            outputBuffer.nextRequest();

        }

        rp.setStage(org.apache.coyote.Constants.STAGE_ENDED);

        // Recycle
        inputBuffer.recycle();
        outputBuffer.recycle();
        this.socket = null;
        // Recycle ssl info
        sslSupport = null;
    }

 

 

 

Connector配置解析:

 

官方文档:

http://tomcat.apache.org/tomcat-6.0-doc/config/http.html

 

文档中讲了比较多的选项的用法,其中,我把比较重要的几个列举下:

 

maxKeepAliveRequests

在服务器关闭socket连接之前,能保持的最大请求数。

 

maxThreads

服务器的最大线程数。讲白了就是Worker的最大数目,当然如果配置开启了Executor的话,这个配置项便是没有用的。

 

这里你会不会有疑问,线程数和请求数有什么关系。根据我上一篇文章tomcat分配请求 的分析,一个Worker线程对应一个请求。

那么你会不会有更多的疑问,maxThreads如何设置得比 maxKeepAliveRequests 小会怎么办?

请看下面这段代码

Http11Processor.java

 int keepAliveLeft = maxKeepAliveRequests;
        int soTimeout = endpoint.getSoTimeout();

        // When using an executor, these values may return non-positive values
        int curThreads = endpoint.getCurrentThreadsBusy();
        int maxThreads = endpoint.getMaxThreads();
        if (curThreads > 0 && maxThreads > 0) {
            // Only auto-disable keep-alive if the current thread usage % can be
            // calculated correctly
            if ((curThreads*100)/maxThreads > 75) {
                keepAliveLeft = 1; // 当前使用线程是最大线程数的75%的时候,会自动禁用keepAlive
            }
        }

 

 while (started && !error && keepAlive) {
……
  if (maxKeepAliveRequests > 0 && --keepAliveLeft == 0)
                keepAlive = false;
……
}

 

当前使用线程是最大线程的75% 的时候,会自动禁用keepAlive

所以maxThreads设置得比maxKeepAliveRequests 小,则这个maxKeepAliveRequests 设置时没有效果的。

当maxThreads设置肯定要比 maxKeepAliveRequests 来的大,而且 maxKeepAliveRequests 不会超过maxThreads的75%!!

默认:maxThreads 为 200

maxKeepAliveRequests  为100

 

 

keepAliveTimeout

 服务器Socket读取HTTP请求行到来的限制时间。 以millionseconds为单位。默认和connectionTimeout 的值一样。

 

connectionTimeout

单位是毫秒,Connector从接受连接到提交URI请求数据的等待的时间。

开始这个我没搞懂,不过找到了这篇文章: http://twotwoandapple.blogbus.com/logs/62770043.html  上面的解释和测试。

也可以看下面的代码:Http11Processor.java

 while (started && !error && keepAlive) {
            // Parsing the request header
            try {
                if (keptAlive) {
                    if (keepAliveTimeout > 0) {
                        socket.setSoTimeout(keepAliveTimeout);
                    }
                    else if (soTimeout > 0) {
                        socket.setSoTimeout(soTimeout);
                    }
                }
                // 服务器获取客户端请求行,这里会调用inputBuffer的read 方法,引起socket阻塞,阻塞时间超过soTimeout的话就会SocketTimeOutException
                inputBuffer.parseRequestLine();

 

 

disableUploadTimeout

是否允许在上传操作的时候给与更长的socketTimeOut时间。默认false不允许。

如果设置为true,则默认为5分钟限制,超过5分钟则会报SocketTimeOut异常。

如果要改这个时间,需要用这个Attribute: timeout 这个官方文档没有写,不知道为什么,可能不建议修改吧,因为5分钟是和apache 的httpd的时间保持一致的。

类似:

    <Connector port="8080" protocol="HTTP/1.1" 
               connectionTimeout="20000" 
               redirectPort="8443" disableUploadTimeout="false" timeout="600000"/>

 

  其中HTTP 协议,最好参考下RFC的文档 结合Http11Protocal 和 Http11Processor来看比较好

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值