SpringBoot的启动容器主要是Tomcat,Jetty,Undertow三种容器类型,具体的配置类为

org.springframework.boot.autoconfigure.web.ServerProperties

@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
public class ServerProperties {/*** Server HTTP port.*/private Integer port;/*** Network address to which the server should bind.*/private InetAddress address;@NestedConfigurationPropertyprivate final ErrorProperties error = new ErrorProperties();/*** Strategy for handling X-Forwarded-* headers.*/private ForwardHeadersStrategy forwardHeadersStrategy;/*** Value to use for the Server response header (if empty, no header is sent).*/private String serverHeader;/*** Maximum size of the HTTP message header.*/private DataSize maxHttpHeaderSize = DataSize.ofKilobytes(8);/*** Type of shutdown that the server will support.*/private Shutdown shutdown = Shutdown.IMMEDIATE;@NestedConfigurationPropertyprivate Ssl ssl;@NestedConfigurationPropertyprivate final Compression compression = new Compression();@NestedConfigurationPropertyprivate final Http2 http2 = new Http2();private final Servlet servlet = new Servlet();private final Tomcat tomcat = new Tomcat();private final Jetty jetty = new Jetty();private final Netty netty = new Netty();private final Undertow undertow = new Undertow();public Integer getPort() {return this.port;}..............
}

Server相关

port

端口 默认值为8080

address

org.apache.coyote.AbstractProtocol类中的地址(Tomcat)

ErrorProperties

path

如果发生error,将会跳到的页面。实际上是SpringMvc控制。

public void registerErrorPages(ErrorPageRegistry errorPageRegistry) {ErrorPage errorPage = new ErrorPage(this.dispatcherServletPath.getRelativePath(this.properties.getError().getPath()));errorPageRegistry.addErrorPages(errorPage);}

includeException

结果是否包含Exception,默认为false,如果设置为true,默认情况下会将Exception返回给前端

private void addErrorDetails(Map<String, Object> errorAttributes, WebRequest webRequest,boolean includeStackTrace) {Throwable error = getError(webRequest);if (error != null) {while (error instanceof ServletException && error.getCause() != null) {error = error.getCause();}errorAttributes.put("exception", error.getClass().getName());if (includeStackTrace) {addStackTrace(errorAttributes, error);}}addErrorMessage(errorAttributes, webRequest, error);}

includeStacktrace

结果是否包含异常栈信息,默认为Never,有三个选项

  • never 默认情况
  • ALWAYS 总是返回异常栈的信息
  • ON_PARAM 请求参数加入 trace且值为 true的时候会打印栈的信息
protected boolean isTraceEnabled(ServerRequest request) {return getBooleanParameter(request, "trace");}

includeMessage

Exception中的异常信息,默认为never,有三个选项

  • never 默认值

  • always 总是返回message 如果没有信息 返回 No message available

  • ON_PARAM 加入请求参数 message且为true的时候返回message

includeBindingErrors

是否返回 error,默认为never,有三个选项

  • never永远不打印

  • always 总是

  • ON_PARAM 加入请求参数为 errors 且为true的时候打印

whitelabel

白标,主要是Undertow的时候有用,当没有配置errorPath的时候,且这个值为true的时候默认一个页面。

protected Mono<ServerResponse> renderErrorView(ServerRequest request) {Map<String, Object> error = getErrorAttributes(request, getErrorAttributeOptions(request, MediaType.TEXT_HTML));int errorStatus = getHttpStatus(error);ServerResponse.BodyBuilder responseBody = ServerResponse.status(errorStatus).contentType(TEXT_HTML_UTF8);return Flux.just(getData(errorStatus).toArray(new String[] {})).flatMap((viewName) -> renderErrorView(viewName, responseBody, error)).switchIfEmpty(this.errorProperties.getWhitelabel().isEnabled()? renderDefaultErrorView(responseBody, error) : Mono.error(getError(request))).next();}

ForwardHeadersStrategy

是否透传Forward的请求头,有三个值选择,默认为 空

  • NATIVE 用当前容器支持的透传
  • FRAMEWORK Spring 框架支持的透传
  • NONE 完全不支持透传

