tomcat?集群监控与弹性伸缩详解

 更新时间:2022年09月09日 08:37:07   作者:随风21  
这篇文章主要为大家介绍了tomcat?集群监控与弹性伸缩详解,
(福利推荐:【腾讯云】服务器最新限时优惠活动,云服务器1核2G仅99元/年、2核4G仅768元/3年,立即抢购>>>:9i0i.cn/qcloud

(福利推荐:你还在原价购买阿里云服务器?现在阿里云0.8折限时抢购活动来啦!4核8G企业云服务器仅2998元/3年,立即抢购>>>:9i0i.cn/aliyun

如何给 tomcat 配置合适的线程池

任务分为 CPU 密集型和 IO 密集型

对于 CPU 密集型的应用来说,需要大量 CPU 计算速度很快,线程池如果过多,则保存和切换上下文开销过高反而会影响性能,可以适当将线程数量调小一些

对于 IO 密集型应用来说常见于普通的业务系统,比如会去查询 mysql、redis 等然后在内存中做简单的数据组装和逻辑判断,此时由于有 epoll、dma 等支持,消耗较长时间的线程不会长时间占据 CPU 时间,所以可以适当将线程数量调大一些

对于线程数到底该设置多大,网上有很多的方案

我们在实际情况中基于 wrk 等压测工具进行压测,压测逻辑相对复杂请求量相对较高的接口先配置一个相对保守的值

先预估假设当前接口处理平均耗时 300MS,1S 一个线程平均处理 3 个请求,最大 100 个线程 1S 能处理 300 TPS

粗略估算每个请求会消耗多大的内容空间,假如是 2KB,那么每秒会消耗 600KB 以此来估算 YGC 多久会触发一次,假设年轻代为 1GB 那么大约 29 分钟触发一次 YGC

然后再看 100 个线程持续处理 300TPS 的时候 CPU 消耗情况

观察内存几分钟 GC 一次,或者 CPU 使用率稳定在 50% 左右就好,假设此时线程池 70 个线程都在运作

那么监控系统采集到线程池线程使用率达到了 80% 就开始扩容,因为扩容拉起新的服务器到提供服务可能也需要1-2分钟的时间,所以需要预留服务器资源能够处理弹性扩容期间的流量

实际场景中是相对比较复杂的,前期最好设置一个相对保守的扩容阈值,如果发现在达到这个阈值前服务器已经顶不住了就可以实时的缩小阈值

同时还可以根据在达到扩容阈值扩容的时候,观察线上真实的 CPU 和内存使用情况,可以基于 promethues + grafana 来进行监控,如果发现扩容时候 CPU 使用率和内存使用率 GC 评率比较低,那么可以再配置中心动态的调整线程池的大小

所以说与其寻找一个准确的计算线程池数量的配置方式,不如提供一个可以动态调整的线程池作为 tomcat 的线程池

如何监控 tomcat 线程池的工作情况

spring boot 在启动过程中会调用 TomcatProtocolHandlerCustomizer 的实现类,此处可以自定化 tomcat 线程池,也可以获取到 tomcat 线程池

public class MyTomcatProtocolHandlerCustomizer implements TomcatProtocolHandlerCustomizer<ProtocolHandler> {
    private final ThreadPoolExecutor tomcatThreadPoolExecutor;
    public TomcatProtocolHandlerCustomizer(ThreadPoolExecutor tomcatThreadPoolExecutor) {
        this.tomcatThreadPoolExecutor = tomcatThreadPoolExecutor;
    }
    @Override
    public void customize(ProtocolHandler protocolHandler) {
        protocolHandler.setExecutor(tomcatThreadPoolExecutor);
    }
    public ThreadPoolExecutor getThreadPoolExecutor() {
        return tomcatThreadPoolExecutor;
    }
}

然后将线程池装入一个容器 bean 中注册到 promethues 监控中,当每秒进行采集的时候通过回调的方法去获取线程池的最新指标

promethues 每秒采集一次容器的线程池运行指标、服务器测 CPU 使用率当满足定义的扩容阈值时就拉起新的 POD

grafana 每秒采集一次 promethues 的数据汇聚图标展示

@Bean
public AllServersThreadPoolCollector allServersThreadPoolCollector(@Qualifier(value = "GrpcThreadPoolExecutor") ThreadPoolExecutor GrpcThreadPoolExecutor,
                                                                   @Qualifier(value = "jdTomcatThreadPoolExecutor") org.apache.tomcat.util.threads.ThreadPoolExecutor TomcatThreadPoolExecutor,
                                                                   MeterRegistry registry) {
    return new AllServersThreadPoolCollector(GrpcThreadPoolExecutor, jdTomcatThreadPoolExecutor, registry);
}
public void init() {
    try {
        createGauge(this, "grpc_tomcat_core_pool_size", pool -&gt; this.getCorePoolSize());
        createGauge(this, "grpc_tomcat_maximum_pool_size", pool -&gt; this.getMaximumPoolSize());
        createGauge(this, "grpc_tomcat_busy_pool_size", pool -&gt; this.getActiveCount());
        createGauge(this, "grpc_tomcat_wait_queue_size", pool -&gt; this.getWaitQueueSize());
    } catch (Exception e) {
        log.error("注册 all servers 监控失败", e);
    }
}
private void createGauge(AllServersThreadPoolCollector weakRef, String metric, ToDoubleFunction&lt;AllServersThreadPoolCollector&gt; measure) {
    Gauge.builder(metric, weakRef, measure)
            .register(this.registry);
}
public int getWaitQueueSize() {
    return grpcThreadPoolExecutor.getQueue().size() + tomcatThreadPoolExecutor.getQueue().size();
}

tomcat 线程池扩缩容

Java 线程池是支持直接修改 corePoolSize、maximumPoolSize 的

  • 修改 corePoolSize

(1)数量小于 maximumPoolSize 抛异常

(2)如果 corePoolSize - 原来的 = delta,delta 大于 0 那么创建等待队列任务数量和 delta 个线程来处理等待处理的任务

(3)如果正在运行的线程数量 > corePoolSize 那么就中断多余的线程

  • 修改 maximumPoolSize

(1)maximumPoolSize 小于 corePoolSize 抛错

(2)如果运行的线程大于 maximumPoolSize 中断掉一些空闲的线程

基于这些机制就能在运行期间动态调整线程池内容

无需担心会中断掉正在运行的任务,因为线程池 worker 线程每执行一个任务的时候

tomcat 是如何避免原生线程池的缺陷的

原生线程池的工作原理

(1)运行的线程数小于核心线程,就创建一个 worker 线程去执行任务

(2)运行的线程数 >= 核心线程了,将任务全部积压到队列中

(3)队列如果满了继续创建非核心线程 worker 去执行任务

假如 tomcat 采用了原生线程池,核心线程为 10 个,最大线程为 100,队列为 200,并发来了 100 个请求,那么同时系统只能处理 10 个,剩下 90 个都得放入队列中让 10 个核心线程慢慢排队处理,延时必然非常高

tomcat 如何优化线程池,核心在于阻塞队列的实现,因为阻塞队列满了才会继续创建非核心 worker 线程处理任务

(1)运行的线程数小于核心线程,就创建一个 worker 线程去执行任务

(2)当前已经创建的核心+非核心线程数等于最大线程数,任务压入队列

(3)正在处理的请求数量小于核心+非核心线程数,任务压入队列

(4)当前已经创建的核心+非核心线程数小于最大线程数,创建 worker 线程处理请求

总结就是一句话当高并发流量过来的时候,会去创建最大线程数的 worker 去处理请求用以降低尾延迟,超过最大线程后,任务将被压入队列中进行处理

以上就是tomcat 集群监控与弹性伸缩详解的详细内容,更多关于tomcat 集群监控弹性伸缩的资料请关注程序员之家其它相关文章!

相关文章

  • idea专业版和idea社区版整合Tomcat并将war包部署

    idea专业版和idea社区版整合Tomcat并将war包部署

    IDEA是一个功能完善的Java开发工具,除了具备有良好的代码开发提示之外,还可以直接在IDEA中集成并启动Tomcat实现程序的自动部署,本文主要介绍了idea专业版和idea社区版整合Tomcat并将war包部署,感兴趣的可以了解一下
    2023-11-11
  • 详解Tomcat多域名配置(多个项目共用80端口)

    详解Tomcat多域名配置(多个项目共用80端口)

    本篇文章主要介绍了Tomcat多域名配置(多个项目共用80端口),具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-06-06
  • Tomcat使用线程池处理远程并发请求的方法

    Tomcat使用线程池处理远程并发请求的方法

    这篇文章主要介绍了Tomcat使用线程池处理远程并发请求的方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-12-12
  • Tomcat的类加载机制流程及源码解析

    Tomcat的类加载机制流程及源码解析

    我们知道,ava默认的类加载机制是通过双亲委派模型来实现的,而Tomcat实现的方式又和双亲委派模型有所区别,下面这篇文章主要给大家介绍了关于Tomcat类加载机制流程的相关资料,需要的朋友可以参考下
    2021-11-11
  • 浅析Tomcat各种日志的关系与catalina.out文件的分割问题

    浅析Tomcat各种日志的关系与catalina.out文件的分割问题

    这篇文章主要介绍了Tomcat各种日志的关系与catalina.out文件的分割,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-10-10
  • Tomcat源码导入idea的方法

    Tomcat源码导入idea的方法

    这篇文章主要介绍了Tomcat源码导入idea的方法,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-09-09
  • Tomcat管理平台_动力节点Java学院整理

    Tomcat管理平台_动力节点Java学院整理

    这篇文章主要为大家详细介绍了Tomcat管理平台的相关资料,讲解Tomcat服务器的管理平台具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-07-07
  • Tomcat部署项目的几种常见方式[亲测]

    Tomcat部署项目的几种常见方式[亲测]

    这篇文章主要介绍了Tomcat部署项目的几种常见方式,文中给大家提到了三种方法,除此之外还有Tomcat热部署的方式 ,感兴趣的朋友跟随小编一起看看吧
    2018-11-11
  • tomcat配置虚拟路径的实现步骤

    tomcat配置虚拟路径的实现步骤

    本文主要介绍了tomcat配置虚拟路径的实现步骤,主要是在localhost文件中进行配置,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-05-05
  • Idea部署tomcat服务实现过程图解

    Idea部署tomcat服务实现过程图解

    这篇文章主要介绍了Idea部署tomcat服务实现过程图解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-08-08

最新评论

?


http://www.vxiaotou.com