tomcat 常见参数

tomcat可以绑定多个端口,也就是可以建立多个connector,每个connector的配置及绑定,过程如下:

tomcat启动之前,建立connector,并指定参数,可以添加多个connector,每个connector对应一个端口。

 @Bean
    public ServletWebServerFactory servletContainer() {
        TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
        tomcat.addAdditionalTomcatConnectors(createConnector());
        return tomcat;
    }
private Connector createConnector() {
        Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
        Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler();
        try {
            protocol.setKeepAliveTimeout(30000);
            protocol.setMaxKeepAliveRequests(100);
            protocol.setMaxConnections(1000);
            protocol.setAcceptCount(100);
            protocol.setMaxThreads(1000);
            return connector;
        }
        catch (IOException ex) {
          
        }
    }

绑定监听端口,并指定acceptQueue大小

   // ----------------------------------------------- Public Lifecycle Methods
    /**
     * Initialize the endpoint.
     */
    @Override
    public void bind() throws Exception {
        ...
        serverSock.socket().bind(addr,getAcceptCount());
        serverSock.configureBlocking(true); //mimic APR behavior
        ...
        // Initialize thread count defaults for acceptor, poller
        // Initialize SSL if needed
    }

t初始化最大链接数,创建线程池,创建多个Poller线程,创建多个Acceptor

/**
     * Start the NIO endpoint, creating acceptor, poller threads.
     */
    @Override
    public void startInternal() throws Exception {
        if (!running) {
            ...
            // Create worker collection
            createExecutor();
            //最大链接数
            initializeConnectionLatch();
            // Start poller threads
            pollers = new Poller[getPollerThreadCount()];
            ...
            startAcceptorThreads();
        }
    }

1 acceptCount

-serverSock.socket().bind(addr,getAcceptCount());
注:socket 请求完成队列数量,如果socket链接数量超过maxConnections,Acceptor线程进入等待状态,不会接accept新的链接,后续完成建链的请求会占用acceptQueue,占满后会导致后续请求建链失败。

2 maxConnections

链接接入:

