大家好,我是树哥!

对于提供接口服务的应用来说,很多都是用 SpringBoot 默认的 Servlet 容器 Tomcat。在一开始上线的时候,由于大多数流量较小,我们也并不会为 Tomcat 做专门的参数调整。但随着流量越来越大,应用的各项性能指标越来越差,此时我们大多数都会选择扩容。

除了扩容之外,我们还可以选择对 Tomcat 进行性能调优,从而在不增加成本的情况下提升性能。如果面试官问你,流量突增你们一般怎么做,你只会答扩容可就太差劲了。

今天树哥就跟大家简单分享下,如何对 Tomcat 进行简单地性能调优,从而提升应用的性能!

组件架构

要对 Tomcat 进行性能调优,我们需要先了解其组件架构。Tomcat 的组件架构如下图所示:

Tomcat 组件结构示意图

从上图可以看到,Tomcat 将其业务抽象成了 Server、Service、Connector、Container 等等组件,每个组件都有不同的作用。

  • Server 组件。 Server 组件是 Tomcat 最外层的组件,该组件是 Tomcat 实例本身的抽象,代表着 Tomcat 自身。一个 Server 组件可以有一个或多个 Service 组件。

  • Service 组件。 Service 组件是 Tomcat 中一组提供服务、处理请求的组件,一个 Service 组件可以有多个 Connector 连接器和一个 Container,有多个 Connector 表示其可以同时使用多种协议接收用户请求。

  • Connector 组件。 Connector 负责处理客户端的连接,它提供各种服务协议支持,包括:BIO、NIO、AIO 等等。其存在的价值在于,为 Container 容器屏蔽了多协议的复杂性,统一了 Container 容器的处理标准。

  • Container 组件。 Container 组件是负责具体业务逻辑处理的容器,当 Connector 组件与客户端建立连接后,便会将请求转发给 Container 组件的 Engine 组件处理。

到这里,Tomcat 的核心组件基本上讲完了。实际上 Container 组件里还细分了很多组件,其实对业务的抽象,感兴趣的可以继续看看。

  • Engine 组件。 Engine 组件表示可运行的 Servlet 实例,包含了 Servlet 容器的核心功能,其可以有一个或多个虚拟主机(Host)。其主要功能是将请求委托给合适的虚拟主机处理,即根据 URL 路径的配置匹配到合适的虚拟主机处理。

  • Host 组件。 Host 组件负责运行多个应用,其负责安装这些应用,其主要作用是解析 web.xml 文件,并将其匹配到对应的 Context 组件。

  • Context 组件。 Context 组件代表具体的 Web 应用程序本身,其最重要的功能就是管理里面的 Servlet 实例。一个 Context 可以有一个或者多个 Servlet 实例。

  • Wrapper 组件。 一个 Wrapper 组件代表一个 Servlet,它负责管理一个 Servlet,包括 Servlet 的装载、初始化、执行以及资源回收。Wrapper 是最底层的容器。

可以看到,Host 是虚拟主机的抽象,Context 是应用程序的抽象,Wrapper 是 Servlet 的抽象,而 Engine 则是处理层的抽象。

核心参数

在了解核心参数之前,我们我们需要大致了解一下 Tomcat 对于请求的处理流程。Tomcat 对请求的处理流程如下所示:

  • 首先,客户端向 Tomcat 服务器发起请求,Connector 组件监听到请求,于是与客户端建立起连接。

  • 接着,Connector 将请求封装后转发给 Engine 组件处理。

  • 最后,Engine 组件处理完之后将结果返回给 Connector,Connector 组件再将结果返回给客户端。

上述过程可以用如下示意图来表示:

Tomcat 核心参数示意图

在上面的示意图中有三个非常关键的核心参数,这几个关键的参数也是性能调优的关键,它们分别是:

  1. acceptCount:当 Container 线程池达到最大数量且没有空闲线程,同时 Connector 队列达到最大数量时,操作系统最多能接受的连接数。

  2. maxConnections:当 Container 线程池达到最大数量且没有空闲线程时,Connector 的队列能接收的最大线程数。

  3. maxThreads:Container 线程池的处理线程的最大数量。

