1 概述1.0 关键依赖包以
springboot:2.3.12.RELEASE
中内嵌的tomcat-embed-core:9.0.46
为例,进行分析
spring-boot-autoconfigure
: 2.3.12.RELEASEspring-boot
: 2.3.12.RELEASEspring-context
: 5.2.15.RELEASEspring-webmvc
: 5.2.15.RELEASEtomcat-embed-core
:9.0.46tomcat-embed-jasper
:9.0.461.1 内嵌 Web Server 的优势我们在使用 springboot 开发 web 项目时,大多数时候采用的是内置的 Tomcat (当然也可配置支持内置的 jett y),内置 Tomcat 有什么好处呢?
(相关资料图)
方便微服务部署,减少繁杂的配置方便项目启动,不需要单独下载web容器,如Tomcat,jetty等。1.2 Web Server 的优化思路针对目前的容器优化,可以从以下几点考虑:
1、线程数2、超时时间首先,线程数是一个重点,每一次HTTP请求到达Web服务器,Web服务器都会创建一个线程来处理该请求,该参数决定了应用服务同时可以处理多少个HTTP请求。比较重要的有两个:1) 初始线程数; 2) 最大线程数。
初始线程数:保障启动的时候,如果有大量用户访问,能够很稳定的接受请求。最大线程数:用来保证系统的稳定性。
3、JVM优化1.3 Tomcat Web Server的核心配置参数min-spare-threads超时时间:用来保障连接数不容易被压垮。如果大批量的请求过来,延迟比较高,很容易把线程数用光,这时就需要提高超时时间。这种情况在生产中是比较常见的 ,一旦网络不稳定,宁愿丢包也不能把服务器压垮。
max-threads默认 10最小备用线程数,tomcat启动时的初始化的线程数。
accept-count默认 200Tomcat可创建的最大的线程数,每一个线程处理一个请求;超过这个请求数后,客户端请求只能排队,等有线程释放才能处理。建议:这个配置数可以在服务器CUP核心数的 200~250 倍之间
max-connections默认 100当调用Web服务的HTTP请求数达到tomcat的最大线程数时,还有新的HTTP请求到来,这时tomcat会将该请求放在等待队列中这个acceptCount就是指能够接受的最大等待数如果等待队列也被放满了,这个时候再来新的请求就会被tomcat拒绝(connection refused)。
connection-timeout这个参数是指在同一时间,tomcat能够接受的最大连接数。(最大线程数+排队数)一般这个值要大于 (max-threads)+(accept-count)。
keepAliveTimeout1 默认值: 60S or 20S2 参数定义: 与客户端建立连接后,Tomcat 等待客户端请求的时间。 如果客户端没有请求进来,等待一段时间后断开连接,释放线程。3 备注说明: Tomcat 中 等效于 : socket.soTimeout (SO_TIMEOUT) => 即: 为 socket 调用 read() 等待读取的时间4 入口类:
Tomcat 在关闭连接(Connector)之前,等待另一个请求的时间
HTTP 1.0HTTP 1.1http协议的早期是,每开启一个http链接,是要进行一次socket,也就是新启动一个TCP链接。
1 特性:长连接 (现主流浏览器的默认协议)2 使用keep-alive可以改善这种状态,即在一次TCP连接中可以持续发送多份数据而不会断开连接。通过使用keep-alive机制,可以减少tcp连接建立次数。3 如果浏览器支持keepalive的话,那么请求头中会有: Connection: Keep-Alive4 对于keepalive的部分,主要集中在Connection属性当中,这个属性可以设置两个值:
close (告诉WEB服务器或者代理服务器,在完成本次请求的响应后,断开连接,不要等待本次连接的后续请求了)。keepalive (告诉WEB服务器或者代理服务器,在完成本次请求的响应后,保持连接,等待本次连接的后续请求)。5 keep-alive与TIME_WAIT的关系?使用http keep-alive,可以减少服务端TIME_WAIT数量(因为由服务端httpd守护进程主动关闭连接)。道理很简单,相较而言,启用keep-alive,建立的tcp连接更少了,自然要被关闭的tcp连接也相应更少了。什么是TIME_WAIT呢?通信双方建立TCP连接后,主动关闭连接的一方就会进入TIME_WAIT状态。客户端主动关闭连接时,会发送最后一个ack后,然后会进入TIME_WAIT状态,再停留2个MSL时间,进入CLOSED状态。那么这个TIME_WAIT到底有什么作用呢?主要原因:a)可靠地实现TCP全双工连接的终止b)允许老的重复分节在网络中消逝6 截止目前,我们讨论的是 http 1.1 request/response header 的 keep-alive 选项;而 tcp协议 也有keepalive的概念。
http keep-alive与tcp keep-alive,不是同一回事,意图不一样。http keep-alive是为了让tcp活得更久一点,以便在同一个连接上传送多个http,提高socket的效率。而tcp keep-alive是TCP的一种检测TCP连接状况的保鲜机制。tcp keep-alive保鲜定时器,支持三个系统内核配置参数:echo 1800 > /proc/sys/net/ipv4/tcp_keepalive_timeecho 15 > /proc/sys/net/ipv4/tcp_keepalive_intvlecho 5 > /proc/sys/net/ipv4/tcp_keepalive_probeskeepalive是TCP保鲜定时器,当网络两端建立了TCP连接之后,闲置idle(双方没有任何数据流发送往来)了tcp_keepalive_time后,服务器内核就会尝试向客户端发送侦测包,来判断TCP连接状况(有可能客户端崩溃、强制关闭了应用、主机不可达等等)。如果没有收到对方的回答(ack包),则会在 tcp_keepalive_intvl后再次尝试发送侦测包,直到收到对对方的ack,如果一直没有收到对方的ack,一共会尝试 tcp_keepalive_probes次,每次的间隔时间在这里分别是15s, 30s, 45s, 60s, 75s。如果尝试tcp_keepalive_probes,依然没有收到对方的ack包,则会丢弃该TCP连接。TCP连接默认闲置时间是2小时,一般设置为30分钟足够了。总结一下,实际上tcp keep-alive是一个协议级别的心跳检测实现,当超过规定的时间,tcp就断开,而这边是讨论的http的keepalive,描述的http高层多次tcp链接共享,根本不是一个网络层级的东西,一定注意不要混淆。
1.4 springboot --> tomcatspring-boot-autoconfigure : 2.3.12.RELEASE-> org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration @ConditionalOnClass({Tomcat.class, UpgradeProtocol.class}) public static class TomcatWebServerFactoryCustomizerConfiguration { [*] @Bean public TomcatWebServerFactoryCustomizer tomcatWebServerFactoryCustomizer(Environment environment, ServerProperties serverProperties){ return new TomcatWebServerFactoryCustomizer(environment, serverProperties); } } -> org.springframework.boot.autoconfigure.web.embedded.TomcatWebServerFactoryCustomizer + 关系: public class TomcatWebServerFactoryCustomizer implements WebServerFactoryCustomizer, Ordered { /** ... **/ } + 属性: private final Environment environment; private final org.springframework.boot.autoconfigure.web.ServerProperties serverProperties; [*] + 方法: public void customize(ConfigurableTomcatWebServerFactory factory) { ServerProperties properties = this.serverProperties; ServerProperties.Tomcat tomcatProperties = properties.getTomcat(); --> Tomcat { // 内部类 private final Threads threads = new Threads(); ... private int maxConnections; private int acceptCount; ... private Duration connectionTimeout; ... private Charset uriEncoding; --> Threads { // 内部类 private int max = 200; private int minSpare = 10; } } PropertyMapper propertyMapper = PropertyMapper.get(); ServerProperties.Tomcat.Threads threadProperties = tomcatProperties.getThreads(); ... propertyMapper.from(threadProperties::getMax).when(this::isPositive).to((maxThreads) -> { this.customizeMaxThreads(factory, threadProperties.getMax()); }); ... propertyMapper.from(threadProperties::getMinSpare).when(this::isPositive).to((minSpareThreads) -> { this.customizeMinThreads(factory, minSpareThreads); }); ... propertyMapper.from(tomcatProperties::getMaxHttpFormPostSize).asInt(DataSize::toBytes).when((maxHttpFormPostSize) -> { return maxHttpFormPostSize != 0; }).to((maxHttpFormPostSize) -> { this.customizeMaxHttpFormPostSize(factory, maxHttpFormPostSize); }); ... propertyMapper.from(tomcatProperties::getAccesslog).when(ServerProperties.Tomcat.Accesslog::isEnabled).to((enabled) -> { this.customizeAccessLog(factory); }); ... propertyMapper.from(tomcatProperties::getUriEncoding).whenNonNull().to(factory::setUriEncoding); ... propertyMapper.from(tomcatProperties::getConnectionTimeout).whenNonNull().to((connectionTimeout) -> { this.customizeConnectionTimeout(factory, connectionTimeout); }); ... propertyMapper.from(tomcatProperties::getMaxConnections).when(this::isPositive).to((maxConnections) -> { this.customizeMaxConnections(factory, maxConnections); }); ... propertyMapper.from(tomcatProperties::getAcceptCount).when(this::isPositive).to((acceptCount) -> { this.customizeAcceptCount(factory, acceptCount); }); } private void customizeAcceptCount(ConfigurableTomcatWebServerFactory factory, int acceptCount) { factory.addConnectorCustomizers(new TomcatConnectorCustomizer[]{(connector) -> { ProtocolHandler handler = connector.getProtocolHandler(); if (handler instanceof AbstractProtocol) { AbstractProtocol> protocol = (AbstractProtocol)handler; protocol.setAcceptCount(acceptCount); } }}); } ... private void customizeMaxConnections(ConfigurableTomcatWebServerFactory factory, int maxConnections) { factory.addConnectorCustomizers(new TomcatConnectorCustomizer[]{(connector) -> { ProtocolHandler handler = connector.getProtocolHandler(); if (handler instanceof AbstractProtocol) { AbstractProtocol> protocol = (AbstractProtocol)handler; protocol.setMaxConnections(maxConnections); } }}); } ...
X 参考文献使用Tomcat设置Session - CSDN
标签:
仓储物流“成渝圈”如何乘势而上? 12月3日,连接昆明和万象的中老铁路全线开通运营,被惠及的显...
两件西周青铜簋时隔三千年成功配对 考古工作者介绍,这个铜簋的盖、身分别时隔40余年出土,纹饰...
“医保砍价”不是一个人在战斗 晁星 “我眼泪都快掉下来了”“每一个小群体都不该被放弃”…...
“购物成瘾”真的是一种病 刘艳 牛雅娟 本周日即将迎来“双十二”促销季,很多人又开始摩拳...
因迷恋山间风景,一男子在甘孜州稻城县海拔4000多米的无人区迷失方向,随后与同伴失联。12月的稻城...
嫌疑人DNA信息比中后,成都市公安局刑侦支队技术处DNA实验室民警白小刚一下坐在凳子上,恍惚迟疑间...
一批反映南京大屠杀历史的新书发布 新华社南京12月7日电(记者邱冰清、蒋芳)“以史为鉴,开创未来...
我在现场·照片背后的故事|电影《亲爱的》里面没有的结局,在我眼前“上映” 12月6日,在深圳市...
冥想?泡脚?不如听听助眠音乐 晚上睡不着,白天睡不醒,成为最贴合都市人群的“睡眠画像”。随...
养老话题 老年教育面临缺口 “终身教育”潜力无限 【现实挑战】“新老年”群体愿意在培养兴...
孙海洋被拐14年儿子如何找到的? 警方侦办另一宗拐骗儿童案时发现线索,通过人像比对、DNA确认找...
北京天文馆、圆明园将对未成年人免费开放 12月6日,北京天文馆发布通知称,12月8日起试行对未成...
今年全国粮食总产量再创新高 连续7年保持在1 3万亿斤以上 根据对全国31个省(区、市)的抽样调...
斑块软的很危险 硬的就无碍? 血管里的“垃圾”分类 赶快学起来! 一项最新研究显示:中国...
诺西那生钠注射液大幅降价 聚焦医保谈判背后脊髓性肌萎缩症家庭 医保目录公布那天 好多家长都...
抖音“窗花剪剪”遭抄袭 被判获赔20万元 法院认为“窗花剪剪”的这种表达方式理应受到《著作权...
公安机关近日侦破3起拐卖儿童案件 失散十几年 3组家庭终于团圆了 北京青年报记者12月6日从公...
2021年度十大网络用语发布 本报讯(记者 路艳霞)作为年度“汉语盘点”活动最具网络特色的组成部...
北京天文馆向未成年人免费开放 本报讯(记者 牛伟坤)北京天文馆对票价免费及优惠政策作出调整:1...
2021北京百个网红打卡地发布 本报讯(记者 李洋)2021北京网红打卡地推荐榜单昨晚正式发布。自然...