keep-alive主要靠服务器实现,那么问题来了,作为java程序的主流服务容器,tomcat 是如何实现keep-alive的呢?
先看tomcat,以主流的nio实现为例
在NioEndpoint.SocketProcessor#doRun的方法中会处理三次握手:
if (handshake == 0) {
log.info("开启三次握手验证");
SocketState state = SocketState.OPEN;
// Process the request from this socket
if (event == null) {
log.info("state = getHandler().process(socketWrapper, SocketEvent.OPEN_READ);");
state = getHandler().process(socketWrapper, SocketEvent.OPEN_READ);
} else {
log.info("state = getHandler().process(socketWrapper, event);");
state = getHandler().process(socketWrapper, event);
}
if (state == SocketState.CLOSED) {
poller.cancelledKey(key, socketWrapper);
}
} else if (handshake == -1 ) {
getHandler().process(socketWrapper, SocketEvent.CONNECT_FAIL);
poller.cancelledKey(key, socketWrapper);
} else if (handshake == SelectionKey.OP_READ){
socketWrapper.registerReadInterest();
} else if (handshake == SelectionKey.OP_WRITE){
socketWrapper.registerWriteInterest();
}
处理后的finally会将当前的SocketProcessor加入到缓存中:
if (running && !paused && processorCache != null) {
processorCache.push(this);
}
下次Poller在执行processSocket 中会先判断processorCache是否为空,不为空则拿出来直接使用,跳过三次握手
就这么简单吗?
仔细想想,好像不对,tomcat是怎么判断两次请求是应该复用同一个processSocket的呢?除非,第一次创建socketChannel没有关闭。那就意味着,这个socketChannel一直阻塞在work threadPool里?!太可怕,所以tomcat 对keep-alive有很苛刻的要求,线程池容量不够的情况下也不支持。这篇文章写完大半年后,看到了H大的文章,不禁眼泪掉下来。我将这篇文章大部分内容删掉,只保留了自己的思考和线索。以后这类文章少写,或者放在自己的备忘录就好了。 H大的文章地址:tomcat对keep-alive的实现逻辑