这个的作用,我们在分布式系统中,当多台机器转发调用的时候,容易找不到每个部分的ip以及访问者的IP,也就是 X-Forwarded-*相关参数,这个参数方便我们判断,

具体的信息看类org.apache.catalina.valves.RemoteIpValve

serverHeader

返回的头,也就是为每一个服务请求返回设置头,如果设置为 a,那么返回的响应头就有

server: a

maxHttpHeaderSize

默认为8Kb,最大的请求头大小。

shutdown

关闭状态,值分为两种,默认为IMMEDIATE,如果是linux 就看kill的参数了。

  • GRACEFUL 等所有请求完成后才关闭
  • IMMEDIATE 立马关闭,

Ssl

ssl相关参数,

Compression

压缩相关配置

enabled

是否开启压缩

mimeTypes

压缩文件类型,

private static Predicate[] getCompressionPredicates(Compression compression) {List<Predicate> predicates = new ArrayList<>();predicates.add(new MaxSizePredicate((int) compression.getMinResponseSize().toBytes()));predicates.add(new CompressibleMimeTypePredicate(compression.getMimeTypes()));if (compression.getExcludedUserAgents() != null) {for (String agent : compression.getExcludedUserAgents()) {RequestHeaderAttribute agentHeader = new RequestHeaderAttribute(new HttpString(HttpHeaders.USER_AGENT));predicates.add(Predicates.not(Predicates.regex(agentHeader, agent)));}}return predicates.toArray(new Predicate[0]);}

excludedUserAgents

请求头中包含的User-Agent,是否需要排除压缩

minResponseSize

这个长度一定要在请求头中声明,不然这个属性将被忽略。

@Override
public boolean resolve(HttpServerExchange value) {if (value.getResponseHeaders().contains(Headers.CONTENT_LENGTH)) {return this.maxContentSize.resolve(value);}return true;
}

Http2

enable

是否为true,如果为true使用HTTP2.默认为false。

Http2总体相比较于1.1来说做了部分的性能优化,

  • 引入Hpack (org.apache.coyote.http2.Hpack) 来优化 头部
  • 引入Stream (org.apache.coyote.http2.Stream) 来解决队头阻塞问题

具体的实现类为 org.apache.coyote.http2.Http2Protocol

Servlet相关设置

这里就长话短说

contextParameters

上下文参数,

contextPath

项目路径

applicationDisplayName

项目名称

registerDefaultServlet

是否自动注入到容器

encoding

编码

JSP

jsp相关参数,

Session

session相关参数

persistent

是否持久化

Tomcat相关

tomcat工厂类为 org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory ,tomcat为默认的Spring-boot容器。

accesslog

日志参数配置

enabled

是否开启tomcat自己的日志,默认为false 不开启。

propertyMapper.from(tomcatProperties::getAccesslog).when(ServerProperties.Tomcat.Accesslog::isEnabled).to((enabled) -> customizeAccessLog(factory));

conditionIf

if (!getState().isAvailable() || !getEnabled() || logElements == null|| condition != null&& null != request.getRequest().getAttribute(condition)|| conditionIf != null&& null == request.getRequest().getAttribute(conditionIf)) {return;}

如果这个值设置了,且这个值没传。那么不打印日志

conditionUnless

如果这个值设置了,且传了。那么就不打印日志

pattern

日志格式。

directory

日志文件夹

prefix

日志文件夹前缀

Threads

这个参数调节Tomcat的最大工作线程和最小工作线程,

在tomcat中,线程池的创建方式如下

  • max参数是线程池的 maximumPoolSize的值,默认为200

  • minSpare 是线程池的corePoolSize的值,默认为10

  • tomcat中线程池的队列是org.apache.tomcat.util.threads.TaskQueue,他是一个阻塞队列。他的策略如下

    • 如果当前线程池满,装入队列(等待线程执行)
    • 如果当前线程池还没达到最小的参数,直接装入队列(直接用现有线程执行)
    • 如果当前提交数小于线程的最大值,返回false(新建线程执行)
    • 其他情况直接装入队列
  • 线程拒绝策略为默认(tomcat的线程池没配置最大队列)