从上面三个参数的含义我们可以知道如下几点结论:

  1. 客户端并不是直接与 Tomcat 的 Connector 组件建立联系的,而是先与操作系统建立,然后再移交给 Connector 的。这点很重要,不然你就无法理解 acceptCount 这个参数。

  2. 不仅仅 Connector 组件中有队列,操作系统中也有队列来临时存储与客户端的连接,这也是很关键的点。

  3. 我们所说的线程池,指的是 Container 这个容器里的线程池。

明白这三个核心参数的含义是非常重要的,不然没有办法进行后续的性能调优工作。

maxThreads

我们知道 maxThreads 指的是请求处理线程的最大数量,在 Tomcat7 和 Tomcat8 中都是默认 200 个。

对于这个参数的设置,需要根据任务的执行内容去调整,一般来说计算公式为:最大线程数 = ((IO时间 + CPU时间)/CPU时间) * CPU 核数。这个公式的思路其实很简单,就是最大化利用 CPU 的资源。一个任务的耗时分为 IO 耗时和 CPU 耗时,基本上 IO 耗时是最多的,这时候 CPU 是没事干的。

因此如果可以让 CPU 在任务等待 IO 的时候处理其他任务,那么 CPU 利用率不就上来了么。一般来说,由于 IO 耗时远大于 CPU 耗时,因此根据公式计算出来的 maxThreads 数都会远大于 CPU 核数,这是很正常的。

要注意的是,这个数值也不是越高越好。因为一旦线程数太多了,CPU 需要进行上下文切换,这就消耗了一部分 CPU 资源。因此最好的办法是用上述公式去计算一个基准值,随后再进行压力测试,去调整到一个合理的值。

一般来说,如果调高了 maxThreads 的值,但是吞吐量没有提升或者下降的话,那么表明可能到达了了瓶颈了。

maxConnections

maxConnections 指的是当线程池的线程达到最大值,并且都在忙的时候,Connector 中的队列最多能容纳多少个连接。一般来说,我们都要设置一个合理的数值,不能让其无限制堆积。

因为 Tomcat 的处理能力肯定是有限的,到达一定程度肯定就处理不过来了,因此你堆积太多了也没啥用,反而会造成内存堆积,最终导致内存溢出 OOM 的发生。

一般来说,一个经验值是可以设置成为 maxThreads 同样的大小。 我想这样也是比较合理的,因为在队列中的连接最多只需要等待线程处理一个任务的时间即可,不会等待太久,响应时间也不会太长。

如果你想缩短响应时间,那么可以将 maxConnections 调低于 maxThreads 一些,这样可以降低一些响应时间。但要注意的是,如果降得太低的话,可能就会严重降低性能,降低吞吐量。

acceptCount

acceptCount 指的是当 Container 线程池达到最大数量且没有空闲线程,同时 Connector 队列达到最大数量时,操作系统最多能接受的连接数。

队列中的个数达到最大值后,进来的请求一律被拒绝,默认值是 100。这可以理解成是操作系统的一种自我保护机制吧,堆积太多无法处理,那就直接拒绝掉,保护自身资源。

这个参数的调优资料比较少,但根据其含义,这个值不建议比 maxConnections 大。 因为在这个队列中的连接,是需要等待的。如果数值太大,就说明会有很多连接没有被处理。

连接越多,那么其等待的时间就越长,其响应时间就越慢。如果你想响应时间短一些,或许应该调低一下这个值。

有同学会疑惑,为啥有了 maxConnections 了还要有 acceptCount 呢?这不是重复了么?其实在 BIO 的时代,这两个数值基本都是相同的。我猜是因为后面出现了 NIO、AIO 等技术,操作系统可以接受更多的客户端连接了。

于是就可以先让操作系统先建立连接缓存着,随后 Connnector 直接从操作系统处获取连接即可,这样就不需要等待操作系统进行耗时的 TCP 连接了,从而提高了效率。

除了上面这三个参数之外,还有几个非核心参数,但我觉得还是有些作用的。

  • connectionTimeout 参数, 表示建立连接后的等待超时时间,如果超过这个时间,那么就会直接返回超时。

  • minSpareThreads 参数, 表示最小存活线程数,也就是如果没有请求了,那么最低要保持几个线程存活。这个参数与是否有突发流程相关联,在有突发流量的情况下,如果这个数值太低,那么就会导致瞬时的响应时间比较长。