countUpOrAwaitConnection() 检查是否超过最大链接数,如果超过则进入等待状态,直到有链接释放,不会再接入新的链接;
setSocketOptions(socket) 将Poller注册到socket进行实践监听,所有socket的请求都由Poller进行处理。

    // --------------------------------------------------- Acceptor Inner Class
    /**
     * The background thread that listens for incoming TCP/IP connections and
     * hands them off to an appropriate processor.
     */
    protected class Acceptor extends AbstractEndpoint.Acceptor {
        @Override
        public void run() {
            // Loop until we receive a shutdown command
            while (running) {
                ...
                try {
                    //if we have reached max connections, wait
                    countUpOrAwaitConnection();
                    SocketChannel socket = null;
                    try {
                        // Accept the next incoming connection from the server
                        // socket
                        socket = serverSock.accept();
                    } ...
                    // Successful accept, reset the error delay
                   ...
        }
}

3 maxThreads

Executor线程池,最大线程数,tomcat线程池如下,默认使用TaskQueue,线程池的队列为LinkedBlockingQueue,LinkedBlockingQueue可以无限增加,也就是其最大数量为最大链接数(当然不包括每个socket有多个链接的场景):

    public void createExecutor() {
        internalExecutor = true;
        TaskQueue taskqueue = new TaskQueue();
        TaskThreadFactory tf = new TaskThreadFactory(getName() + "-exec-", daemon, getThreadPriority());
        executor = new ThreadPoolExecutor(getMinSpareThreads(), getMaxThreads(), 60, TimeUnit.SECONDS,taskqueue, tf);
        taskqueue.setParent( (ThreadPoolExecutor) executor);
    }

/**
 * As task queue specifically designed to run with a thread pool executor. The
 * task queue is optimised to properly utilize threads within a thread pool
 * executor. If you use a normal queue, the executor will spawn threads when
 * there are idle threads and you wont be able to force items onto the queue
 * itself.
 */
public class TaskQueue extends LinkedBlockingQueue<Runnable> {
    // ---------------------------------------------- Request processing methods

    /**
     * Process the given SocketWrapper with the given status. Used to trigger
     * processing as if the Poller (for those endpoints that have one)
     * selected the socket.
     *
     * @param socketWrapper The socket wrapper to process
     * @param event         The socket event to be processed
     * @param dispatch      Should the processing be performed on a new
     *                          container thread
     *
     * @return if processing was triggered successfully
     */
    public boolean processSocket(SocketWrapperBase<S> socketWrapper,
            SocketEvent event, boolean dispatch) {
        try {
            ...
            SocketProcessorBase<S> sc = processorCache.pop();
            ...
            Executor executor = getExecutor();
            if (dispatch && executor != null) {
                executor.execute(sc);
            } else {
                sc.run();
            }
            ...
    }

4 Keep-Alive

意味着一旦建立socket就可以不断的发送请求到服务端,而不需要重新建链(TCP三次握手),使用keep-alive的好处有如下几点:
https://tools.ietf.org/html/rfc2616

Persistent HTTP connections have a number of advantages:

  - By opening and closing fewer TCP connections, CPU time is saved
    in routers and hosts (clients, servers, proxies, gateways,
    tunnels, or caches), and memory used for TCP protocol control
    blocks can be saved in hosts.

  - HTTP requests and responses can be pipelined on a connection.
    Pipelining allows a client to make multiple requests without
    waiting for each response, allowing a single TCP connection to
    be used much more efficiently, with much lower elapsed time.

  - Network congestion is reduced by reducing the number of packets
    caused by TCP opens, and by allowing TCP sufficient time to
    determine the congestion state of the network.

  - Latency on subsequent requests is reduced since there is no time
    spent in TCP's connection opening handshake.

  - HTTP can evolve more gracefully, since errors can be reported
    without the penalty of closing the TCP connection. Clients using
    future versions of HTTP might optimistically try a new feature,
    but if communicating with an older server, retry with old
    semantics after an error is reported.

socket的请求由Poller处理。

    /**
     * Poller class.
     */
    public class Poller implements Runnable {
        /**
         * The background thread that adds sockets to the Poller, checks the
         * poller for triggered events and hands the associated socket off to an
         * appropriate processor as events occur.
         */
        @Override
        public void run() {
            // Loop until destroy() is called
            while (true) {
                ...
                timeout(keyCount,hasEvents);
            }//while
        }

由每个connector的请求处理过程可以看出,消息流应该是:

1 NioEndpoint 初始化 serverSock
2 Acceptors 并发的调 serverSocket.accept()获取链接
3 将socket设置为阻塞状态,获取NioChannel,并将Poller(通过轮寻获得)注册到NioChannel,唤醒selector;

    /**
     * Process the specified connection.
     * @param socket The socket channel
     * @return <code>true</code> if the socket was correctly configured
     *  and processing may continue, <code>false</code> if the socket needs to be
     *  close immediately
     */
    protected boolean setSocketOptions(SocketChannel socket) {
        // Process the connection
        try {
            //disable blocking, APR style, we are gonna be polling it
            socket.configureBlocking(false);
            Socket sock = socket.socket();
            socketProperties.setProperties(sock);

            NioChannel channel = nioChannels.pop();
            ...
            getPoller0().register(channel);
            ...
    }

/**
     * Return an available poller in true round robin fashion.
     * @return The next poller in sequence
     */
    public Poller getPoller0() {
        int idx = Math.abs(pollerRotater.incrementAndGet()) % pollers.length;
        return pollers[idx];
    }
       /**
         * Registers a newly created socket with the poller.
         */
        public void register(final NioChannel socket) {
            socket.setPoller(this);
            NioSocketWrapper ka = new NioSocketWrapper(socket, NioEndpoint.this);
            socket.setSocketWrapper(ka);
            ka.setPoller(this);
            ...
            PollerEvent r = eventCache.pop();
            ka.interestOps(SelectionKey.OP_READ);//this is what OP_REGISTER turns into.
            if ( r==null) r = new PollerEvent(socket,ka,OP_REGISTER);
            else r.reset(socket,ka,OP_REGISTER);
            addEvent(r);
        } 
        //添加监听事件,唤醒selector
       private void addEvent(PollerEvent event) {
            events.offer(event);
            if ( wakeupCounter.incrementAndGet() == 0 ) selector.wakeup();
        }

5 请求由Poller转给内部线程池

还需要看下selector是怎么玩的?


image.png

参考:
https://www.jianshu.com/p/76ff17bc6dea

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,233评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,013评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,030评论 0 241
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,827评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,221评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,542评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,814评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,513评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,225评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,497评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,998评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,342评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,986评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,055评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,812评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,560评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,461评论 2 266

推荐阅读更多精彩内容