public void setMinSpareThreads(int minSpareThreads) {this.minSpareThreads = minSpareThreads;Executor executor = this.executor;if (internalExecutor && executor instanceof java.util.concurrent.ThreadPoolExecutor) {// The internal executor should always be an instance of// j.u.c.ThreadPoolExecutor but it may be null if the endpoint is// not running.// This check also avoids various threading issues.((java.util.concurrent.ThreadPoolExecutor) executor).setCorePoolSize(minSpareThreads);}}public void setMaxThreads(int maxThreads) {this.maxThreads = maxThreads;Executor executor = this.executor;if (internalExecutor && executor instanceof java.util.concurrent.ThreadPoolExecutor) {// The internal executor should always be an instance of// j.u.c.ThreadPoolExecutor but it may be null if the endpoint is// not running.// This check also avoids various threading issues.((java.util.concurrent.ThreadPoolExecutor) executor).setMaximumPoolSize(maxThreads);}}

优化

这个参数是Tomcat调优的主要手段,这个值调大了容易造成资源浪费,调小了容易造成造成性能瓶颈。

这个值要根据性能测试以及业务复杂度,消耗资源度等综合评估,并不是简单的根据CPU核数来确定,具体还要看业务在CPU上的执行表现,以及业务是否波动,请求规律等

  • 比如一个可预见请求量很少,且与其他共用服务共用服务器的,可以将最小值和最大值都调小
  • 其他就根据CPU测试表现,数据库访问型,且访问较大或者独享资源。可以调大这个值。

basedir

tomcat的baseDir,如果没有指定。那么直接创建到临时目录

File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");

backgroundProcessorDelay

后台线程的处理间隔,默认值为10S,它最终将设置进Engine中。他会在启动的时候执行

org.apache.catalina.core.ContainerBase#startInternal

// Start our threadif (backgroundProcessorDelay > 0) {monitorFuture = Container.getService(ContainerBase.this).getServer().getUtilityExecutor().scheduleWithFixedDelay(new ContainerBackgroundProcessorMonitor(), 0, 60, TimeUnit.SECONDS);}protected void threadStart() {if (backgroundProcessorDelay > 0&& (getState().isAvailable() || LifecycleState.STARTING_PREP.equals(getState()))&& (backgroundProcessorFuture == null || backgroundProcessorFuture.isDone())) {if (backgroundProcessorFuture != null && backgroundProcessorFuture.isDone()) {// There was an error executing the scheduled task, get it and log ittry {backgroundProcessorFuture.get();} catch (InterruptedException | ExecutionException e) {log.error(sm.getString("containerBase.backgroundProcess.error"), e);}}backgroundProcessorFuture = Container.getService(this).getServer().getUtilityExecutor().scheduleWithFixedDelay(new ContainerBackgroundProcessor(),backgroundProcessorDelay, backgroundProcessorDelay,TimeUnit.SECONDS);}}

在后台线程通过DFS去遍历所有的Container,执行后台线程处理。

大约处理时事情有(初始化的时候):

  • org.apache.catalina.core.ContainerBase#backgroundProcess

    • org.apache.catalina.Cluster#backgroundProcess 集群相关的
    • org.apache.catalina.Realm#backgroundProcess 领域相关的
    • org.apache.catalina.Valve#backgroundProcess 管道相关的
    • 触发时间监听
  • org.apache.catalina.core.StandardWrapper#backgroundProcess

    触发周期类事件的监听,可以尝试做Tomcat的动态加载

  • org.apache.catalina.core.StandardContext#backgroundProcess

    • org.apache.catalina.Loader#backgroundProcess 资源重加载
    • org.apache.catalina.Manager#backgroundProcess 数据的持久化
    • org.apache.catalina.WebResourceRoot#backgroundProcess 资源更新和回收
    • org.apache.catalina.core.DefaultInstanceManager#backgroundProcess 缓存的释放

优化,

这个值如果设置过低,后台线程允许频繁,可能触发一些无效的事情,造成CPU飘高。

如果设置过低,可能会有些数据更新或者缓存回收不及时

这个要根据综合情况,建议观察org.apache.catalina.core.ContainerBase.ContainerBackgroundProcessor的执行时间和CPU的消耗程度,可以考虑用Arthas 和 top -H -p命令

maxHttpFormPostSize

最大表单请求,默认值为2MB。如果大于这个值,抛出IllegalStateException

while (len > -1) {len = getStream().read(buffer, 0, CACHED_POST_LEN);if (connector.getMaxPostSize() >= 0 &&(body.getLength() + len) > connector.getMaxPostSize()) {// Too much datacheckSwallowInput();throw new IllegalStateException(sm.getString("coyoteRequest.chunkedPostTooLarge"));}if (len > 0) {body.append(buffer, 0, len);}}

maxSwallowSize

主要作用于长连接,即Http1.1的控制

  1. 在发生IO异常的时候,会check这个参数,check这个参数是否大于了文件传输过来的大小。
public long end() throws IOException {final boolean maxSwallowSizeExceeded = (maxSwallowSize > -1 && remaining > maxSwallowSize);long swallowed = 0;// Consume extra bytes.while (remaining > 0) {int nread = buffer.doRead(this);tempRead = null;if (nread > 0 ) {swallowed += nread;remaining = remaining - nread;if (maxSwallowSizeExceeded && swallowed > maxSwallowSize) {// Note: We do not fail early so the client has a chance to// read the response before the connection is closed. See:// https://httpd.apache.org/docs/2.0/misc/fin_wait_2.html#appendixthrow new IOException(sm.getString("inputFilter.maxSwallow"));}} else { // errors are handled higher up.remaining = 0;}}// If too many bytes were read, return the amount.return -remaining;}

打开注释的链接,可以看见

Below is a message from Roy Fielding, one of the authors of HTTP/1.1.

Why the lingering close functionality is necessary with HTTP

The need for a server to linger on a socket after a close is noted a couple times in the HTTP specs, but not explained. This explanation is based on discussions between myself, Henrik Frystyk, Robert S. Thau, Dave Raggett, and John C. Mallery in the hallways of MIT while I was at W3C.

If a server closes the input side of the connection while the client is sending data (or is planning to send data), then the server’s TCP stack will signal an RST (reset) back to the client. Upon receipt of the RST, the client will flush its own incoming TCP buffer back to the un-ACKed packet indicated by the RST packet argument. If the server has sent a message, usually an error response, to the client just before the close, and the client receives the RST packet before its application code has read the error message from its incoming TCP buffer and before the server has received the ACK sent by the client upon receipt of that buffer, then the RST will flush the error message before the client application has a chance to see it. The result is that the client is left thinking that the connection failed for no apparent reason.

There are two conditions under which this is likely to occur:

  1. sending POST or PUT data without proper authorization
  2. sending multiple requests before each response (pipelining) and one of the middle requests resulting in an error or other break-the-connection result.

The solution in all cases is to send the response, close only the write half of the connection (what shutdown is supposed to do), and continue reading on the socket until it is either closed by the client (signifying it has finally read the response) or a timeout occurs. That is what the kernel is supposed to do if SO_LINGER is set. Unfortunately, SO_LINGER has no effect on some systems; on some other systems, it does not have its own timeout and thus the TCP memory segments just pile-up until the next reboot (planned or not).

Please note that simply removing the linger code will not solve the problem – it only moves it to a different and much harder one to detect.

大致的意思是

通常在长连接中,如果服务端在客户端发送或者计划发送数据的时候关闭输入端,服务器要发送RST给客户端,客户端收到RST后,客户端刷新TCP,根据RST包参数返回un-ACK包。一般服务器这个时候会发送一个错误的message,如果在关闭前发送了一个message。RST将会刷掉错误message,从而导致链接失败而没错误信息。触发有两个条件

  • 请求为PUT 和 POST的时候(这个时候数据量大,容易导致message包延后)
  • 在多个请求的时候,一个导致错误,其他导致关闭连接。

解决方案是,不写了,读还是要读的。把message读出来。如果设置了SO_LINGER(继续发送)。

猜想maxSwallowSize的目的是,如果数据量太大,那么也只读这么多数据。然后抛出异常

  1. 这个参数也会影响keepAlive 的打开和关闭。
private void checkMaxSwallowSize() {// Parse content-length headerlong contentLength = -1;try {contentLength = request.getContentLengthLong();} catch (Exception e) {// Ignore, an error here is already processed in prepareRequest// but is done again since the content length is still -1}if (contentLength > 0 &&(contentLength - request.getBytesRead() > protocol.getMaxSwallowSize())) {// There is more data to swallow than Tomcat will accept so the// connection is going to be closed. Disable keep-alive which will// trigger adding the "Connection: close" header if not already// present.keepAlive = false;}}

这里限制了长连接的长度,如果长连接在我们这里的长度太长,会将长连接置为关闭状态。

redirectContextRoot

如果没Path 是否从定向到 ‘/’ 默认为true

if(mappingData.wrapper == null && noServletPath &&contextVersion.object.getMapperContextRootRedirectEnabled()) {// The path is empty, redirect to "/"path.append('/');pathEnd = path.getEnd();mappingData.redirectPath.setChars(path.getBuffer(), pathOffset, pathEnd - pathOffset);path.setEnd(pathEnd - 1);return;}

useRelativeRedirects

重定向是否用相对路径,默认为true

if (getRequest().getCoyoteRequest().getSupportsRelativeRedirects() &&getContext().getUseRelativeRedirects()) {locationUri = location;} else {locationUri = toAbsolute(location);}

uriEncoding

连接编码,默认为UTF-8

maxConnections

最大连接数,默认为8192

限制连接的实现类为 org.apache.tomcat.util.threads.LimitLatch

实现原理为AQS,主要方法为

  • countUpOrAwait 如果满了就进入阻塞,如果没满就+1
  • countDown 当前连接减一

acceptCount

backlog的数量,最大Pending连接的数量。也就是连接用的数量.默认为100

serverSock.bind(addr, getAcceptCount());

processorCache

最大processorCache的数量,默认为200,理论上来说最大的Cache是maxConnections。他也和MaxThread相关。

相关的类是org.apache.coyote.AbstractProtocol.RecycledProcessors

@Override
public boolean push(Processor processor) {int cacheSize = handler.getProtocol().getProcessorCache();boolean offer = cacheSize == -1 ? true : size.get() < cacheSize;//avoid over growing our cache or add after we have stoppedboolean result = false;if (offer) {result = super.push(processor);if (result) {size.incrementAndGet();}}if (!result) handler.unregister(processor);return result;
}

这个值控制着org.apache.tomcat.util.collections.SynchronizedStack同步栈的大小。

  • 如果关闭链接的时候,就回收Processor.链接大于这个值的时候就会丢弃
  • 如果新增链接的时候,先从这里取链接,如果取完了,那就直接创建

当请求频繁的时候,这个值可以设置为最大线程数,如果请求只有一小部分时间巅峰。可以调小这个值,如果最大线程数大于这个值,不调整这个值也不会收到影响。

additionalTldSkipPatterns

限制tomcat加载jar,通常对Class做了特殊处理的时候会用到,比如(加密等)

代码在 org.apache.tomcat.util.scan.StandardJarScanner#scan

relaxedPathChars

允许的特殊字符,在路径中包含特殊字符的时候。请求会失败。调整这个值可以兼容

org.apache.tomcat.util.http.parser.HttpParser类中会存IS_NOT_REQUEST_TARGET,IS_ABSOLUTEPATH_RELAXED,IS_QUERY_RELAXED 三个128字符的数组,对应128个码,

特殊字符解析的时候会报错,如果relaxedPathChars排除了这个,就不会报错

relaxedQueryChars

同上

connectionTimeout

链接超时时间,

 // Set back socket to blocking modeSocket.timeoutSet(data.socket, getConnectionTimeout() * 1000);

resource

静态资源配置

主要是缓存的时间

Mbeanregistry

Mbean的配置

Remoteip

和ForwardHeadersStrategy 相关,都是请求头参数

SpringBoot中Web容器配置和调优相关推荐

  1. Springboot内置Tomcat配置参数调优

    Springboot内置Tomcat配置参数调优,首先,线程数是一个重点,每一次HTTP请求到达Web服务器,Web服务器都会创建一个线程来处理该请求,该参数决定了应用服务同时可以处理多少个HTTP请 ...

  2. Docker中应用的性能调优指南(一)- 先谈谈容器化性能调优

    摘要: 前言 性能调优是一个老生常谈的话题,通常情况下,一个应用在上线之前会进行容量规划.压力测试并进行验证,而性能调优则是在容量规划与验证结果之间出现差异时会进行的必然手段.从某种角度来讲,性能调优 ...

  3. Servlet容器中web.xml配置context-param与init-param

    Servlet容器中web.xml配置<context-param>与<init-param>的区别与作用 <context-param>的作用: web.xml的 ...

  4. Nginx安装/负载均衡/反向代理配置与调优

    [Nginx安装] Linux下直接使用包管理安装 sudo apt-get install nginx 使用whereis命令查看安装位置 whereis nginx #sbin下代表nginx可执 ...

  5. php+php-fom+nginx配置参数调优详解

    文章目录 一.前言 1.mysql配置参数: 2.注意 二.php参数配置及讲解 1.phpini的基本设置 2.php参数设置 三.php-fpm设置 1.设置子进程数,增加并发量 2.防止频繁出现 ...

  6. 在RedHat Enterprise Linux 上Oracle 9i的安装配置与调优

    1 安装配置Oracle 9i数据库 本章描述内容如下所示: 1.1 安装前的准备工作 介绍在安装Oracle之前所需的准备工作. 1.2安装前的系统设置 介绍在安装Oracle之前所必须的系统设置. ...

  7. springboot 中 mybatis configuration 配置失效问题

    springboot 中 mybatis configuration 配置失效问题 环境 场景 springboot角度分析 SqlSessionFactory 设置Configuration Myb ...

  8. springboot中druid数据源配置无效的问题和jar包找不到问题

    springboot中druid数据源配置无效的问题 阿里云的仓库 链接: 阿里云仓库. 自己在springboot项目中,引入druid的依赖,希望引入druid数据源. 但是idea中,虽然在这个 ...

  9. SpringBoot中Logback常用配置以及自定义输出到MySql数据库

    之前基于SpringBoot开发的项目运行一段时间后,客户使用网站偶尔会出现接口调用失败的情况,每次产品经理询问是怎么回事的时候,都需要让运维提下最近的日志才能分析具体原因,这样时效性和便利性不能满足 ...

最新文章

  1. signature=680da11b802226668317d65ae7c38eb7,encryption with designated verifiers
  2. 区块链以太坊五大开发工具,你喜欢哪个?
  3. linux(6/17)--文件打包上传和下载
  4. nbns协议_网络协议详解1 - NBNS
  5. 节能原理 (能量平衡)
  6. HandlerThread
  7. Windows平台下kafka环境的搭建
  8. 记录一个JS异常Uncaught NotFoundError
  9. 10行代码让你轻松搞定对象检测
  10. iPhone 12 mini大幅砍单 苹果可能又要因为屏幕而向三星支付违约金
  11. Ajax datatype:'JSON'的error问题Status1:200,JSON格式
  12. -创建日期和时间数组--提取年月日-显示格式
  13. TCP之keepalive
  14. IntelliJ IDEA创建和配置Maven项目并运行
  15. 四级英语测试软件,英语四级必备软件推荐
  16. 【Tomcat】修改密码
  17. linux sd卡修复工具,免费的SD卡数据恢复工具介绍
  18. Ffmpeg 视频教程 向视频中添加文字
  19. win10照片文件夹里面图片,突然不显示缩略图
  20. 实现Excel里每个sheet的排序并整合在一个sheet里

热门文章

  1. Laravel4.1数据库 数据库填充(六)
  2. OpenCV自适应直方图均衡CLAHE图像和分块大小不能整除的处理
  3. ChipGAN: A Generative Adversarial Network for Chinese Ink Wash Painting Style Transfer翻译
  4. oozie action shell 实战(完整配置文件)
  5. Mybatis—动态SQL语句与逆向工程
  6. c语言vsprintf函数,vsprintf函数
  7. 一文带你入门机器学习中的树模型(附源码)
  8. 网络优化之net.ipv4.tcp_tw_recycle参数
  9. Linux命令行与shell脚本编程大全(shell脚本编程基础部分)
  10. 208核、6TB内存!阿里云发布全球最强云服务器:挑战摩尔定律极限