总结

今天我们分享了 Tomcat 的核心组件,接着讲解了 Tomcat 处理请求过程时的 3 个核心参数及其调优经验。

对于 maxThreads 参数而言,如果按照公式计算的话,我们需要获取 IO 时间和 CPU 时间,但实际上这两个值并不是很好获取。所以一般情况下,我们可以通过压测的方式来获得一个比较合适的 maxThreads。

对于 maxConnections 参数而言,可以设置一个与 maxThreads 相同的值,再根据具体情况进行调整。如果想降低响应时间,那么可以稍微调低一些,否则可以调高一些。

对于 acceptCount 参数而言,其调优逻辑与 maxConnections 类似,可以设置与 maxConnections 相似,再根据对相应时间的要求,做一个微调。

好了,这就是今天的分享了。

如果你喜欢这篇文章,请帮忙点赞转发支持我,感谢~

文章思维导图

参考资料

  • 优化指南,详解 Tomcat 的连接数与线程池 - 腾讯云开发者社区 - 腾讯云

  • Tomcat 性能优化,如何优化 tomcat 配置 (从内存、并发、缓存 4 个方面) 优化_你是我的天晴的博客 - CSDN 博客_tomcat 性能优化

  • 讲解得挺清楚的,不错!VIP!Tomcat 线程连接池参数优化_人工智的博客 - CSDN 博客_tomcat 连接池配置参数

  • Tomcat 生产服务器性能优化 - 心疼米饭

  • 性能优化实战,不错!VIP!干货收藏!史上最强 Tomcat 8 性能优化来啦!| 原力计划 - 知乎

  • 例子很形象,不错!VIP!RestTemplate 调优,Tomcat 优化,线程池优化思路. - 知乎

  • 官网对于参数的讲解!权威!VIP!Apache Tomcat 8 Configuration Reference (8.5.81) - The HTTP Connector

  • 案例挺多的,可以看看,查漏补缺!VIP!亿级流量网站性能优化的方法论步骤 - 掘金

  • Tomcat 如何处理一个 HTTP 请求。VIP!Tomcat 处理 HTTP 请求流程解析 - 掘金

  • 原理类。后续可以看看!Tomcat 架构原理解析到架构设计借鉴 - SegmentFault 思否

  • 组件结构不错!Tomcat 系列 (4)——Tomcat 组件及架构详细部分 - 海米傻傻 - 博客园


推荐阅读

  • MySQL 啥时候用表锁,啥时候用行锁?

  • 从全局角度,如何设计一个秒杀系统?

  • 系统总出故障怎么办,或许你该学学稳定性建设!

  • 服务器宕机了,Kafka 消息会丢失吗?

  • Java 内存模型,或许应该这么理解

  • 深入理解 Java 对象的内存布局

  • 深入理解 synchronized 的锁优化

  • 树哥的 JVM 小站上线了!真不错!

  • 深入理解 volatile 关键字

  • 深入理解 happens-before 原则

