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

目录
  • 如何给 tomcat 配置合适的线程池
  • 如何监控 tomcat 线程池的工作情况
  • tomcat 线程池扩缩容
  • tomcat 是如何避免原生线程池的缺陷的

如何给 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 集群监控弹性伸缩的资料请关注我们其它相关文章!

(0)

相关推荐

  • Nginx+Tomcat负载均衡集群安装配置案例详解

    目录 前言 一.Nginx+Tomcat 二.配置Nginx服务器 三.部署Tomcat应用服务器 总结 前言 介绍Tomcat及Nginx+Tomcat负载均衡集群,Tomcat的应用场景,然后重点介绍Tomcat的安装配置.Nginx+Tomcat负载均衡集案列是应用于生产环境的一套可靠的Web站点解决方案. 一.Nginx+Tomcat 通常情况下,一个Tomcat站点由于可能出现单点故障及无法应付过多客户复杂多样的请求等问题,不能单独应用于生产环境下,所以我们需要一套更可靠的解决方案来完

  • 基于Docker部署Tomcat集群、 Nginx负载均衡的问题小结

    写在前面 看完Dokcer相关的书籍,正好有个项目要这样搞,所以自己练习一下. 当作一百世一样.这里的道理很明白:我思故我在,既然我存在,就不能装作不存在.无论如何,我要为自己负起责任.--王小波<三十而立> 结构图: 这里仅作为一种学习,一般这种负载的话,Nginx是放到主机侧的, JavaWeb(Tomcat)应用放到容器里. 效果 新建文件夹. D=uag;mkdir $D;cd $D;mkdir uag_nginx uag_tomcat8; ls uag_nginx uag_tomca

  • Nginx构建Tomcat集群的操作方法

    目录 一.准备服务器 二.配置上游服务器 三.负载均衡策略-轮训 四.负载均衡策略-加权轮训 nginx是一款自由的.开源的.高性能的HTTP服务器和反向代理服务器:同时也是一个IMAP.POP3.SMTP代理服务器:nginx可以作为一个HTTP服务器进行网站的发布处理,另外nginx可以作为反向代理进行负载均衡的实现. 一.准备服务器 准备1台Nginx服务器和3台Tomcat服务器,并修改3台服务器中Tomcat的默认访问页面,用数字标记页面所处的服务器. vim /usr/local/t

  • Nginx+Tomcat负载均衡集群的实现示例

    目录 引言 一.案例概述 二.环境部署 三.Nginx 主机安装 四.Tomcat 安装及配置 1. 安装 Tomcat 2. Tomcat 服务器1配置 3. Tomcat 服务器2配置 五.Nginx server 配置 六.验证结果 总结 引言 通常情况下,一个 Tomcat 站点由于可能出现单点故障以及无法应付过多客户复杂多样的请求等问题,不能单独应用于生产环境中,所以需要一套更可靠的解决方案来完善 Web 站点架构. 一.案例概述 Nginx 是一款非常优秀的 http 服务器软件,它

  • Nginx+tomcat负载均衡集群的实现方法

    实验环境如下 这里需要准备4台服务器(1台nginx.2台tomcat做负载.一台MySQL做数据存储) 准备软件包如下: 软件包地址连接: 链接: https://pan.baidu.com/s/1Zitt5gO5bDocV_8TgilvRw 提取码: ny1r nginx配置(172.16.1.54) 1.安装依赖包 yum -y install pcre-devel zlib-devel gcc gcc-c++ 2.创建nginx运行用户 useradd -M -s /sbin/nolog

  • 详解Tomcat集群如何同步会话

    Tocmat集群中最重要的交换信息就是会话消息,对某个tomcat实例某会话做的更改要同步到集群其他tomcat实例的该会话对象,这样才能保证集群所有实例的会话数据一致.在tribes组件的基础上完成这些工作就相当容易些,tribes是tomcat实现的一个通信框架. 如下图,tomcat实现会话同步的过程中大致会使用如下组件,现在假设中间的tomcat实例的会话改变了,它会通过会话管理器Manager将改变的动作消息封装成消息然后调用集群对象Cluster,通过Cluster将消息发送出去,同

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

    目录 如何给 tomcat 配置合适的线程池 如何监控 tomcat 线程池的工作情况 tomcat 线程池扩缩容 tomcat 是如何避免原生线程池的缺陷的 如何给 tomcat 配置合适的线程池 任务分为 CPU 密集型和 IO 密集型 对于 CPU 密集型的应用来说,需要大量 CPU 计算速度很快,线程池如果过多,则保存和切换上下文开销过高反而会影响性能,可以适当将线程数量调小一些 对于 IO 密集型应用来说常见于普通的业务系统,比如会去查询 mysql.redis 等然后在内存中做简单的

  • Docker Consul概述以及集群环境搭建步骤(图文详解)

    目录 一.Docker consul概述 二.基于 nginx 与 consul 构建自动发现即高可用的 Docker 服务架构 一.Docker consul概述 容器服务更新与发现:先发现再更新,发现的是后端节点上容器的变化(registrator),更新的是nginx配置文件(agent) registrator:是consul安插在docker容器里的眼线,用于监听监控节点上容器的变化(增加或减少,或者宕机),一旦有变化会把这些信息告诉并注册在consul server端(使用回调和协程

  • ceph集群RadosGW对象存储使用详解

    目录 什么是对象存储 ceph对象存储的构成 RadosGW存储池作用 RadosGW常用操作详解 操纵radosgw 需要先安装好python3环境,以及python的boto模块 python脚本编写 一个完整的ceph集群,可以提供块存储.文件系统和对象存储. 本节主要介绍对象存储RadosGw功能如何灵活的使用 集群背景: $ ceph -s cluster: id: f0a8789e-6d53-44fa-b76d-efa79bbebbcf health: HEALTH_OK servi

  • Kubernetes集群模拟删除k8s重装详解

    目录 一.系统环境 二.前言 三.重装Kubernetes集群 3.1 环境介绍 3.2 删除k8s所有节点(node) 3.3 kubeadm初始化 3.4 添加worker节点到k8s集群 3.5 安装calico 一.系统环境 服务器版本 docker软件版本 CPU架构 CentOS Linux release 7.4.1708 (Core) Docker version 20.10.12 x86_64 二.前言 当我们安装部署好一套Kubernetes集群,使用一段时间之后可能会有重新

  • kafka与storm集群环境的安装步骤详解

    前言 在开始之前,需要说明下,storm和kafka集群安装是没有必然联系的,我将这两个写在一起,是因为他们都是由zookeeper进行管理的,也都依赖于JDK的环境,为了不重复再写一遍配置,所以我将这两个写在一起.若只需一个,只需挑选自己选择的阅读即可.下面话不多说了,来一起看看详细的介绍吧. 这两者的依赖如下: Storm集群:JDK1.8 , Zookeeper3.4,Storm1.1.1: Kafa集群 : JDK1.8 ,Zookeeper3.4 ,Kafka2.12: 说明: Sto

  • Spark学习笔记 (二)Spark2.3 HA集群的分布式安装图文详解

    本文实例讲述了Spark2.3 HA集群的分布式安装.分享给大家供大家参考,具体如下: 一.下载Spark安装包 1.从官网下载 http://spark.apache.org/downloads.html 2.从微软的镜像站下载 http://mirrors.hust.edu.cn/apache/ 3.从清华的镜像站下载 https://mirrors.tuna.tsinghua.edu.cn/apache/ 二.安装基础 1.Java8安装成功 2.zookeeper安装成功 3.hadoo

  • 集群rpm安装MySQL步骤详解

    安装mysql数据库 a)下载mysql源安装包:wget http://dev.mysql.com/get/mysql57-community-release-el7-8.noarch.rpm b)安装mysql源:yum localinstall mysql57-community-release-el7-8.noarch.rpm 若结尾出现complete!,则说明MySQL源安装完成 c)检测是否安装完成:yum repolist enabled | grep "mysql.*-comm

  • LINUX中NGINX反向代理下的TOMCAT集群(详解)

    Nginx具有反向代理(注意和正向代理的区别)和负载均衡等特点. 这次Nginx安装在 192.168.1.108 这台linux 机器上.安装Nginx 先要装openssl库,gcc,PCRE,zlib库等. Tomcat 安装在192.168.1.168 和 192.168.1.178 这两台机器上.客户端通过访问192.168.1.108 反向代理访问到 192.168.1.168 和 192.168.1.178 里Tomcat 部署的工程内容. 1.Linux 下安装Nginx (机器

  • 详解Spring Cloud 断路器集群监控(Turbine)

    一. 简介 上一篇文章我们已经实现了对单个服务实例的监控,当然在实际应用中,单个实例的监控数据没有多大的价值,我们更需要的是一个集群系统的监控信息,这时我们就需要引入Turbine.Turbine能够汇集监控信息,并将聚合后的信息提供给Hystrix Dashboard来集中展示和监控. 二. 构建监控局和服务 2.1 整体结构与准备 本文的工程实现是基于上一篇文章的工程,通过引入Turbine来聚合service-ribbon服务的监控信息,并输出给Hystrix Dashboard来进行展示

随机推荐