Spring Cloud Alibaba - 利用Nacos实现高效动态线程池管理

news2025/1/19 3:20:40

文章目录

  • 引言
  • 概述
  • 什么是动态线程池
  • Nacos简介
  • 如何利用Nacos实现动态线程池管理
  • 应用场景
  • Code
    • 版本说明
    • POM
    • 配置文件
      • Nacos Config配置文件加载顺序
        • 1. bootstrap.yml的加载
        • 2. application.yml的加载
        • 注意事项
        • 示例
    • nacos配置
      • Data Id
      • Nacos中Data ID的命名格式解释
        • `${spring.application.name}`
        • `${spring.profile.active}`
        • `${spring.cloud.nacos.config.file-extension}`
        • 合并后的Data ID
        • 示例
    • Configuration & Change Callback
  • 测试
  • 小结

在这里插入图片描述


引言

Java线程池实现原理及其在美团业务中的实践

开源组件:Hippo4J 、 dynamic-tp


概述

随着现代应用程序的复杂性不断增加,动态线程池管理成为了构建可靠和高效系统的关键之一。而Nacos作为一个优秀的服务发现和配置中心,能够帮助我们实现动态线程池的灵活管理。

我们这里将介绍如何利用Nacos来实现高效的动态线程池管理,并探讨其在分布式系统中的应用。

什么是动态线程池

在软件开发中,线程池是一种管理和重用线程的机制,它能够有效地控制并发执行的线程数量,避免资源耗尽和性能下降。动态线程池则是在传统线程池的基础上,能够根据系统负载和资源需求动态调整线程数量的一种改进型线程池管理方式。


Nacos简介

Nacos是阿里巴巴开源的一款多功能的服务发现和配置中心,它提供了服务注册与发现、动态配置管理、服务路由等功能,被广泛应用于微服务架构中。其优势在于高可用、易扩展、支持多种注册中心和配置源等特性。


如何利用Nacos实现动态线程池管理

  1. 服务注册与发现:首先,将应用程序注册到Nacos服务注册中心,使其成为Nacos的服务实例。这样,我们就可以利用Nacos的服务发现功能来获取可用的服务实例列表。

  2. 动态配置管理:借助Nacos的动态配置管理功能,我们可以将线程池的配置信息存储在Nacos的配置中心中,例如线程池大小、核心线程数、最大线程数、线程存活时间等参数。

  3. 监听配置变更:通过监听Nacos配置中心的变更通知,当线程池配置发生改变时,我们可以及时感知并动态调整线程池的参数,从而实现线程池的动态管理。

  4. 实时监控与调整:结合Nacos的服务监控和告警功能,可以实现对线程池运行状态的实时监控,当发现异常或负载过高时,及时进行调整,保障系统的稳定性和性能。


应用场景

利用Nacos实现动态线程池管理适用于各种需要动态调整线程数量的场景,特别适用于:

  • 微服务架构下的服务调用和资源管理;
  • Web服务器、消息队列等高并发场景的应用;
  • 云计算环境下的资源弹性伸缩。

Code

在这里插入图片描述

版本说明

:: Spring Boot ::                             (v2.4.1)
spring-cloud-starter-alibaba-nacos-discovery   2021.1
spring-cloud-starter-alibaba-nacos-config      2021.1

POM

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <artifactId>boot2</artifactId>
        <groupId>com.artisan</groupId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <groupId>com.artisan</groupId>
    <artifactId>boot-threadpool-nacos</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>boot-threadpool-nacos</name>
    <description>boot-threadpool-nacos</description>
    <properties>
        <java.version>8</java.version>
    </properties>
    <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            <version>2021.1</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
            <version>2021.1</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-bootstrap -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bootstrap</artifactId>
            <version>3.1.8</version>
        </dependency>


    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>


配置文件

bootstrap.yml

server:
  port: 9090
  # 应用名称(会注册到Nacos上)
spring:
  application:
    name: artisan-service
  cloud:
    nacos:
      discovery:
        namespace: public
        server-addr: 127.0.0.1:8848
      config:
        server-addr: 127.0.0.1:8848
        file-extension: yml

application.yml

spring:
  profiles:
    active: dev

Nacos Config配置文件加载顺序

在使用Spring Boot结合Nacos作为配置中心时,配置文件的加载顺序是非常重要的。一般来说,Spring Boot应用会先加载bootstrap.yml(或bootstrap.properties),再加载application.yml(或application.properties)。下面我们来详细解释这个加载顺序。