接口流量突增,如何做好性能优化?相关推荐

  1. 近期业务大量突增微服务性能优化总结-2.开发日志输出异常堆栈的过滤插件

    最近,业务增长的很迅猛,对于我们后台这块也是一个不小的挑战,这次遇到的核心业务接口的性能瓶颈,并不是单独的一个问题导致的,而是几个问题揉在一起:我们解决一个之后,发上线,之后发现还有另一个的性能瓶颈问 ...

  2. 线上流量突增百万高可用保障方案

    一:事前预防 1.预估系统瓶颈 1.1 梳理核心接口 按调用量梳理Top100 PM按业务重要等级梳理下端可能起量的接口 输出终版的接口文档 1.2 评估核心接口最高的TPS 测试环境模拟生产环境数据 ...

  3. T 沙龙移动实践日总结 ——享物说大流量⼩程序的架构与性能优化方案

    PPT 和 视频 视频地址 PPT地址 下面是 T 沙龙小编对分享的一些总结: 第一位分享嘉宾是来自享物说的 Rolland Safort(中文名:塞福),目前负责享物说小程序开发工作,有多年前端工作 ...

  4. 图片处理+高速计算机配置,PS越用越卡?4招做好性能优化,让你的电脑再战3年!...

    你是不是经常会遇到这样的问题?刚装的Ps速度很快,使用一段时间以后发现越来越卡,时不时还会死机崩溃? 大多数人遇到这种问题都是选择重装软件,或者重做系统,耗时耗力不说,过不了多久又会出现同样的问题,非 ...

  5. Linux系统换万兆卡流量1g,linux 系统万兆网卡 性能优化

    修改网卡参数前得先修改 sysctl -w net.ipv4.tcp_window_scaling=1 sysctl -p 再重启服务器后再修改那些参数才能起效,这就是为啥我们先前修改参数一直没用的原 ...

  6. 数据库性能优化—主从分离

    文章出自:阿里巴巴十亿级并发系统设计(2021版) 链接:https://pan.baidu.com/s/1lbqQhDWjdZe1CBU-6U4jhA 提取码:8888 上节课,我们用池化技术解决了 ...

  7. 那些不得不说的性能优化套路

    你有没有想过,为什么跨行转账要告诉你2小时内到账,而不是立即到账?为什么抖音那么多用户同时在使用,却很少出现崩溃的情况?电商网站是如何支撑住双十一全国人民买买买的? 性能优化对一个产品的重要性不言而喻 ...

  8. 【Java内存溢出排查】gc监测以及内存突增问题排查

    前情提要 文档:[Java内存溢出排查]测试环境服务器挂... 链接:http://note.youdao.com/noteshare?id=783e7ec89950f4167867ef3ef3347 ...

  9. 赠书:《Java性能优化实践》,众多业内大佬推荐阅读

    没有捷径可走的 Java 性能优化 多年来,用 Google 搜索 Java performance tuning,出现的三篇最热门文章之一是于 1997 年到 1998 年左右发表的文章,这篇文章在 ...

  10. 清除浏览器缓存之后为什么还是显示旧的html页面_H5缓存机制浅析-移动端Web加载性能优化...

    1 H5缓存机制介绍 H5,即HTML5,是新一代的HTML标准,加入很多新的特性.离线存储(也可称为缓存机制)是其中一个非常重要的特性.H5引入的离线存储,这意味着 web 应用可进行缓存,并可在没 ...

最新文章

  1. STM32添加项目所需要的工程文件
  2. android源码模块编译错误,Android 源码编译错误记录
  3. Java - 自己动手之在线书店(2)
  4. 小心多任务设计被滥用
  5. when is view bound to its corresponding controller instance
  6. 基于对象的JavaScript编程
  7. Ansible自动化运维笔记3(playbook)
  8. [Javascript] Functor Basic Intro
  9. Windows Server 2012 R2 WSUS-3:安装服务器角色
  10. Android自定义View【实战教程】4⃣️----BitmapShader详解及圆形、圆角、多边形实现
  11. 基于用户画像的在线健康社区用户流失预测研究
  12. 手机远程共享计算机文件,电脑如何共享文件到手机
  13. godaddy不支持java_godaddy主机被墙的解决方案
  14. 垃圾回收分类系统、垃圾回收高保真原型设计 、垃圾分类后台管理系统、垃圾回收分类平台、垃圾回收分类、智慧管理系统、订单管理、财务管理、系统管理、库存管理、设备管理、Axure原型、rp原型
  15. 在国内访问AWS与阿里云速度如何?
  16. 【汇编】32位操作系统进程为什么最大可以占用4G内存?
  17. python爬取B站视频弹幕分析并制作词云
  18. seetaface6 GPU版本windows编译
  19. 黑苹果10.10.3手动开启SSD的TIRM提高硬盘效率
  20. python手机摄像头投测距_python opencv单目测距 小孔成像原理

热门文章

  1. python爬取高清动图
  2. 怎么做网站XML地图讲解
  3. 什么是传统企业电商洪水围城下的诺亚方舟
  4. Ikbc F400使用说明书
  5. warp-transducer源码安装,warprnnt_pytorch生成
  6. echarts的legend显示不全_【报Bug】echarts图表的legend没有显示
  7. 苹果支付验单java
  8. php 中%3cspan%3e,vue实战(4)——网站统计之——友盟百度统计
  9. 一文读懂 Jmeter - 你以为Jmeter只能用来做压力测试?
  10. submit 和 button的区别