实战 | 生产环境中如何动态调整线程池大小?

开发 前端
在某些情况下,应用程序可能会突然接收到大量的请求,这被称为突发流量。如果线程池大小固定且不足以处理这种突发流量,那么应用程序的性能可能会受到严重影响。通过动态调整线程池大小,可以快速地增加线程数量以应对这种突发流量,从而保持应用程序的稳定性和性能。

环境:JDK17 + Nacos2.1.0

1. 简介

本文旨在探讨如何结合Nacos作为动态配置中心,实现在线动态修改线程池大小的功能。将线程池大小的配置信息动态地传递给应用程序。此外,我们还将讨论如何在应用程序中监听配置变化,并根据新的配置信息动态地调整线程池的大小。通过这种方式,我们可以提高系统的灵活性和可扩展性,更好地适应业务需求的变化。

2. 实战案例

我们不会在SpringBoot项目中去使用,只是通过普通的maven项目进行演示。

2.1 依赖管理

<properties>
  <nacos.version>2.1.2</nacos.version>
  <yaml.version>1.33</yaml.version>
  <java.version>17</java.version>
</properties>
<dependency>
  <groupId>com.alibaba.nacos</groupId>
  <artifactId>nacos-client</artifactId>
  <version>${nacos.version}</version>
  <!-- 指定纯净版SDK -->
  <classifier>pure</classifier>
</dependency>
<dependency>
  <groupId>com.alibaba.nacos</groupId>
  <artifactId>nacos-common</artifactId>
  <version>${nacos.version}</version>
</dependency>
<dependency>
  <groupId>com.alibaba.nacos</groupId>
  <artifactId>nacos-api</artifactId>
  <version>${nacos.version}</version>
</dependency>
<dependency>
  <groupId>org.yaml</groupId>
  <artifactId>snakeyaml</artifactId>
  <version>${yaml.version}</version>
</dependency>

2.2 Nacos中初始配置

在Nacos中进行线程池(核心数,最大数)初始配置

图片图片

2.3 自定义Nacos监听器

编写Nacos配置发生变化的监听器,该监听器的作用就是用来修改线程池的核心线程池数及最大线程数。

public class NacosConfigListener {


  public void start() throws Exception {
    String serverAddr = "localhost:8848";
    String dataId = "dy-thread.yaml";
    String group = "dy";
    Properties properties = new Properties();
    properties.put("serverAddr", serverAddr);
    properties.put("username", "nacos") ;
    properties.put("password", "nacos") ;
    ConfigService configService = NacosFactory.createConfigService(properties);
    String content = configService.getConfig(dataId, group, 5000);
    System.out.println("初始配置:\n" + content) ;
    Yaml yaml = new Yaml() ;
    configService.addListener(dataId, group, new Listener() {
      public void receiveConfigInfo(String configInfo) {
        try {
          LinkedHashMap<String, Object> content = (LinkedHashMap<String, Object>) yaml.load(configInfo) ;
          System.out.println("监听线程池修改:" + content) ;
          // 当内容发生变化后,修改线程池的配置信息
          LinkedHashMap<String, Object> dy = (LinkedHashMap<String, Object>) content.get("dy") ;
          Integer coreSize = (Integer) dy.get("coreSize") ;
          Integer maximumPoolSize = (Integer) dy.get("maximumPoolSize") ;
          DynamicThreadPoolConfig.pool.setMaximumPoolSize(maximumPoolSize) ;
          DynamicThreadPoolConfig.pool.setCorePoolSize(coreSize) ;
        } catch (Exception e) {
          e.printStackTrace() ;
        }
      }
      @Override
      public Executor getExecutor() {
        return null ;
      }
    });
  }


}

2.4 线程池使用

这里简单模拟使用线程池执行任务。

public class DynamicThreadPoolConfig {


  public static final ThreadPoolExecutor pool = new ThreadPoolExecutor(2, 3, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(100)) ;


  public static void main(String[] args) throws Exception {


    // 启动监听器
    new NacosConfigListener().start() ;


    var schedule = new ScheduledThreadPoolExecutor(1) ;
    // 以固定的周期打印线程池线程信息
    schedule.scheduleAtFixedRate(() -> {
      System.out.println( 
          "核心线程数: " + pool.getCorePoolSize() 
        + ", 最大线程数: " + pool.getMaximumPoolSize() 
        + ", 当前活动任务数: " + pool.getActiveCount()
      ) ;
    }, 0, 3, TimeUnit.SECONDS) ;


    // 动态添加任务
    for (var i = 0; i < 100; i++) {
      pool.execute(() -> {
        try {
          System.out.println(Thread.currentThread().getName()) ;
          TimeUnit.SECONDS.sleep(10) ;
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }) ;
    } 
  }
}

2.5 测试

直接运行程序,控制台如下输出

图片图片

输出的都是默认值。接下来,通过nacos界面修改线程池大小

图片图片

控制台输出

图片图片

程序正确的监听到了配置发生了变化,同时修改了线程池的大小。

总结:

在实际生产环境下,动态修改线程池大小具有重要意义。以下是一些主要的原因:

  1. 适应负载变化:应用程序的负载可能会随着时间、用户数量、数据量等因素的变化而变化。如果线程池大小固定,那么在负载增加时可能会出现线程资源不足的情况,导致性能下降或响应延迟。反之,如果负载降低,过多的线程可能会导致资源浪费。因此,动态调整线程池大小可以根据当前的负载情况来优化资源使用。
  2. 应对突发流量:在某些情况下,应用程序可能会突然接收到大量的请求,这被称为突发流量。如果线程池大小固定且不足以处理这种突发流量,那么应用程序的性能可能会受到严重影响。通过动态调整线程池大小,可以快速地增加线程数量以应对这种突发流量,从而保持应用程序的稳定性和性能。
  3. 提高系统灵活性:在生产环境中,应用程序的需求和负载可能会随着业务的发展而不断变化。如果线程池大小固定,那么可能需要频繁地重启应用程序或修改配置来适应这些变化。而通过动态调整线程池大小,可以在不重启应用程序的情况下,根据实际需求来灵活地调整线程资源,从而提高系统的灵活性。

总之,动态修改线程池大小可以帮助应用程序更好地适应负载变化、应对突发流量,并提高系统的灵活性和可扩展性。这对于保持应用程序的稳定性和性能,以及满足不断变化的业务需求具有重要意义。


责任编辑:武晓燕 来源: Spring全家桶实战案例源码
相关推荐

2019-09-09 09:50:27

设置Java线程池

2010-03-18 15:15:08

Java线程池

2019-07-15 16:10:00

技术研发指标

2010-01-27 14:39:58

Android图片大小

2022-03-14 08:02:08

轻量级动态线程池

2020-10-22 16:48:30

LinuxLVM逻辑卷调整

2023-04-19 13:18:41

动态线程池平台

2022-08-29 09:06:43

hippo4j动态线程池

2023-01-11 08:09:25

Springboot修改日志级别

2010-09-08 15:19:46

生产环境性能测试风险

2011-03-11 14:07:51

Ubuntu 11.0

2021-07-31 22:20:00

线程池系统参数

2022-02-14 16:08:15

开源项目线程池动态可监控

2010-02-05 18:21:24

Android应用程序

2021-09-23 15:55:50

线程池语言公式

2020-03-05 15:34:16

线程池C语言局域网

2022-05-26 09:00:00

网站抓取Lightrun开发

2013-06-25 09:56:55

vSphereVM

2021-02-20 09:27:36

Python编程语言机器学习

2016-08-18 13:56:33

AndroidExecutorsubmit
点赞
收藏

51CTO技术栈公众号