美文网首页
Tomcat并发处理请求

Tomcat并发处理请求

作者: ZMRWEGo | 来源:发表于2018-10-12 16:21 被阅读169次

    Tomcat处理连接请求的模式:

    • BIO:阻塞模型
    • NIO:非阻塞模型
    • APR: 高性能,可扩展的模式,Tomcat8版本默认模式
      Tomcat连接器(Connector)是处理请求的主要组件,它负责接收请求,创建Request和Response对象用于和前端进行数据的交换;然后分配线程让Servlet容器来处理这个请求,并把产生的Request和Response对象传给Servlet容器。当Engine处理完请求后,也会通过Connector将结果返回给请求端。即Connector进行请求的调度和控制。
      根据协议的不同,可以分为Http Connector和AJP Connector,两种协议的不同可以看这篇博文

    一、NIO、BIO、APR

    1. Connector的模式

    Connector在处理HTTP请求时,会使用不同的模式。不同版本的Tomcat支持的模式不行同(Tomcat8+版本支持NIO以及APR去掉了对BIO的支持)
    BIO与NIO大家都是比较熟悉的,APR是Apache Portable Runtime,是Apache可移植运行库,利用本地库可以实现高扩展性、高性能;APR是在Tomcat上运行高并发应用的首选模式,但是需要安装apr、apr-utils、tomcat-native等包

    2. Connector的请求流程

    OverView

    Connector启动后会启动三种线程组用于不同阶段的处理:

    • Acceptor线程组。用于接收新连接,并将新连接封装以下,选择一个Poller将新连接添加到Poller的事件队列中
    • Poller线程组。用于监听Socket事件,当Socket可读或可写时,将Socket封装一下添加到worker线程池的任务队列中
    • Worker线程组。用于对请求进行处理,包括分析请求报文并创建Request对象,调用容器的pipeline
      Acceptor、Poller、Worker的线程池(ThreadPoolExcutor)均维护在NioEndPoint中
    Connector的初始化及启动
    tomcat-connector-start
    1. initServerSocket(),通过ServerSocketChannel.open()打开一个ServerSocket,默认绑定到8080端口,默认的连接等待队列长度为100,当超过100时会拒绝服务。我们可以通过在conf/server.xml中的Connector的acceptCount属性对其进行设置。
    2. createExecutor()用于创建Worker线程池。默认会启动10个Worker线程,Tomcat处理请求过程中,Worker最多不超过200个。我们可以通过配置conf/server.xml中的Connector的minSpareThreads 和 maxThreads 对这两个属性进行定制。
    3. Poller用于检测已经就绪的Socket,默认不超过2个线程,我们可以通过配置 pollerThreadCount 设置。
      4.Acceptor用于接收新的连接,默认1个线程,我们可以通过配置 acceptorThreadCount 对其进行设置。
    Acceptor请求过程
    1. Acceptor在启动后会阻塞在ServerSocketChannel.accept()处,当有新连接到达时,该方法返回一个SocketChannel
      2.配置完Socket以后会将Socket封装到NioChannel中,并注册到 Poller,由于我们一开始就启动了多个 Poller 线程,注册的时候,连接是公平的分配到每个 Poller 的。
      3.addEvent() 方法会将 Socket 添加到该 Poller 的 PollerEvent 队列中。到此 Acceptor 的任务就完成了。
    Poller过程
    1. selector.select(1000)。当 Poller 启动后因为 selector 中并没有已注册的 Channel,所以当执行到该方法时只能阻塞。所有的 Poller 共用一个 Selector,其实现类是 sun.nio.ch.EPollSelectorImpl
      2.events() 方法会将通过 addEvent() 方法添加到事件队列中的 Socket 注册到 EPollSelectorImpl,当 Socket 可读时,Poller 才对其进行处理
      3.createSocketProcessor() 方法将 Socket 封装到 SocketProcessor 中,SocketProcessor 实现了 Runnable 接口。worker 线程通过调用其 run() 方法来对 Socket 进行处理。
      4.execute(SocketProcessor) 方法将 SocketProcessor 提交到线程池,放入线程池的 workQueue 中。workQueue 是 BlockingQueue 的实例。到此 Poller 的任务就完成了。
    Worker过程
    • worker 线程被创建以后就执行 ThreadPoolExecutor 的 runWorker() 方法,试图从 workQueue 中取待处理任务,但是一开始 workQueue 是空的,所以 worker 线程会阻塞在 workQueue.take() 方法。
    • 当新任务添加到 workQueue后,workQueue.take() 方法会返回一个 Runnable,通常是 SocketProcessor,然后 worker 线程调用 SocketProcessor 的 run() 方法对 Socket 进行处理。
    • createProcessor() 会创建一个 Http11Processor, 它用来解析 Socket,将 Socket 中的内容封装到 Request 中。注意这个 Request 是临时使用的一个类,它的全类名是 org.apache.coyote.Request
    • postParseRequest() 方法封装一下 Request,并处理一下映射关系(从 URL 映射到相应的 Host、Context、Wrapper)。

    参考:谈谈 Tomcat 请求处理流程(http://www.importnew.com/27729.html

    相关文章

      网友评论

          本文标题:Tomcat并发处理请求

          本文链接:https://www.haomeiwen.com/subject/fvkgaftx.html