1. bootstrap.yml的加载

当Spring Boot应用启动时,首先会加载bootstrap.yml(或bootstrap.properties)文件。这个文件通常用于一些系统级别的配置,例如日志系统的配置、应用的环境变量配置等。在使用Nacos作为配置中心时,可以在bootstrap.yml中配置Nacos的相关参数,如Nacos的服务地址、命名空间等。

2. application.yml的加载

接着,Spring Boot会加载application.yml(或application.properties)文件。这个文件包含了应用程序的业务逻辑相关的配置,如数据库连接信息、端口配置、服务注册信息等。

注意事项
  • 加载顺序优先级: 在Spring Boot中,bootstrap.yml的加载优先级高于application.yml。这意味着如果在bootstrap.yml中配置了某些参数,而在application.yml中也有相同的配置项,那么以bootstrap.yml中的配置为准。
  • Nacos配置优先级: 如果将Nacos作为配置中心,那么Nacos中的配置会覆盖本地配置文件(如bootstrap.yml、application.yml)中的配置。因此,建议将系统级别的配置放在bootstrap.yml中,并将业务逻辑相关的配置放在Nacos中,以便实现配置的分离管理和动态更新。
示例

下面是一个简单的示例,展示了bootstrap.yml和application.yml的配置内容:

# bootstrap.yml
spring:
  application:
    name: my-application
  cloud:
    nacos:
      config:
        server-addr: localhost:8848
        namespace: your-namespace
# application.yml
server:
  port: 8080

在这个示例中,bootstrap.yml中配置了Nacos的服务地址和命名空间,而application.yml中配置了应用程序的端口号。


nacos配置

在这里插入图片描述

在这里插入图片描述
我们目前只配置了两个参数,核心线程数量和最大线程数。

Data Id

Nacos中Data ID的命名格式解释

在Nacos中,Data ID是用来唯一标识配置信息的,而其命名格式一般遵循一定的规则,以便于系统的管理和查找。

${spring.application.name}-${spring.profile.active}.${spring.cloud.nacos.config.file-extension}就是一种常见的Data ID命名格式

${spring.application.name}

${spring.application.name}表示Spring Boot应用的名称,它是在application.propertiesapplication.yml中通过spring.application.name属性进行配置的。这个属性通常用来标识应用的名称,用于服务注册、日志输出等场景。

${spring.profile.active}

${spring.profile.active}表示Spring Boot应用当前的Profile,它是通过spring.profiles.active属性进行配置的。Profile用于区分不同环境下的配置信息,例如devtestprod等,可以根据实际情况进行配置。

${spring.cloud.nacos.config.file-extension}

${spring.cloud.nacos.config.file-extension}表示配置文件的扩展名,它是通过spring.cloud.nacos.config.file-extension属性进行配置的。在Nacos中,配置信息可以是properties格式或yaml格式的文件,通过指定扩展名来区分不同类型的配置文件,如.properties.yaml

合并后的Data ID

将上述三部分内容按照规定的格式进行合并,就得到了Nacos中Data ID的命名格式:${spring.application.name}-${spring.profile.active}.${spring.cloud.nacos.config.file-extension}。这个命名格式能够唯一标识一个配置文件,并且包含了应用名称、Profile和配置文件类型等信息,方便系统根据需要进行查找和加载。

示例

假设我们有一个名为my-application的Spring Boot应用,当前处于dev环境,并且使用properties格式的配置文件,那么对应的Data ID就是:my-application-dev.properties

那我们这里的就是 artisan-service-dev.yml

在这里插入图片描述


Configuration & Change Callback

package com.artisan.bootthreadpoolnacos.config;

import com.alibaba.cloud.nacos.NacosConfigManager;
import com.alibaba.cloud.nacos.NacosConfigProperties;
import com.alibaba.nacos.api.config.listener.Listener;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Configuration;

import java.util.concurrent.*;

/**
 * @author 小工匠
 * @version 1.0
 * @mark: show me the code , change the world
 */
@RefreshScope
@Configuration
@Slf4j
public class DynamicThreadPoolConfig implements InitializingBean {

    @Value("${core.size}")
    private String coreSize;

    @Value("${max.size}")
    private String maxSize;

    private static ThreadPoolExecutor threadPoolExecutor;

    @Autowired
    private NacosConfigManager nacosConfigManager;

    @Autowired
    private NacosConfigProperties nacosConfigProperties;

