精华内容
下载资源
问答
  • tomcat调优之监控连接数和连接池

    千次阅读 2019-01-04 18:23:40
    Tomcat配置文件server.xml中:Connector的主要功能,是接收连接请求,创建Request和Response对象用于和请求端交换数据;然后分配线程让Engine(也就是Servlet容器)来处理这个请求,并把产生的Request和...

    一:前言

    在使用tomcat时,经常会遇到连接数、线程数之类的配置问题,要真正理解这些概念,必须先了解Tomcat的连接器(Connector)。

    Tomcat配置文件server.xml中:Connector的主要功能,是接收连接请求,创建Request和Response对象用于和请求端交换数据;然后分配线程让Engine(也就是Servlet容器)来处理这个请求,并把产生的Request和Response对象传给Engine。当Engine处理完请求后,也会通过Connector将响应返回给客户端。

    可以说,Servlet容器处理请求,是需要Connector进行调度和控制的,Connector是Tomcat处理请求的主干,因此Connector的配置和使用对Tomcat的性能有着重要的影响。这篇文章将从Connector入手,讨论一些与Connector有关的重要问题,包括NIO/BIO模式、线程池、连接数等。

    根据协议的不同,Connector可以分为HTTP Connector、AJP Connector等,本文只讨论HTTP Connector。

     

    二:Nio、Bio、APR

    1.Connector的protocol

    Connector在处理HTTP请求时,会使用不同的protocol。不同的Tomcat版本支持的protocol不同,其中最典型的protocol包括BIO、NIO和APR(Tomcat7中支持这3种,Tomcat8增加了对NIO2的支持,而到了Tomcat8.5和Tomcat9.0,则去掉了对BIO的支持)。

    BIO是Blocking IO,顾名思义是阻塞的IO;NIO是Non-blocking IO,则是非阻塞的IO。而APR是Apache Portable Runtime,是Apache可移植运行库,利用本地库可以实现高可扩展性、高性能;Apr是在Tomcat上运行高并发应用的首选模式,但是需要安装apr、apr-utils、tomcat-native等包。

    2.如何指定protocol

    Connector使用哪种protocol,可以通过<connector>元素中的protocol属性进行指定,也可以使用默认值。

    指定的protocol取值及对应的协议如下:

    • HTTP/1.1:默认值,使用的协议与Tomcat版本有关

    • org.apache.coyote.http11.Http11Protocol:BIO

    • org.apache.coyote.http11.Http11NioProtocol:NIO

    • org.apache.coyote.http11.Http11Nio2Protocol:NIO2

    • org.apache.coyote.http11.Http11AprProtocol:APR

    如果没有指定protocol,则使用默认值HTTP/1.1,其含义如下:在Tomcat7中,自动选取使用BIO或APR(如果找到APR需要的本地库,则使用APR,否则使用BIO);在Tomcat8中,自动选取使用NIO或APR(如果找到APR需要的本地库,则使用APR,否则使用NIO)。

    3.BIO/NIO有何不同

    无论是BIO,还是NIO,Connector处理请求的大致流程是一样的:

    在accept队列中接收连接(当客户端向服务器发送请求时,如果客户端与OS完成三次握手建立了连接,则OS将该连接放入accept队列);在连接中获取请求的数据,生成request;调用servlet容器处理请求;返回response为了便于后面的说明,首先明确一下连接与请求的关系:连接是TCP层面的(传输层),对应socket;请求是HTTP层面的(应用层),必须依赖于TCP的连接实现;一个TCP连接中可能传输多个HTTP请求。

    在BIO实现的Connector中,处理请求的主要实体是JIoEndpoint对象。JIoEndpoint维护了Acceptor和Worker:Acceptor接收socket,然后从Worker线程池中找出空闲的线程处理socket,如果worker线程池没有空闲线程,则Acceptor将阻塞。其中Worker是Tomcat自带的线程池,如果通过<Executor>配置了其他线程池,原理与Worker类似。

    在NIO实现的Connector中,处理请求的主要实体是NIoEndpoint对象。NIoEndpoint中除了包含Acceptor和Worker外,还是用了Poller,处理流程如下图所示

     

    Acceptor接收socket后,不是直接使用Worker中的线程处理请求,而是先将请求发送给了Poller,而Poller是实现NIO的关键。Acceptor向Poller发送请求通过队列实现,使用了典型的生产者-消费者模式。在Poller中,维护了一个Selector对象;当Poller从队列中取出socket后,注册到该Selector中;然后通过遍历Selector,找出其中可读的socket,并使用Worker中的线程处理相应请求。与BIO类似,Worker也可以被自定义的线程池代替。

    通过上述过程可以看出,在NIoEndpoint处理请求的过程中,无论是Acceptor接收socket,还是线程处理请求,使用的仍然是阻塞方式;但在“读取socket并交给Worker中的线程”的这个过程中,使用非阻塞的NIO实现,这是NIO模式与BIO模式的最主要区别(其他区别对性能影响较小,暂时略去不提)。而这个区别,在并发量较大的情形下可以带来Tomcat效率的显著提升:

    目前大多数HTTP请求使用的是长连接(HTTP/1.1默认keep-alive为true),而长连接意味着,一个TCP的socket在当前请求结束后,如果没有新的请求到来,socket不会立马释放,而是等timeout后再释放。如果使用BIO,“读取socket并交给Worker中的线程”这个过程是阻塞的,也就意味着在socket等待下一个请求或等待释放的过程中,处理这个socket的工作线程会一直被占用,无法释放;因此Tomcat可以同时处理的socket数目不能超过最大线程数,性能受到了极大限制。而使用NIO,“读取socket并交给Worker中的线程”这个过程是非阻塞的,当socket在等待下一个请求或等待释放时,并不会占用工作线程,因此Tomcat可以同时处理的socket数目远大于最大线程数,并发性能大大提高。

     

    三:acceptCount、maxConnections、maxThreads

    再回顾一下Tomcat处理请求的过程accept队列中接收连接(当客户端向服务器发送请求时,如果客户端与OS完成三次握手建立了连接,则OS将该连接放入accept队列);在连接中获取请求的数据,生成request;调用servlet容器处理请求;返回response

    相对应的,Connector中的几个参数功能如下:

    1.acceptCount

    accept队列的长度;当accept队列中连接的个数达到acceptCount时,队列满,进来的请求一律被拒绝。默认值是100。

    2.maxConnections

    Tomcat在任意时刻接收和处理的最大连接数。当Tomcat接收的连接数达到maxConnections时,Acceptor线程不会读取accept队列中的连接;这时accept队列中的线程会一直阻塞着,直到Tomcat接收的连接数小于maxConnections。如果设置为-1,则连接数不受限制。

    默认值与连接器使用的协议有关:NIO的默认值是10000,APR/native的默认值是8192,而BIO的默认值为maxThreads(如果配置了Executor,则默认值是Executor的maxThreads)。

    在windows下,APR/native的maxConnections值会自动调整为设置值以下最大的1024的整数倍;如设置为2000,则最大值实际是1024。

    3.maxThreads

    请求处理线程的最大数量。默认值是200(Tomcat7和8都是的)。如果该Connector绑定了Executor,这个值会被忽略,因为该Connector将使用绑定的Executor,而不是内置的线程池来执行任务。

    maxThreads规定的是最大的线程数目,并不是实际running的CPU数量;实际上,maxThreads的大小比CPU核心数量要大得多。这是因为,处理请求的线程真正用于计算的时间可能很少,大多数时间可能在阻塞,如等待数据库返回数据、等待硬盘读写数据等。因此,在某一时刻,只有少数的线程真正的在使用物理CPU,大多数线程都在等待;因此线程数远大于物理核心数才是合理的。

    换句话说,Tomcat通过使用比CPU核心数量多得多的线程数,可以使CPU忙碌起来,大大提高CPU的利用率。

    4.参数设置

    (1)maxThreads的设置既与应用的特点有关,也与服务器的CPU核心数量有关。通过前面介绍可以知道,maxThreads数量应该远大于CPU核心数量;而且CPU核心数越大,maxThreads应该越大;应用中CPU越不密集(IO越密集),maxThreads应该越大,以便能够充分利用CPU。当然,maxThreads的值并不是越大越好,如果maxThreads过大,那么CPU会花费大量的时间用于线程的切换,整体效率会降低。

    (2)maxConnections的设置与Tomcat的运行模式有关。如果tomcat使用的是BIO,那么maxConnections的值应该与maxThreads一致;如果tomcat使用的是NIO,那么类似于Tomcat的默认值,maxConnections值应该远大于maxThreads。

    (3)通过前面的介绍可以知道,虽然tomcat同时可以处理的连接数目是maxConnections,但服务器中可以同时接收的连接数为maxConnections+acceptCount 。acceptCount的设置,与应用在连接过高情况下希望做出什么反应有关系。如果设置过大,后面进入的请求等待时间会很长;如果设置过小,后面进入的请求立马返回connection refused。

     

    四:线程池Executor

    Executor元素代表Tomcat中的线程池,可以由其他组件共享使用;要使用该线程池,组件需要通过executor属性指定该线程池。

    Executor是Service元素的内嵌元素。一般来说,使用线程池的是Connector组件;为了使Connector能使用线程池,Executor元素应该放在Connector前面。Executor与Connector的配置举例如下:

    <Executor name="tomcatThreadPool" namePrefix ="catalina-exec-" maxThreads="150" minSpareThreads="4" />
    <Connector executor="tomcatThreadPool" port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" acceptCount="1000" />
    

    Executor的主要属性包括:

    • name:该线程池的标记

    • maxThreads:线程池中最大活跃线程数,默认值200(Tomcat7和8都是)

    • minSpareThreads:线程池中保持的最小线程数,最小值是25

    • maxIdleTime:线程空闲的最大时间,当空闲超过该值时关闭线程(除非线程数小于minSpareThreads),单位是ms,默认值60000(1分钟)

    • daemon:是否后台线程,默认值true

    • threadPriority:线程优先级,默认值5

    • namePrefix:线程名字的前缀,线程池中线程名字为:namePrefix+线程编号

       

    五:查询当前状态

    上面介绍了Tomcat连接数、线程数的概念以及如何设置,下面说明如何查看服务器中的连接数和线程数。

    查看服务器的状态,大致分为两种方案:(1)使用现成的工具,(2)直接使用Linux的命令查看。

    现成的工具,如JDK自带的jconsole工具可以方便的查看线程信息(此外还可以查看CPU、内存、类、JVM基本信息等),Tomcat自带的manager,收费工具New Relic等。下图是jconsole查看线程信息的界面:

    下面说一下如何通过Linux命令行,查看服务器中的连接数和线程数。

    1.连接数

    假设Tomcat接收http请求的端口是8083,则可以使用如下语句查看连接情况:

    netstat –nat | grep 8083
    

    结果如下所示:

    可以看出,有一个连接处于listen状态,监听请求;除此之外,还有4个已经建立的连接(ESTABLISHED)和2个等待关闭的连接(CLOSE_WAIT)。

    2.线程

    ps命令可以查看进程状态,如执行如下命令:

    ps –e | grep java
    

    结果如下图:

     

    可以看到,只打印了一个进程的信息;27989是线程id,java是指执行的java命令。这是因为启动一个tomcat,内部所有的工作都在这一个进程里完成,包括主线程、垃圾回收线程、Acceptor线程、请求处理线程等等。

    通过如下命令,可以看到该进程内有多少个线程;其中,nlwp含义是number of light-weight process。

    ps –o nlwp 27989
    

    可以看到,该进程内部有73个线程;但是73并没有排除处于idle状态的线程。要想获得真正在running的线程数量,可以通过以下语句完成:

    ps -eLo pid ,stat | grep 27989 | grep running | wc -l
    

    其中ps -eLo pid ,stat可以找出所有线程,并打印其所在的进程号和线程当前的状态;两个grep命令分别筛选进程号和线程状态;wc统计个数。其中,ps -eLo pid ,stat | grep 27989输出的结果如下:

     

     图中只截图了部分结果;Sl表示大多数线程都处于空闲状态。

    展开全文
  • Tomcat监控

    千次阅读 2019-10-23 11:06:46
    Tomcat监控方法通常有两种: 一是自带的监控模块status; 二是第三方监控工具probe。 一、Tomcat启动与停止 Tomcat启动 ./usr/local/apache‐tomcat‐8.5.31/bin/startup.sh Tomcat停止 ./usr/local/apache‐...

    在这里插入图片描述
    Tomcat监控方法通常有两种:
    一是自带的监控模块status;
    二是第三方监控工具probe。

    一、Tomcat启动与停止
    Tomcat启动
    ./usr/local/apache‐tomcat‐8.5.31/bin/startup.sh
    Tomcat停止
    ./usr/local/apache‐tomcat‐8.5.31/bin/shutdown.sh

    二、status监控
    使用status监控步骤如下:
    1.配置角色与用户
    配置角色与用户的文件
    usr/local/apache-tomcat-8.5.31/conf/tomcat-users.xml
    配置角色与用户的语法:
    //角色名



    //用户

    角色是指权限,指访问Tomcat的权限
    如果需要监控tomcat,那么需要两类角色权限
    如果是监控server status那么需要的角色权限为manager-gui
    如果需要监控host manage那么需要的角色权限为admin-gui
    配置用户时需要配置其相关角色,简单的来说就配置其对应权限
    2.如果提示403错误
    如果配置好角色之后还是出现403的错误,那么表现我们没有权限去读监控的相关信息,那么需要修改以下两
    个文件中的内容:
    ./webapps/host-manager/meta-inf/context.xml
    ./webapps/manager/meta-inf/context.xml

    将allow的值修改为测试机的IP地址网段
    3.重启tomcat
    ./usr/local/apache‐tomcat‐8.5.31/bin/shutdown.sh
    ./usr/local/apache‐tomcat‐8.5.31/bin/startup.sh
    4.进入监控界面
    Tomcat监控的URL地址
    http://ip:8080
    如:
    http://192.168.40.133:8080/
    如果监控server status
    http://192.168.40.133:8080/manager/status
    如果监控host manage
    http://192.168.40.133:8080/host‐manager/html
    三、probe监控
    使用第三方监控工具的步骤如下:
    1.安装probe
    现在安装的probe的版本是psi-probe
    2.配置角色和用户
    如果只是使用probe进行监控的,那么只需要manager-gui角色即可
    conf/tomcat‐users.xml文件中添加以下代码
    //设置角色名

    //设置用户

    3.重启tomcat服务器
    4.进监控界面
    http://ip:8080/probe
    如:
    http://192.168.40.133:8080/probe/

    监控内容如下:
    1.applications标签页
    显示webapps目录下所有的内容信息,有每个目录的请求数、请求是由那个jsp类生成、所以使用到的jsp
    applications标签页中显示了所有应用程序,我们现在测试的程序是opencarrun
    status列:表示运行的状态
    REQ.列:表示HTTP请求数
    sess.列:表示session数
    JSP列:表示发布程序所有JSP文件
    2.datasources标签页
    表示数据源,我们这里没有设置源
    3.deployment标签页
    表示允许在客户端向服务上传jar文件
    4.logs标签页
    显示日志文件信息,只显示catalina.out文件的日志信息
    5.threads标签页
    显示由tomcat产生的线程,对我们来,一般情况下我们主要关注的线程是http-nio-8080,关注的目的是确定
    http连接器是否能正常的处理我们的请求
    6.cluster标签页
    表示tomcat的集群设置
    7.system标签页
    显示系统相关信息,主要是用于查看JVM内存使用情况
    8.connectors标签页
    表示连接器使用的情况,显示的内容包括:请求数、进程执行时间、处理的字节数

    展开全文
  • tomcat+spring mvc 原理(三):tomcat网络请求监控与处理前言:请求处理的准备Connector处理请求Connector内部结构请求处理的动态实现 前言:     tomcat + spring mvc 原理(一):tomcat原理...

    tomcat+spring mvc 原理(三):tomcat网络请求的监控与处理1

    前言:

        tomcat + spring mvc 原理(一):tomcat原理综述总结了tomcat的整体运作原理、静态容器架构和容器配置,tomcat + spring mvc 原理(二):tomcat容器的初始加载与启动详细介绍了tomcat动态容器初始化和启动过程。本文主要介绍tomcat网络请求的监控与处理逻辑。
        利用tomcat + spring mvc架构体系构建服务器,很重要的一个部分就是网络请求的监控、接收、解包、封包、请求传递等功能的实现,这样在建服务器时就只需要关注业务参数的传入和处理,而不用关心网络协议等和业务无关的细节。 一般服务的问题都出现在请求和应答处理的过程,一旦是因为框架内部导致的问题,这时候充分了解tomcat+spring mvc的请求处理逻辑就很重要了。

    请求处理的准备

        网络请求相关的处理集中在Connector容器中。由原理一中介绍的总体容器架构可知,Connector是被包含在Service容器中,而且Connector容器的配置也是包含在Service的配置中:

    <Service name="Catalina">
      <Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
          maxThreads="150" minSpareThreads="4"/>
    
      <Connector port="8080" protocol="HTTP/1.1"
                 connectionTimeout="20000"
                 redirectPort="8443" />
    
      <Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
                 maxThreads="150" SSLEnabled="true">
          <SSLHostConfig>
              <Certificate certificateKeystoreFile="conf/localhost-rsa.jks"
                           type="RSA" />
          </SSLHostConfig>
      </Connector>
    
      <Connector port="8443" protocol="org.apache.coyote.http11.Http11AprProtocol"
                 maxThreads="150" SSLEnabled="true" >
          <UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol" />
          <SSLHostConfig>
              <Certificate certificateKeyFile="conf/localhost-rsa-key.pem"
                           certificateFile="conf/localhost-rsa-cert.pem"
                           certificateChainFile="conf/localhost-rsa-chain.pem"
                           type="RSA" />
          </SSLHostConfig>
      </Connector>
      ......
    </Service>
    

    以上是我从原理(一)介绍的tomcat的默认配置文件server.xml中捞出来的配置。可以看到,<Connector>标签是包含在标签中的<Service>中的,一个Service可以有多个Connector,可以配置线程池来处理请求。tomcat在启动过程中依据这个配置创建Service和Connector,然后根据原理(二)中介绍的流程初始化和启动Service和Connector。

    Connector处理请求

    • Connector内部结构

    在这里插入图片描述

        一个Connector中会有一个ProtocolHandler,不同的ProtocolHandler接口的实现代表不同的协议,可以看到上文的配置中包括了协议的类的设置,比如protocol="HTTP/1.1"或者protocol=“org.apache.coyote.http11.Http11NioProtocol”。默认实现的协议主要有两种,Ajp或者HTTP。HTTP协议不用说,Ajp是Apache JServ Protocol的缩写,主要用于Apache前端服务器的通讯,特点是长连接,不需要每次断开连接再建立连接,开销比较小(偷偷查了下资料)。

        ProtocolHandler中会包含Endpoint、Processor和Adapter的实现。Endpoint主要用来管理Socket,监听TCP的请求和发送应答。Processor用来实现HTTP协议。Adapter,顾名思义,是作为适配器将请求适配到Container容器。

    • 请求处理的动态实现

        Connector的构造函数中,会根据配置选择ProtocolHandler的实现:

    public Connector(String protocol) {
        boolean aprConnector = AprLifecycleListener.isAprAvailable() &&
                AprLifecycleListener.getUseAprConnector();
    /**
     *下面blabla一堆是用来判断使用哪一个ProtocolHandler的实现
     **/
        if ("HTTP/1.1".equals(protocol) || protocol == null) {
            if (aprConnector) {
                protocolHandlerClassName = "org.apache.coyote.http11.Http11AprProtocol";
            } else {
                protocolHandlerClassName = "org.apache.coyote.http11.Http11NioProtocol";
            }
        } else if ("AJP/1.3".equals(protocol)) {
            if (aprConnector) {
                protocolHandlerClassName = "org.apache.coyote.ajp.AjpAprProtocol";
            } else {
                protocolHandlerClassName = "org.apache.coyote.ajp.AjpNioProtocol";
            }
        } else {
            protocolHandlerClassName = protocol;
        }
    
        // Instantiate protocol handler
        ProtocolHandler p = null;
        try {
            Class<?> clazz = Class.forName(protocolHandlerClassName);
            p = (ProtocolHandler) clazz.getConstructor().newInstance();
        } catch (Exception e) {
            log.error(sm.getString(
                    "coyoteConnector.protocolHandlerInstantiationFailed"), e);
        } finally {
    
            this.protocolHandler = p;  //在这里给引用赋值
    
        }
    
        // Default for Connector depends on this system property
        setThrowOnFailure(Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE"));
    }
    

    然后在Connector的生命周期方法initInternal()和startInternal()中(原理(二)有讲到)都调用了ProtocolHandler相应的init()和start()生命周期方法。需要注意的是,在initInternal()中调用protocolHandler.init()之前,先设置了protocolHanler的Adpter

    @Override
        protected void initInternal() throws LifecycleException {
            ······
            // Initialize adapter
            adapter = new CoyoteAdapter(this);
            protocolHandler.setAdapter(adapter);
            ······
            try {
                protocolHandler.init();
            } catch (Exception e) {
                throw new LifecycleException(
                        sm.getString("coyoteConnector.protocolHandlerInitializationFailed"), e);
            }
        }
    

        同样的故事也发生在Endpoint身上。Endpoint构造发生在ProtocolHandler的实现类构造函数中:

    public Http11NioProtocol() {
        super(new NioEndpoint());
    }
    

    在ProtocolHandler的init()和start()生命周期方法中调用了Endpoint的相应生命周期的init()和start()方法(由此可见生命周期这一抽象的应用在tomcat中随处可见)。
        Endpoint工作在连接和传输数据的最前线。父类AbstractEndpoint的init()方法中调用了bind()方法,start()方法调用了Endpoint的startInternal()方法。

    //init()方法
    public final void init() throws Exception {
        if (bindOnInit) {
            bindWithCleanup();
            bindState = BindState.BOUND_ON_INIT;
        }
        ......
    }
    //bindWithCleanup()调用bind
    private void bindWithCleanup() throws Exception {
        try {
            bind();
        } catch (Throwable t) {
            ExceptionUtils.handleThrowable(t);
            unbind();
            throw t;
        }
    }
    //start()中调用startInternal()同原理(二)中所述,不再列出
    

    其中bind()方法和startInternal()方法都是在子类NioEndpoint中实现。
        NioEndpoint使用的套接字是JDK1.4之后新增的NioSocket,相对于普通Socket效率要更高。NioSocket中的实现关键是Selector和Channel,Channel需要注册到关注的Selector(具体可以参看NioSocket的相关讲解)。在bind()方法中依次创建 ServerSocketChannel和Selector的线程池。需要注意的线程池中的基本对象是Poller,Poller继承自Thread,内部包含了一个Selector,实现了Selector的select()的持续监听。

    public void bind() throws Exception {
        //见下。创建Channel
        initServerSocket();
    
        setStopLatch(new CountDownLatch(1));
    
        initialiseSsl();
        //Selector线程池
        selectorPool.open(getName());
    }
    //initServerSocket()
    protected void initServerSocket() throws Exception {
        if (!getUseInheritedChannel()) {
            serverSock = ServerSocketChannel.open();
            socketProperties.setProperties(serverSock.socket());
            InetSocketAddress addr = new InetSocketAddress(getAddress(), getPortWithOffset());
            serverSock.socket().bind(addr,getAcceptCount());
        } else {
            // Retrieve the channel provided by the OS
            Channel ic = System.inheritedChannel();
            if (ic instanceof ServerSocketChannel) {
                serverSock = (ServerSocketChannel) ic;
            }
            if (serverSock == null) {
                throw new IllegalArgumentException(sm.getString("endpoint.init.bind.inherited"));
            }
        }
        serverSock.configureBlocking(true); //mimic APR behavior
    }
    

    startInternal()中启动了Acceptor,Acceptor主要的作用是调用Endpoint中方法实现Poller和Channel的注册和请求连接的监听,然后获取请求的SocketChannel。

    public void startInternal() throws Exception {
            ······
            startAcceptorThread();
            ······
        }
    }
    

    标准Poller的实现是继承自Thread,其中的run()方法主要是Selector.select(),等待请求的到来,然后循环遍历SelectKey
    (这部分中的实现和NioSocket的使用强相关,没有了解过一定要提前看下),在循环中调用processKey()方法。

    public class Poller implements Runnable {
        @Override
        public void run() {
            // Loop until destroy() is called
            while (true) {
    
                boolean hasEvents = false;
    
                try {
                    if (!close) {
                        hasEvents = events();
                        if (wakeupCounter.getAndSet(-1) > 0) {
                          /**
                           *Selector.select()监听到来的请求
                           **/
                            keyCount = selector.selectNow();
                        } else {
                            keyCount = selector.select(selectorTimeout);
                        }
                        wakeupCounter.set(0);
                    }
                ......
                Iterator<SelectionKey> iterator =
                    keyCount > 0 ? selector.selectedKeys().iterator() : null;
    
                while (iterator != null &&  iterator.hasNext()) {
                    SelectionKey sk = iterator.next();
                    NioSocketWrapper socketWrapper = (NioSocketWrapper) sk.attachment();
                    if (socketWrapper == null) {
                        iterator.remove();
                    } else {
                        iterator.remove();
                        
                        processKey(sk, socketWrapper);
                        
                    }
                }
                timeout(keyCount,hasEvents);
            }
            getStopLatch().countDown();
        }
    }
    

    SocketWrapper可以说是一个大杂烩,里面包括了各种和连接有关的东西,比如Endpoint、Selector的pool、 NioChannel的栈、Poller、interestOps(与SelectorKey相关的操作码)、SendfileDataSocketBufferHandler、IOException等等。
        processKey()调用了SocketWrraper对象中Channel的读操作,将消息读入到Buffer中,然后调用processSocket()方法,进一步处理消息.processSocket()中获取了一个SocketProcessor类对象(注意并不是图上的Processor),并调用了它的run()方法。这个类的父类SocketProcessorBase实现了Runnable,在run()中调用了doRun()方法,SocketProcessor类中实现了doRun()方法。SocketProcessor是Endpoint的内部类,它的doRun()方法调用Endpoint的Handler的process方法(终于绕回到我的图了)。
        Handler的process()方法主要就是处理和Processor选用相关的逻辑,Processor用来对TCP的消息进行解包,因此和ProtocolHandler一样,有不同协议的实现。其中,Http11Processor的实现就主要对Http的request和response进行解包和封包。
    Handler的process获取了Processor对象,然后调用了AbstractProcessorLight(是实现了Processor的抽象类)的process()方法,process()中调用了两个比较重要的方法:service()和dispatch()。service()对于不同协议有不同的实现,Http11Processor的service实现就是对接收的request进行HTTP解包,如果有错误会对response进行设置。dispatch()方法中调用:

    getAdapter().asyncDispatch(request, response, status)
    

    利用Adapter的asyncDispatch()方法先将org.apache.coyote.Request request和org.apache.coyote.Response response分别转换为org.apache.catalina.connector.Request和org.apache.catalina.connector.Response,然后利用自身包含的Connector对象(还记得上文说的“需要注意的是,在initInternal()中调用protocolHandler.init()之前,先设置了protocolHanler的Adpter”吗?Connector也在这个时候将自己的实例设置到了Adapter唯一实现CoyoteAdapter实例中):

    connector.getService().getContainer().getPipeline()
               .getFirst().invoke(request, response);
    

    将request和response传递给了Container(原理一原理二中提到了Engine、Host、Context和Wrapper等)。
        由于本文章的内容已经过多,特别是在在Endpoint部分中纠缠往复,很难理清。关于后续Container中请求的处理和调用Filter对请求拦截的内容就放在下期来讲。
    相关文章:
    tomcat + spring mvc原理(一):tomcat原理综述和静态架构
    tomcat + spring mvc原理(二):tomcat容器初始化加载和启动
    tomcat + spring mvc原理(四):tomcat网络请求的监控与处理2
    tomcat + spring mvc原理(五):tomcat Filter组件实现原理

    展开全文
  • Status页对Tomcat监控的步骤如下: 步骤1:修改配置文件tomcat-users(该文件在Tomcat安装程序根目录中的conf文件夹中),添加一个admin设置权限,在中添加的内容如下: 步骤2:修改完成后,重启Tomcat服务器...

    在这里插入图片描述
    Status页对Tomcat监控的步骤如下:
    步骤1:修改配置文件tomcat-users(该文件在Tomcat安装程序根目录中的conf文件夹中),添加一个admin设置权限,在中添加的内容如下:


    步骤2:修改完成后,重启Tomcat服务器,在浏览器中输入URL(http://localhost:8080/),如果是远程访问,访问的URL为http://IP:8080,如图所示。
    在这里插入图片描述
    在JBoss Management页面,提供几种监控Tomcat的方法:Tomcat status、JMX Console和JBoss Web Console。
    其中关于Tomcat status内容包括三种:Tomcat status基本信息、扩展的全部Tomcat status信息和XML格式的Tomcat status信息。
    单击Tomcat status链接,进入Tomcat status信息页面,如图所示。
    在这里插入图片描述
    基本信息中主要包括三部分内容:JVM、HTTP和jk。
    JVM的信息如下:
    Free memory: 30.38 MB Total memory: 65.60 MB Max memory: 506.31 MB
    Free memory:空闲内存大小;
    Total memory:总内存大小;
    Max mermory:最大内存大小;
    JVM(Java Virtual Machine)Java虚拟机,Java虚拟机包括一套字节码指令集、一组寄存器、一个栈、一个垃圾回收堆和一个存储方法域。 JVM屏蔽了与具体操作系统平台相关的信息,使Java程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行,JVM在执行字节码时,实际上最终还是把字节码解释成具体平台上的机器指令执行。
    HTTP相关信息如下:
    Max threads: 250 Min spare threads: 25 Max spare threads: 75 Current thread count: 10 Current thread busy: 2
    Max processing time: 234 ms Processing time: 1 s Request count: 21 Error count: 6 Bytes received: 0.00 MB Bytes sent: 0.02 MB
    在这里插入图片描述
    Max threads:最大线程数;
    Min spare threads:最小空闲线程数;
    Max spare threads:最大空闲线程数;
    Current thread count:最近运行的线程数;
    thread busy:正在运行的线程数;
    Max processing time:最大CPU时间;
    Processing time:CPU消耗总时间;
    Request count:请求总数;
    Error count:错误的请求数;
    Bytes received:接收字节数;
    Bytes sent:发送字节数;
    关于请求阶段的有以下几种情况:
    P:表示正准备发送的请求;
    S:表示请求正在服务器端处理;
    F:表示已经完成的请求;
    R:表示即将发送的请求;
    K:表示当前活动的请求;
    jk显示的信息与http信息相同,jk是Apache连接Tomcat的一个模块,支持集群和负载均衡。
    如果单击Tomcat status后的full链接,则可以显示所有关于Tomcat的详细信息,除其Tomcat的基本信息,还包括一些模块的详细信息,主要包括模块有:localhost/mtours、localhost/qcbin、localhost/ws4ee、localhost/web-console、localhost/jbossmq-httpil、localhost/invoker、localhost/sabin、localhost/jmx-console、localhost/。
    如果希望以XML方式来查看Tomccat的信息,那么单击XML链接即可。

    展开全文
  • tomcat 连接池活动数目监控

    万次阅读 2012-03-09 08:28:59
    关于如何配置Tomcat数据库连接池,网上已有太多文章了。可是找不到一篇文章能 告诉我,怎么能得到Tomcat连接池的当前连接数。如果想要监视Tomcat的运行状况,这 是一个重要参数。所以我花了半天的时间,专门来研究...
  • Tomcat 监控指标

    千次阅读 2019-10-10 20:52:34
    Tomcat 监控指标列表 监测点 监测指标 指标含义 Tomcat 发送字节() 发送的字节数 接收字节() 收到的字节数 ...
  • tomcat参数以及tcp连接-性能调优实验

    千次阅读 2019-11-06 11:08:00
    TCP 三次握手进入的半连接队列和全连接队列 TOMCAT的acceptCount和操作系统的TCP全连接队列关系 TOMAT最大连接数和线程数以及TCP全连接的关系 jmeter的连接超时时间和TCP状态监测,...jconsole远程监控tomcat的MBean
  • zabbix5.0实战监控Tomcat

    2021-02-02 17:47:31
    zabbix实战监控Tomcat
  • 配置JMX Exporter2.1 下载安装JMX Exporter文件2.2 收集Tomcat数据2.3 集成Prometheus3.Tomcat关注指标4.集成Grafana 1.安装部署 1.1 安装Prometheus 部署Prometheus请点击此链接:...
  • 最近,测试部门的同事找到我,说他们测试时,没一会就发现服务接口请求一直无响应,Tomcat跟死掉了一样,也没有返回任何的错误响应,说让我赶紧排查下;听完后,我瞬间激灵了下,妹的,最近老是出问题,领导都要给我...
  • Tomcat测试监控Tomcat性能监控工具

    千次阅读 2019-07-30 09:15:31
    Tomcat主要监控线程工作状态、请求数、 会话数、线程数、虚拟主机、JAVA虚拟机内存占用情况。 监控工具 Tomcat提供的manager 通过使用Applications Manager(又称opManager)来进行监控。 使用这种方式,所监控Tomc...
  • 摘要:JAVA源码,媒体网络,山寨QQ,Java聊天程序 Java编写的山寨QQ,多人聊天+用户在线,程序分服务端和客户端,典型C/S结构, 当用户发送第一次请求的时候,验证用户登录,创建一个该qq号和服务器端保持通讯连接得线程...
  • Tomcat面试题+http面试题+Nginx面试题+常见面试题

    千次阅读 多人点赞 2019-12-12 15:04:43
    Tomcat面试题 1、Tomcat的缺省端口是多少?怎么修改?...2、Tomcat有哪几种connector运行模式(服务的请求方式)? 答:三种。修改它的运行模式需要在主配置文件中找到connector字段中的protocol进行修改...
  • Tomcat连接数设置

    千次阅读 2019-08-12 20:22:45
    配置中,和连接数相关的参数有:minProcessors:最小空闲连接线程数,用于提高系统处理性能,默认值为10maxProcessors:最大连接线程数,即:并发处理的最大请求数,默认值为75acceptCount:允许的最大连接数,应...
  • 点击上方关注“Java后端技术栈”回复“面试”获取最新资料一、下载地址https://tomcat.apache.org/download-80.cgi二、安装步骤将安装包 apach...
  • Tomcat开启远程监控Jconsole配置

    千次阅读 2017-03-24 10:14:52
    HEAD请求来源是HTTP1.0。HTTP1.0就定义了三种请求方式GET,POST,HEAD。...此处主要是讲HEAD请求。w3.org定义在w3.org里面是这么说的The HEAD method is identical to GET except that the server MUST
  • Zabbix监控Tomcat

    千次阅读 2018-10-09 20:50:20
    简介 从Zabbix 2.0版本开始,以...要查得一台主机特定的JMX计数器值,Zabbix server向Zabbix Java gateway发送请求,后者使用JMX管理API 去请求远程的有关应用。应用不需要额外安装软件,只需要启动时在命令行...
  • Tomcat学习--tomcat运行状态监控

    千次阅读 2018-05-02 20:43:42
    上一篇博客Tomcat学习--war服务相关状态信息监控中我们已经了解了一下对war包的启动、停止、运行状态、重载和卸载操作的实现机制,接下来我们用这篇博客了解一下tomcat运行过程中服务器,操作系统,jvm和war的一些...
  • zabbix4.0监控tomcat

    2020-06-21 12:40:47
    zabbix-server启用javapollers进程去链接zabbix-java-gateway去请求数据(修改配置文件可实现),Zabbix-Javagateway就相当于一个代理,它负责收集客户端tomcat数据; zabbix-java-gateway开启JMX功能,用于远程连接...
  • 我们在本地启动Tomcat服务器后,用localhost:&lt;默认端口&gt;访问: 再点Manager App,即可...最近我在github上找到一个功能强大的Tomcat 管理监控工具,可以用来替代Tomcat默认的Manager应用: https...
  • tomcat 记录 访问者 ip + 访问地址

    千次阅读 2018-11-08 14:43:00
    tomcat 记录 访问者 ip + 访问地址 技术小胖子  2017-11-14 17:11:00 浏览256 评论0 日志   Apache   tomcat   Server   IP   xml   ...
  • zabbix4.0学习三:Zabbix监控tomcat和java

    万次阅读 2019-02-14 09:58:56
    zabbix4.0学习三:Zabbix监控tomcat和java 前言 想理解怎么监控tomcat,必需识下图 zabbix-Web前端界面,它通过数据库里数据展示。和其它组件不直接关联 zabbix-server运行在10051端口,Zabbix-server要知道java...
  • 监控宝对tomcat监控

    千次阅读 2014-03-16 08:36:54
    Tomcat性能监控服务的同时我们也推出了Tomcat服务的监控插件,帮助您实时了解到以下性能指标: JVM内存,包括JVM可使用内存、JVM所使用内存、JVM最大可使用内存;Tomcat请求数,包括每秒请求数,每秒出错数;...
  • Tomcat(JVM)监控方法(转帖)

    千次阅读 2018-07-26 19:01:40
    2、LoadRunner编写脚本实现Tomcat监控  采用编写VuGen脚本访问Tomcat的Status页面的方式获取性能数据(利用了关联和lr_user_data_point函数),本质上还是使用tomcat自带的监控页面,只是将监控结...
  • Tomcat最大连接数问题

    万次阅读 2012-05-24 21:38:07
    Tomcat的server.xml中Context元素的以下参数应该怎么配合适 maxThreads="150" minSpareThreads="25" maxSpareThreads="75" acceptCount="100" />    答曰: maxThreads="150" 表示最多同时处理...
  • Tomcat(JVM)监控方法

    千次阅读 2015-03-04 14:41:06
    转载自:...   Tomcat(JVM)监控方法 1、Tomcat自带的监控页面 ... 配置详见Tomcat安装配置监控一文,如图所示为监控页面: ...2、LoadRunner编写脚本实现Tomcat监控
  • 这几天,发现Nginx与Tomcat之间也存在同样的问题,原因是两边的相关配置参数不一致引起的。 先说说服务为什么使用HTTPs长连接技术?有如下几个原因: 1、对响应时间要求较高; 2、服务走的是公网,客
  • Java连接池详解 tomcat

    千次阅读 2016-11-23 20:36:41
    对于共享资源,有一个很著名的设计模式:资源池(Resource Pool)。该模式正是为了解决资源的频繁分配﹑释放所造成的问题。为解决我们的问题,可以...我们可以通过设定连接池最大连接数来防止系统无尽的与数据库连接

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 33,294
精华内容 13,317
关键字:

tomcat监控连接请求地址