1. Request processing process AprEndPoint

When a request is sent to Tomcat, it is forwarded by the Connector to AprEndPoint, which calls the startInternal() method. This method does four things:

  • LimitLatch Limits connection times.
  • The Poller thread is created.
  • The sendFile thread was created.
  • An acceptor was created.

Poller, SendFile, and Acceptor are all internal classes of AprEndPoint because their parent classes implement Runnable, so the core logic is in their own run() methods.

There is so much source code involved that I just can’t be bothered to show it, so I drew the following diagram to give you an idea.

  • LimitLatchIs the connection controller, which controls the maximum number of connections.
  • AcceptorRunning in a single thread, it passes calls in an infinite loopaccept()Method to receive a new connection, which returns a longsocketAnd then put thissocketEncapsulated intoAprSocketWrapperObject.
  • PollerIt also runs in a separate thread, which maintains one internallySocketListObject that containssocketArray, it’s checking in an infinite loopsocketData ready state, once there issocketReadable, it generates oneSocketProcessorThe task object is thrown toExecutorTo deal with.
  • ExecutorIt’s just a thread pool that runsSocketProcessorThe task,SocketProcessorrun()Method will callHttp11ProcessorTo read and parse the request data.

Some of your friends have no idea what AprEndPoint or Apr is after reading it.

A brief introduction:

APR (Apache Portable Runtime Libraries) is the Apache Portable Runtime library implemented in C language. It aims to provide a cross-platform operating system interface library for upper-layer applications. Tomcat can use it to handle both file and network I/O to improve performance.

In Tomcat8.5. X, the default I/O mode using the NIO, use linker is org. The apache. Coyote. Http11. Http11NioProtocol, of course, as is the default, without display configuration, In server.xml, you just need to write:

<Connector port="8080" protocol="HTTP / 1.1"
            connectionTimeout="20000"
            redirectPort="8443" />
Copy the code

But if you wanted to change it to APR, you would have to write it like this:

<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>
Copy the code

Now, a soul-searching question, how does APR improve performance?

Like NioEndpoint, AprEndpoint implements non-blocking I/O. The differences are: NioEndpoint implements non-blocking I/O by calling Java’s NIO API, whereas AprEndpoint implements non-blocking I/O by JNI invoking the APR native library.

The Tomcat Endpoint component needs to allocate a Buffer in advance when receiving network data. The so-called Buffer is byte array []. Java passes the address of this Buffer to C code through JNI calls. C code reads the Socket through the operating system API and populates the Buffer with data.

The Java NIO API provides two types of buffers to receive data: HeapByteBuffer and DirectByteBuffer.

The HeapByteBuffer object itself is allocated on the JVM heap, and the byte array it holds, Byte [], is allocated on the JVM heap. However, if HeapByteBuffer is used to receive network data, the data needs to be copied from the kernel to a temporary local memory and then from temporary local memory to the JVM heap, rather than directly from the kernel to the JVM heap.

As data is copied from the kernel to the JVM heap, the JVM may undergo GC, and the object may be moved during GC, which means that the byte array on the JVM heap may be moved, invalidating the Buffer address. The JVM can be guaranteed not to GC any copies from local memory to the JVM heap if there is a local memory transfer.

Tomcat’s AprEndpoint solves this problem with the sendFile feature at the operating system level, which is very concise.

2. Request processing process NioEndPoint

In the context of AprEndpoint’s request processing, let’s take a look at Tomcat’s default NioEndPoint processing.

In fact, the two processes are very similar, and the difference is basically the implementation of non-blocking I/O.

  • inAcceptorIn theaccept()Method returns aChannelObject, go aheadChannelObject toPollerTo deal with.
  • PollerMaintain one internallyChannelArray, it’s checking in an infinite loopChannelData ready state, once there isChannelReadable, it generates oneSocketProcessorThe task object is thrown toExecutorTo deal with. eachPollerThreads have their ownQueue. eachPollerThreads can be multiple at the same timeAcceptorThread calls to registerPollerEventPollerConstantly through the internalSelectorObject queries to the kernelChannelOnce readable, the task class is generatedSocketProcessortoExecutorTo deal with.PollerAnother important task is to iterate over what you manageSocketChannelIf it’s timed out, if it’s timed out, turn this offSocketChannel
  • ExecutorIs the thread pool, which is responsible for runningSocketProcessorThe task,SocketProcessorrun()Method will callHttp11ProcessorTo read and parse the request data.ServerSocketChannelthroughaccept()Accept new connections,accept()Method return getSocketChannelObject, and then willSocketChannelThe object is encapsulated in onePollerEventObject, and willPollerEventPress the object intoPollerQueueIt’s a classic producer-consumer model,AcceptorPollerThread to thread passQueueCommunication.

reference

Jonhuster.blog.csdn.net/article/det…


This article is constantly updated, you can search “Geek excavator” on wechat to read it in the first time, and the key words in reply have all kinds of tutorials PREPARED by me, welcome to read.