当前tomcat 8.5.20中已经不再使用bio模型,默认支持NIO实现的org.apache.coyote.http11.Http11NioProtocol,当前tomcat支持的io模型如下:
在Tomcat启动时会启用一个端口来监听请求,并且会启动多个线程来处理相关的请求操作,如下图:
相关线程介绍:
(1)http-nio-8080-Acceptor为请求接收器,其只接收请求,不会对请求做任务业务处理操作,所以默认为单个线程。
(2)http-nio-8080-ClientPoller-0和http-nio-8080-ClientPoller-1为两个是作为轮询器或者转发器使用的,简单来说就是对获取到的SocketWrapper添加到一个线程池中进行处理,这种类型的线程数与CPU的核数有关。
(3)http-nio-8080-exec-1到10是tomcat的一个线程池产生的默认的10线程,这10个线程是用来执行具体的servlet请求操作,线程的数目可以跟随请求说的变化而变化。
以上3种类型的线程有点类似Reactor模式。
接下来我们看看tomcat是如何处理一个Servlet请求的。
1、tomcat启动时会初始化一个http-nio-8080-Acceptor线程来接收请求
- protected class Acceptor extends AbstractEndpoint.Acceptor {
-
- @Override
- public void run() {
-
- int errorDelay = 0;
-
- while (running) {
-
-
- while (paused && running) {
- state = AcceptorState.PAUSED;
- try {
- Thread.sleep(50);
- } catch (InterruptedException e) {
-
- }
- }
-
- if (!running) {
- break;
- }
- state = AcceptorState.RUNNING;
-
- try {
- countUpOrAwaitConnection();
-
- SocketChannel socket = null;
- try {
-
-
-
- socket = serverSock.accept();
- } catch (IOException ioe) {
-
- countDownConnection();
- if (running) {
-
- errorDelay = handleExceptionWithDelay(errorDelay);
-
- throw ioe;
- } else {
- break;
- }
- }
-
- errorDelay = 0;
-
-
- if (running && !paused) {
-
-
-
- if (!setSocketOptions(socket)) {
- closeSocket(socket);
- }
- } else {
- closeSocket(socket);
- }
- } catch (Throwable t) {
- ExceptionUtils.handleThrowable(t);
- log.error(sm.getString("endpoint.accept.fail"), t);
- }
- }
- state = AcceptorState.ENDED;
- }
-
-
- private void closeSocket(SocketChannel socket) {
- countDownConnection();
- try {
- socket.socket().close();
- } catch (IOException ioe) {
- if (log.isDebugEnabled()) {
- log.debug(sm.getString("endpoint.err.close"), ioe);
- }
- }
- try {
- socket.close();
- } catch (IOException ioe) {
- if (log.isDebugEnabled()) {
- log.debug(sm.getString("endpoint.err.close"), ioe);
- }
- }
- }
- }
在上面代码中, socket = serverSock.accept();与客户端建立连接,将连接的socket交给processSocket(socket)来处理,在processSocket会将socket进行包装成NioChannel交给Poller线程来进行处理。
- protected boolean setSocketOptions(SocketChannel socket) {
-
- try {
-
- socket.configureBlocking(false);
- Socket sock = socket.socket();
- socketProperties.setProperties(sock);
-
- NioChannel channel = nioChannels.pop();
- if (channel == null) {
- SocketBufferHandler bufhandler = new SocketBufferHandler(
- socketProperties.getAppReadBufSize(),
- socketProperties.getAppWriteBufSize(),
- socketProperties.getDirectBuffer());
- if (isSSLEnabled()) {
- channel = new SecureNioChannel(socket, bufhandler, selectorPool, this);
- } else {
- channel = new NioChannel(socket, bufhandler);
- }
- } else {
- channel.setIOChannel(socket);
- channel.reset();
- }
-
- getPoller0().register(channel);
- } catch (Throwable t) {
- ExceptionUtils.handleThrowable(t);
- try {
- log.error("",t);
- } catch (Throwable tt) {
- ExceptionUtils.handleThrowable(tt);
- }
-
- return false;
- }
- return true;
- }
2、tomcat根据处理器核数创建http-nio-8080-ClientPoller-0和http-nio-8080-ClientPoller-1线程
Poller线程会通过while(true)不断从selector.selectdKeys获取是否有连接存在,如果有连接存在则从SelectionKey中获取NioSocketWrapper并通过processKey来进行处理
- @Override
- public void run() {
-
- while (true) {
-
- boolean hasEvents = false;
-
- try {
- if (!close) {
- hasEvents = events();
- if (wakeupCounter.getAndSet(-1) > 0) {
-
-
- keyCount = selector.selectNow();
- } else {
- keyCount = selector.select(selectorTimeout);
- }
- wakeupCounter.set(0);
- }
- if (close) {
- events();
- timeout(0, false);
- try {
- selector.close();
- } catch (IOException ioe) {
- log.error(sm.getString("endpoint.nio.selectorCloseFail"), ioe);
- }
- break;
- }
- } catch (Throwable x) {
- ExceptionUtils.handleThrowable(x);
- log.error("",x);
- continue;
- }
-
- if ( keyCount == 0 ) hasEvents = (hasEvents | events());
-
- Iterator iterator =
- keyCount > 0 ? selector.selectedKeys().iterator() : null;
-
-
- while (iterator != null && iterator.hasNext()) {
- SelectionKey sk = iterator.next();
- NioSocketWrapper attachment = (NioSocketWrapper)sk.attachment();
-
-
- if (attachment == null) {
- iterator.remove();
- } else {
- iterator.remove();
-
- processKey(sk, attachment);
- }
- }
-
-
- timeout(keyCount,hasEvents);
- }
-
- getStopLatch().countDown();
- }
在processKey中会判断一些SelectionKeyd 的状态,并将NioSocketWrapper提交给processSocket(SocketWrapperBase socketWrapper,
SocketEvent event, boolean dispatch)来进行处理。
- public boolean processSocket(SocketWrapperBase
socketWrapper,
- SocketEvent event, boolean dispatch) {
- try {
- if (socketWrapper == null) {
- return false;
- }
- SocketProcessorBase
sc = processorCache.pop();
- if (sc == null) {
- sc = createSocketProcessor(socketWrapper, event);
- } else {
- sc.reset(socketWrapper, event);
- }
-
- Executor executor = getExecutor();
- if (dispatch && executor != null) {
- executor.execute(sc);
- } else {
- sc.run();
- }
- } catch (RejectedExecutionException ree) {
- getLog().warn(sm.getString("endpoint.executor.fail", socketWrapper) , ree);
- return false;
- } catch (Throwable t) {
- ExceptionUtils.handleThrowable(t);
-
-
- getLog().error(sm.getString("endpoint.process.fail"), t);
- return false;
- }
- return true;
- }
在processSocket函数中会获取请求处理线程,将SocketProcessor提交到线程池中进行请求处理操作。
2、tomcat创建线程池来处理所有的servlet请求,线程池中线程名称为http-nio-8080-exec-1到10,用来对具体的请求进行处理操作,NIO对应的线程操作类为SocketProcessor。
在socketProcessor线程运行时会调用doRun()方法,在doRun()方法中调用getHandler().process(socketWrapper, SocketEvent.OPEN_READ)来处理socketWrapper请求
- protected class SocketProcessor extends SocketProcessorBase {
-
- public SocketProcessor(SocketWrapperBase socketWrapper, SocketEvent event) {
- super(socketWrapper, event);
- }
-
- @Override
- protected void doRun() {
- NioChannel socket = socketWrapper.getSocket();
- SelectionKey key = socket.getIOChannel().keyFor(socket.getPoller().getSelector());
-
- try {
- int handshake = -1;
-
- try {
- if (key != null) {
- if (socket.isHandshakeComplete()) {
-
- handshake = 0;
- } else if (event == SocketEvent.STOP || event == SocketEvent.DISCONNECT ||
- event == SocketEvent.ERROR) {
- handshake = -1;
- } else {
- handshake = socket.handshake(key.isReadable(), key.isWritable());
-
- event = SocketEvent.OPEN_READ;
- }
- }
- } catch (IOException x) {
- handshake = -1;
- if (log.isDebugEnabled()) log.debug("Error during SSL handshake",x);
- } catch (CancelledKeyException ckx) {
- handshake = -1;
- }
- if (handshake == 0) {
- SocketState state = SocketState.OPEN;
-
-
- if (event == null) {
- state = getHandler().process(socketWrapper, SocketEvent.OPEN_READ);
- } else {
- state = getHandler().process(socketWrapper, event);
- }
- if (state == SocketState.CLOSED) {
- close(socket, key);
- }
- } else if (handshake == -1 ) {
- close(socket, key);
- } else if (handshake == SelectionKey.OP_READ){
- socketWrapper.registerReadInterest();
- } else if (handshake == SelectionKey.OP_WRITE){
- socketWrapper.registerWriteInterest();
- }
- } catch (CancelledKeyException cx) {
- socket.getPoller().cancelledKey(key);
- } catch (VirtualMachineError vme) {
- ExceptionUtils.handleThrowable(vme);
- } catch (Throwable t) {
- log.error("", t);
- socket.getPoller().cancelledKey(key);
- } finally {
- socketWrapper = null;
- event = null;
-
- if (running && !paused) {
- processorCache.push(this);
- }
- }
- }
- }
在父类AbstractProtocol的process方法中会获取处理器Processor,在处理器Processor.process(SocketWrapperBase> socketWrapper, SocketEvent status)中调用service方法处理socketWrapper
- @Override
- public SocketState process(SocketWrapperBase> socketWrapper, SocketEvent status)
- throws IOException {
-
- SocketState state = SocketState.CLOSED;
- Iterator dispatches = null;
- do {
- if (dispatches != null) {
- DispatchType nextDispatch = dispatches.next();
- state = dispatch(nextDispatch.getSocketStatus());
- } else if (status == SocketEvent.DISCONNECT) {
-
- } else if (isAsync() || isUpgrade() || state == SocketState.ASYNC_END) {
- state = dispatch(status);
- if (state == SocketState.OPEN) {
-
-
-
-
-
-
- state = service(socketWrapper);
- }
- } else if (status == SocketEvent.OPEN_WRITE) {
-
- state = SocketState.LONG;
- } else if (status == SocketEvent.OPEN_READ){
- state = service(socketWrapper);
- } else {
-
-
- state = SocketState.CLOSED;
- }
-
- if (state != SocketState.CLOSED && isAsync()) {
- state = asyncPostProcess();
- }
-
- if (getLog().isDebugEnabled()) {
- getLog().debug("Socket: [" + socketWrapper +
- "], Status in: [" + status +
- "], State out: [" + state + "]");
- }
-
- if (dispatches == null || !dispatches.hasNext()) {
-
-
- dispatches = getIteratorAndClearDispatches();
- }
- } while (state == SocketState.ASYNC_END ||
- dispatches != null && state != SocketState.CLOSED);
-
- return state;
- }
在http11Processor中调用service(socketWrapper)进行处理操作,调用CoyoteAdapter的service(request,response)方法进行请求操作。
- @Override
- public SocketState service(SocketWrapperBase> socketWrapper)
- throws IOException {
- RequestInfo rp = request.getRequestProcessor();
- rp.setStage(org.apache.coyote.Constants.STAGE_PARSE);
-
-
- setSocketWrapper(socketWrapper);
- inputBuffer.init(socketWrapper);
- outputBuffer.init(socketWrapper);
-
-
- keepAlive = true;
- openSocket = false;
- readComplete = true;
- boolean keptAlive = false;
- SendfileState sendfileState = SendfileState.DONE;
-
- while (!getErrorState().isError() && keepAlive && !isAsync() && upgradeToken == null &&
- sendfileState == SendfileState.DONE && !endpoint.isPaused()) {
-
-
- try {
- if (!inputBuffer.parseRequestLine(keptAlive)) {
- if (inputBuffer.getParsingRequestLinePhase() == -1) {
- return SocketState.UPGRADING;
- } else if (handleIncompleteRequestLineRead()) {
- break;
- }
- }
-
- if (endpoint.isPaused()) {
-
- response.setStatus(503);
- setErrorState(ErrorState.CLOSE_CLEAN, null);
- } else {
- keptAlive = true;
-
- request.getMimeHeaders().setLimit(endpoint.getMaxHeaderCount());
- if (!inputBuffer.parseHeaders()) {
-
-
- openSocket = true;
- readComplete = false;
- break;
- }
- if (!disableUploadTimeout) {
- socketWrapper.setReadTimeout(connectionUploadTimeout);
- }
- }
- } catch (IOException e) {
- if (log.isDebugEnabled()) {
- log.debug(sm.getString("http11processor.header.parse"), e);
- }
- setErrorState(ErrorState.CLOSE_CONNECTION_NOW, e);
- break;
- } catch (Throwable t) {
- ExceptionUtils.handleThrowable(t);
- UserDataHelper.Mode logMode = userDataHelper.getNextMode();
- if (logMode != null) {
- String message = sm.getString("http11processor.header.parse");
- switch (logMode) {
- case INFO_THEN_DEBUG:
- message += sm.getString("http11processor.fallToDebug");
-
- case INFO:
- log.info(message, t);
- break;
- case DEBUG:
- log.debug(message, t);
- }
- }
-
- response.setStatus(400);
- setErrorState(ErrorState.CLOSE_CLEAN, t);
- getAdapter().log(request, response, 0);
- }
-
-
- Enumeration connectionValues = request.getMimeHeaders().values("Connection");
- boolean foundUpgrade = false;
- while (connectionValues.hasMoreElements() && !foundUpgrade) {
- foundUpgrade = connectionValues.nextElement().toLowerCase(
- Locale.ENGLISH).contains("upgrade");
- }
-
- if (foundUpgrade) {
-
- String requestedProtocol = request.getHeader("Upgrade");
-
- UpgradeProtocol upgradeProtocol = httpUpgradeProtocols.get(requestedProtocol);
- if (upgradeProtocol != null) {
- if (upgradeProtocol.accept(request)) {
-
-
- response.setStatus(HttpServletResponse.SC_SWITCHING_PROTOCOLS);
- response.setHeader("Connection", "Upgrade");
- response.setHeader("Upgrade", requestedProtocol);
- action(ActionCode.CLOSE, null);
- getAdapter().log(request, response, 0);
-
- InternalHttpUpgradeHandler upgradeHandler =
- upgradeProtocol.getInternalUpgradeHandler(
- getAdapter(), cloneRequest(request));
- UpgradeToken upgradeToken = new UpgradeToken(upgradeHandler, null, null);
- action(ActionCode.UPGRADE, upgradeToken);
- return SocketState.UPGRADING;
- }
- }
- }
-
- if (!getErrorState().isError()) {
-
- rp.setStage(org.apache.coyote.Constants.STAGE_PREPARE);
- try {
- prepareRequest();
- } catch (Throwable t) {
- ExceptionUtils.handleThrowable(t);
- if (log.isDebugEnabled()) {
- log.debug(sm.getString("http11processor.request.prepare"), t);
- }
-
- response.setStatus(500);
- setErrorState(ErrorState.CLOSE_CLEAN, t);
- getAdapter().log(request, response, 0);
- }
- }
-
- if (maxKeepAliveRequests == 1) {
- keepAlive = false;
- } else if (maxKeepAliveRequests > 0 &&
- socketWrapper.decrementKeepAlive() <= 0) {
- keepAlive = false;
- }
-
-
- if (!getErrorState().isError()) {
- try {
- rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE);
- getAdapter().service(request, response);
-
-
-
-
-
- if(keepAlive && !getErrorState().isError() && !isAsync() &&
- statusDropsConnection(response.getStatus())) {
- setErrorState(ErrorState.CLOSE_CLEAN, null);
- }
- } catch (InterruptedIOException e) {
- setErrorState(ErrorState.CLOSE_CONNECTION_NOW, e);
- } catch (HeadersTooLargeException e) {
- log.error(sm.getString("http11processor.request.process"), e);
-
-
- if (response.isCommitted()) {
- setErrorState(ErrorState.CLOSE_NOW, e);
- } else {
- response.reset();
- response.setStatus(500);
- setErrorState(ErrorState.CLOSE_CLEAN, e);
- response.setHeader("Connection", "close");
- }
- } catch (Throwable t) {
- ExceptionUtils.handleThrowable(t);
- log.error(sm.getString("http11processor.request.process"), t);
-
- response.setStatus(500);
- setErrorState(ErrorState.CLOSE_CLEAN, t);
- getAdapter().log(request, response, 0);
- }
- }
-
-
- rp.setStage(org.apache.coyote.Constants.STAGE_ENDINPUT);
- if (!isAsync()) {
-
-
-
- endRequest();
- }
- rp.setStage(org.apache.coyote.Constants.STAGE_ENDOUTPUT);
-
-
-
- if (getErrorState().isError()) {
- response.setStatus(500);
- }
-
- if (!isAsync() || getErrorState().isError()) {
- request.updateCounters();
- if (getErrorState().isIoAllowed()) {
- inputBuffer.nextRequest();
- outputBuffer.nextRequest();
- }
- }
-
- if (!disableUploadTimeout) {
- int soTimeout = endpoint.getConnectionTimeout();
- if(soTimeout > 0) {
- socketWrapper.setReadTimeout(soTimeout);
- } else {
- socketWrapper.setReadTimeout(0);
- }
- }
-
- rp.setStage(org.apache.coyote.Constants.STAGE_KEEPALIVE);
-
- sendfileState = processSendfile(socketWrapper);
- }
-
- rp.setStage(org.apache.coyote.Constants.STAGE_ENDED);
-
- if (getErrorState().isError() || endpoint.isPaused()) {
- return SocketState.CLOSED;
- } else if (isAsync()) {
- return SocketState.LONG;
- } else if (isUpgrade()) {
- return SocketState.UPGRADING;
- } else {
- if (sendfileState == SendfileState.PENDING) {
- return SocketState.SENDFILE;
- } else {
- if (openSocket) {
- if (readComplete) {
- return SocketState.OPEN;
- } else {
- return SocketState.LONG;
- }
- } else {
- return SocketState.CLOSED;
- }
- }
- }
- }