    @Override
    public void afterPropertiesSet() throws Exception {
        //按照nacos配置初始化线程池
        threadPoolExecutor = new ThreadPoolExecutor(Integer.parseInt(coreSize), Integer.parseInt(maxSize), 10L, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(10),
                new ThreadFactoryBuilder().setNameFormat("c_t_%d").build(),
                new RejectedExecutionHandler() {
                    @Override
                    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                        log.info("Warn Warn Warn : rejected executed!!!");
                    }
                });

        //nacos配置变更监听
        nacosConfigManager.getConfigService().addListener("order-service-dev.yml", nacosConfigProperties.getGroup(),
                new Listener() {
                    @Override
                    public Executor getExecutor() {
                        return null;
                    }

                    @Override
                    public void receiveConfigInfo(String configInfo) {
                        //配置变更,修改线程池配置
                        log.info("收到Nacos Config Server推来的配置变更,修改线程池配置", configInfo);
                        changeThreadPoolConfig(Integer.parseInt(coreSize), Integer.parseInt(maxSize));
                    }
                });
    }

    /**
     * 打印当前线程池的状态
     */
    public String printThreadPoolStatus() {
        return String.format("core_size:%s,thread_current_size:%s;" +
                        "thread_max_size:%s;queue_current_size:%s,total_task_count:%s", threadPoolExecutor.getCorePoolSize(),
                threadPoolExecutor.getActiveCount(), threadPoolExecutor.getMaximumPoolSize(), threadPoolExecutor.getQueue().size(),
                threadPoolExecutor.getTaskCount());
    }

    /**
     * 给线程池增加任务
     *
     * @param count
     */
    public void dynamicThreadPoolAddTask(int count) {
        for (int i = 0; i < count; i++) {
            int finalI = i;
            threadPoolExecutor.execute(() -> {
                try {
                    log.info("dynamicThreadPoolAddTask->", finalI);
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }
    }

    /**
     * 修改线程池核心参数
     *
     * @param coreSize
     * @param maxSize
     */
    private void changeThreadPoolConfig(int coreSize, int maxSize) {
        threadPoolExecutor.setCorePoolSize(coreSize);
        threadPoolExecutor.setMaximumPoolSize(maxSize);
    }
}
    

动态线程池的配置类,主要功能包括根据Nacos配置动态调整线程池的核心参数,并监听Nacos配置的变化。

  • @RefreshScope是Spring Cloud中的一个注解,用于实现配置信息的热更新。当使用Nacos作为配置中心时,结合@RefreshScope注解可以实现配置信息的动态刷新,即在配置信息发生变化时,应用程序可以动态地重新加载最新的配置信息,而不需要重启应用。 在上述代码中,@RefreshScope注解被用于配置类DynamicThreadPoolConfig上。这意味着当Nacos中的配置信息发生变化时,Spring容器会自动检测到变化,并重新创建被@RefreshScope注解修饰的Bean,以便应用程序能够获取到最新的配置信息。 通过结合@RefreshScope注解和Nacos配置中心,可以实现应用程序在运行时动态地响应配置变化,从而实现更加灵活和可维护的系统配置管理。
  • core.sizemax.size是从Nacos中获取的配置参数,分别代表线程池的核心线程数和最大线程数。
  • afterPropertiesSet方法是InitializingBean接口的实现方法,在Bean属性设置后被调用。在这个方法中,初始化了线程池,并注册了Nacos配置的监听器。
  • printThreadPoolStatus方法用于打印当前线程池的状态信息。
  • dynamicThreadPoolAddTask方法用于向线程池中添加任务。
  • changeThreadPoolConfig方法用于修改线程池的核心参数,例如核心线程数和最大线程数。

测试

package com.artisan.bootthreadpoolnacos.controller;

import com.artisan.bootthreadpoolnacos.config.DynamicThreadPoolConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author 小工匠
 * @version 1.0
 * @mark: show me the code , change the world
 */

@RestController
@RequestMapping("/dtp")
public class ThreadPoolController {

    @Autowired
    private DynamicThreadPoolConfig dynamicThreadPool;

    /**
     * 打印当前线程池的状态
     */
    @GetMapping("/info")
    public String printThreadPoolStatus() {
        return dynamicThreadPool.printThreadPoolStatus();
    }

    /**
     * 给线程池增加任务
     *
     * @param count
     */
    @GetMapping("/add")
    public String dynamicThreadPoolAddTask(int count) {
        dynamicThreadPool.dynamicThreadPoolAddTask(count);
        return String.valueOf(count);
    }
}
    
  • 启动Nacos server
  • 启动应用

在这里插入图片描述

打印基本信息

在这里插入图片描述

增加任务,观察执行情况

http://localhost:9090/dtp/add?count=100

日志输出

在这里插入图片描述

Nacos上修改配置信息

在这里插入图片描述

观察日志和信息

在这里插入图片描述

在这里插入图片描述


小结

通过本文的介绍,我们了解了如何利用Nacos实现高效的动态线程池管理,以及其在分布式系统中的应用场景。动态线程池的灵活调整能够有效地提升系统的性能和稳定性,而Nacos作为一个优秀的服务发现和配置中心,为我们提供了强大的支持和便利,帮助我们更好地构建可靠和高效的分布式应用系统。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1470053.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

力扣● 343. 整数拆分 ● 96.不同的二叉搜索树

● 343. 整数拆分 想不到&#xff0c;要勇于看题解。 关键在于理解递推公式。 1、DP数组及其下标的含义&#xff1a;dp[i]是分解i这个数得到的最大的乘积。 2、DP数组如何初始化&#xff1a;dp[0]和dp[1]都没意义&#xff0c;所以直接不赋值&#xff0c;初始化dp[2]1即可。…

maven 打包命令

Maven是基于项目对象模型(POM project object model)&#xff0c;可以通过一小段描述信息&#xff08;配置&#xff09;来管理项目的构建&#xff0c;报告和文档的软件项目管理工具。 Maven的核心功能便是合理叙述项目间的依赖关系&#xff0c;通俗点讲&#xff0c;就是通过po…

【openGL教程08】基于C++的着色器(02)

LearnOpenGL - Shaders 一、说明 着色器是openGL渲染的重要内容&#xff0c;客户如果想自我实现渲染灵活性&#xff0c;可以用着色器进行编程&#xff0c;这种程序小脚本被传送到GPU的显卡内部&#xff0c;起到动态灵活的着色作用。 二、着色器简述 正如“Hello Triangle”一章…

单片机05__串口USART通信__按键控制向上位机传输字符串

串口USART通信 通用UART介绍 1.通信的概念 计算机与外界进行信息交换的过程称之为通信。 在通信的过程中&#xff0c;通信双方都需要遵守的规则称之为通信协议。 硬件协议&#xff1a;将数据以什么样的方式传输过去 软件协议&#xff1a;将数据以什么样的顺序传输过去 2.常用…

C#与VisionPro联合开发——跳转页面

1、跳转页面并打开相机 From1 所有代码展示 using System; using System.IO; using System.Windows.Forms; //引入VisionPro命名空间 using Cognex.VisionPro;namespace ConnectCamera {public partial class Form1 : Form {public Form1() {InitializeComponent();}CogAcqFif…

云原生之API网关Traefik

1. 前言 说到web服务的开源网关&#xff0c;我首先想到的是Nginx&#xff0c;最早使用的就是它&#xff0c;现在都还在使用它。系统上线了Docker Swarm集群之后&#xff0c;不继续使用Nginx直接做Docker服务的网关&#xff0c;是因为Nginx毕竟比Docker Swarm出现的早&#xff0…

【C#】用于基于 UV DLP 的 3D 打印机的切片软件源码解析(一)DLP原理 GUI

0. 原理 基于 UV DLP 的 3D 打印机的工作原理是这样的&#xff1a; UV DLP 是一种使用数字光处理&#xff08;Digital Light Processing&#xff09;技术的 3D 打印方法&#xff0c;它利用紫外光&#xff08;UV&#xff09;来固化液态树脂&#xff0c;从而形成实体物体。UV DLP…

yolov8添加注意力机制模块-CBAM

修改 在tasks.py&#xff08;路径&#xff1a;ultralytics-main/ultralytics-main - attention/ultralytics/nn/tasks.py&#xff09;文件中&#xff0c;引入CBAM模块。因为yolov8源码中已经包含CBAM模块&#xff0c;在conv.py文件中&#xff08;路径&#xff1a;ultralytics-…

从专业到大众:Sora如何颠覆传统视频制作模式

随着科技的飞速进步&#xff0c;人工智能(AI)技术正逐渐渗透到我们生活的方方面面。在视频制作领域&#xff0c;OpenAI推出的Sora模型为这一传统行业带来了前所未有的变革。Sora不仅改变了视频制作的技术门槛&#xff0c;更将视频制作从专业人士的手中解放出来&#xff0c;推向…

LeetCode 1637.两点之间不包含任何点的最宽垂直区域

给你 n 个二维平面上的点 points &#xff0c;其中 points[i] [xi, yi] &#xff0c;请你返回两点之间内部不包含任何点的 最宽垂直区域 的宽度。 垂直区域 的定义是固定宽度&#xff0c;而 y 轴上无限延伸的一块区域&#xff08;也就是高度为无穷大&#xff09;。 最宽垂直区…

Easy-Jmeter: 性能测试平台

目录 写在开始1 系统架构2 表结构设计3 测试平台生命周期4 分布式压测5 压力机管理6 用例管理6.1 新增、编辑用例6.2 调试用例6.3 启动测试6.4 动态控量6.5 测试详情6.6 环节日志6.7 实时数据6.8 测试结果 7 测试记录7 用例分析8 系统部署8.1普通部署8.2容器化部署 写在最后 写…

opencv基础 python与c++

question: pip install -i https://pypi.tuna.tsinghua.edu.cn/simple matplotlib Opencv 一、读取图片 (1).imshow Mat imread(const string& filename, intflags1 );flags: enum { /* 8bit, color or not */CV_LOAD_IMAGE_UNCHANGED -1, /* 8bit, gray */CV_LOAD_I…

小白水平理解面试经典题目LeetCode 404 Sum of Left Leaves【Tree】

404 左叶之和 小白翻译 给定二叉树的root&#xff0c;返回所有左叶的总和。 叶子是没有子节点的节点。左叶是另一个节点的左子节点的叶。 例子 小白教室做题 在大学某个自习的下午&#xff0c;小白坐在教室看到这道题。想想自己曾经和白月光做题&#xff0c;现在大过年的&a…

使用Templ进行Go模板化

使用Templ在Go项目中高效生成动态内容的指南 动态内容生成是Web开发的一个基本方面。无论您是在构建网站、Web应用程序还是API&#xff0c;根据数据和模板生成动态内容的能力都至关重要。在Go编程世界中&#xff0c;一个名为“Templ”的强大工具简化了这一过程。在这份全面的指…

【Crypto | CTF】BugKu 简单的RSA

天命&#xff1a;这题也不算简单了&#xff0c;要反编译&#xff0c;要灵活一点 首先收到pyc文件&#xff0c;拿去反编译出来&#xff0c;可以用在线反编译&#xff0c;也可以用工具反编译 在线&#xff1a;python反编译 - 在线工具 工具&#xff1a;https://download.csdn.n…

Vue packages version mismatch 报错解决

问题 npm run dev 运行项目的过程中&#xff0c;报错 Vue packages version mismatch 解决方法 根据报错不难看出是 vue 与 vue-template-compiler 版本产生了冲突&#xff0c;vue 与 vue-template-compiler 的版本是需要匹配的。所以解决的办法就是先修改其中一个的版本将 v…

Linux环境下C语言实现ping命令

Linux环境下C语言实现ping命令 涉及的知识点 Linux信号量的使用 SIGALRM信号是操作系统中的其中一个信号。他的作用是设置进程隔多久后会收到一个SIGALRM信号 #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <signal.h> …

AI赋能Oracle DBA:以自然语言与Oracle数据库互动

DBA AI助手&#xff1a;以自然语言与Oracle数据库互动 0. 引言1. AI赋能Oracle DBA的优势2. AI如何与Oracle数据库交互3. 自然语言查询的一些示例4. 未来展望 0. 引言 传统的Oracle数据库管理 (DBA) 依赖于人工操作&#xff0c;包括编写复杂的SQL语句、分析性能指标和解决各种…

PHP语言检测用户输入密码及调用Python脚本

现在有一份计算流体力学N-S方程的Python脚本&#xff0c;想要在用户登录网站后可以可以运行该脚本&#xff0c;然后将脚本运行后绘制的图片显示在用户网页上。 建一个名为N_S.py的python脚本文件&#xff0c;这个脚本在生成图像后会自行关闭&#xff0c;随后将图片保存在指定的…

【读文献】DynamicBind生成式模型预测蛋白配体复合物

published at nature communication (2024.01.24) code link paper link 摘要 尽管在预测静态蛋白质结构方面取得了重大进展&#xff0c;但蛋白质的内在动态性&#xff0c;受到配体调节&#xff0c;对于理解蛋白质功能和促进药物发现至关重要。 传统的对接方法&#xff0c;常…