工作中遇到的一些技术

OverZeal / 2024-07-15 / 原文

dynamic-tp动态线程池

动态线程池,可以通过nacos配置动态修改线程池参数,官网 以下是dynamic-tp与nacos集成的步骤,更详细配置项可以查看官网

  • 引入依赖坐标
<dependency>
    <groupId>org.dromara.dynamictp</groupId>
    <artifactId>dynamic-tp-spring-cloud-starter-nacos</artifactId>
    <version>1.1.3</version>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.dromara.dynamictp</groupId>
    <artifactId>dynamic-tp-extension-skywalking</artifactId>
    <version>1.1.3</version>
</dependency>
  • 添加配置项
spring:
  dynamic:
    tp:
      enabled: true                               # 是否启用 dynamictp,默认true
      enabledCollect: true                        # 是否开启监控指标采集,默认true
      collectorTypes: internal_logging          # 监控数据采集器类型(logging | micrometer | internal_logging | JMX),默认micrometer
      monitorInterval: 5                       # 监控时间间隔(报警检测、指标采集),默认5s
      executors:                               # 动态线程池配置,都有默认值,采用默认值的可以不配置该项,减少配置量
        - threadPoolName: dtpExecutor1         # 线程池名称,必填
          threadPoolAliasName: 测试线程池        # 线程池别名,可选
          executorType: common                 # 线程池类型 common、eager、ordered、scheduled、priority,默认 common
          corePoolSize: 6                      # 核心线程数,默认1
          maximumPoolSize: 8                   # 最大线程数,默认cpu核数
          queueCapacity: 2000                  # 队列容量,默认1024
          queueType: VariableLinkedBlockingQueue         # 任务队列,查看源码QueueTypeEnum枚举类,默认VariableLinkedBlockingQueue
          rejectedHandlerType: CallerRunsPolicy          # 拒绝策略,查看RejectedTypeEnum枚举类,默认AbortPolicy
          keepAliveTime: 60                              # 空闲线程等待超时时间,默认60
          threadNamePrefix: test                         # 线程名前缀,默认dtp
          allowCoreThreadTimeOut: false                  # 是否允许核心线程池超时,默认false
          waitForTasksToCompleteOnShutdown: true         # 参考spring线程池设计,优雅关闭线程池,默认true
          awaitTerminationSeconds: 5                     # 优雅关闭线程池时,阻塞等待线程池中任务执行时间,默认3,单位(s)
          preStartAllCoreThreads: false                  # 是否预热所有核心线程,默认false
          runTimeout: 200                                # 任务执行超时阈值,单位(ms),默认0(不统计)
          queueTimeout: 100                              # 任务在队列等待超时阈值,单位(ms),默认0(不统计)
          taskWrapperNames: ["swTrace"]                  # 任务包装器名称,继承TaskWrapper接口
          notifyEnabled: false                           # 是否开启报警,默认true

nacos作为配置中心

  • 引入依赖坐标
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
    <version>2.2.9.RELEASE</version>
</dependency>
  • 新增bootstrap.yml
spring:
  application:
    name: TEST-CONFIG
  cloud:
    nacos:
      config:
         server-addr: 127.0.0.1:8848
         username: root
         password: root
         file-extension: yaml
         extension-configs:
           - dataId: ${spring.application.name}.${spring.cloud.nacos.config.file-extension}
             group: DEFAULT_GROUP
             refresh: true
         refresh-enabled: true

---
spring:
  profiles: test
  cloud:
    nacos:
      config:
        namespace: test

guava-retry重试

  • 引入依赖坐标
<dependency>
    <groupId>com.github.rholder</groupId>
    <artifactId>guava-retrying</artifactId>
    <version>2.0.0</version>
</dependency>
  • 创建重试器
private static final Retryer<TestDTO> retryer;

static {
    retryer = RetryerBuilder.<TestDTO>newBuilder()
        // 重试条件
        .retryIfException() // 抛出异常时重试
        .retryIfResult(Predicates.isNull()) // 返回结果为null时重试
        // 等待策略:每次请求间隔3s
        .withWaitStrategy(WaitStrategies.fixedWait(3, TimeUnit.SECONDS))
        // 停止策略:尝试请求5次
        .withStopStrategy(StopStrategies.stopAfterAttempt(5))
        .build();
}
  • 使用重试
Callable<TestDTO> callable = new Callable<TestDTO>() {
    int times = 0;
    @Override
    public TestDTO call() throws Exception {
        times++;
        log.info("第{}次请求", times);
        try {
            // TODO 具体逻辑
            return new TestDTO();
        } catch (Exception e) {
            log.error("请求失败", e);
            return null;
        }
    }
};
try {
    retryer.call(callable);
} catch (Exception e) {
    log.error("重试请求异常", e);
}

hystrix和ribben超时时间

# ribbon的超时时间
ribbon:
  ReadTimeout: 9000
  ConnectTimeout: 9000
  # 配置需要立即加载的其他服务(饿加载)
  eager-load:
    enabled: true
    clients: TEST-JOB

# hystrix的超时时间
hystrix:
  command:
    default:
      execution:
        timeout:
          enabled: true
        isolation:
          thread:
            timeoutInMilliseconds: 9000
  threadpool:
    TEST-CONFIG:
      coreSize: 10 # 核心线程数 默认10
      maximumSize: 20 # 最大线程数 默认10
      maxQueueSize: 20 # 队列最大长度 默认-1
      allowMaximumSizeToDivergeFromCoreSize: true # 允许最大线程数超过核心线程数 默认false
      queueSizeRejectionThreshold: 20 # 队列大小拒绝阈值 默认5

curl

curl -H 'Content-Type: application/json' -X POST -o --location 'https://www.xxx.com' -d '{"aooliType": "0"}'
-H: 请求头 
-X: 请求方式 
-d: 请求体
-o --location: 如果有些https地址不安全可以添加该参数跳过验证
curl -o /dev/null -s -w "total time: %{time_total} seconds\n"  命令中加入这些参数可以测试curl调用url用时多少秒

traceId和tid

作为分布式链路追踪技术中,一般使用有spring-cloud-sleuth(zipkin),skywalking等等。traceId是sleuth中的概念,而在skywalking中类似概念的是tid,它们都表示一个链路的唯一id,可以通过这个id将一次微服务调用串联起来

spring-cloud-sleuth

  • 引入依赖坐标
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-sleuth</artifactId>
    <version>2.2.1.RELEASE</version>
</dependency>
  • 修改日志文件(logback.spring.xml)
<!-- 输出日志到文件 -->
<appender name="rollFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <!-- 正在记录的日志文件的路径及文件名 -->
    <file>${app.log_dir}/log_error.log</file>
    <!--日志文件输出格式 X-B3-TraceId X-B3-SpanId X-B3-ParentSpanId是sleuth中固定的名词-->
    <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
        <layout class="ch.qos.logback.classic.PatternLayout">
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level [${appName},%x{X-B3-TraceId},%x{X-B3-SpanId},%x{X-B3-ParentSpanId}] --[%thread] %logger %msg</pattern>
        </layout>
        <!-- 此处设置字符集 -->
        <charset>UTF-8</charset>
    </encoder>
    <!-- 日志记录器指定拆分策略,按日期,按大小记录 -->
    <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
        <!--按照时间拆分文件名 如果以.gz或.zip结尾可以压缩-->
        <fileNamePattern>${log.path}/error/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
        <!--按照文件大小拆分-->
        <maxFileSize>100MB</maxFileSize>
        <!--日志文件保留天数-->
        <maxHistory>15</maxHistory>
    </rollingPolicy>
</appender>
  • 以上配置代码中输出log即可,但是在多线程中需要将TraceId传过去
@Autowired
private Tracer tracer;

public void test(String[] args) {
    Span span = tracer.currentSpan();
    CompletableFuture.supplyAsync(() -> {
        tracer.withSpanInScope(span);
        log.info("业务逻辑开始");
        // TODO 业务逻辑
        return new TestDTO();
    }).exceptionally(throwable -> {
        log.error("请求失败", throwable);
        return null;
    });
}

skywalking

  • 引入依赖坐标
<dependency>
    <groupId>org.apache.skywalking</groupId>
    <artifactId>apm-toolkit-logback-1.x</artifactId>
    <version>8.7.0</version>
</dependency>
<dependency>
    <groupId>org.apache.skywalking</groupId>
    <artifactId>apm-toolkit-trace</artifactId>
    <version>8.11.0</version>
</dependency>
  • 修改日志文件(logback.spring.xml)
<!-- 输出日志到文件 -->
<appender name="rollFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <!-- 正在记录的日志文件的路径及文件名 -->
    <file>${app.log_dir}/log_error.log</file>
    <!--日志文件输出格式 tid是skywalking中固定的名词-->
    <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
        <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
           <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%tid] --[%thread] %logger %msg</pattern>
        </layout>
        <!-- 此处设置字符集 -->
        <charset>UTF-8</charset>
    </encoder>
    <!-- 日志记录器指定拆分策略,按日期,按大小记录 -->
    <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
        <!--按照时间拆分文件名 如果以.gz或.zip结尾可以压缩-->
        <fileNamePattern>${log.path}/error/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
        <!--按照文件大小拆分-->
        <maxFileSize>100MB</maxFileSize>
        <!--日志文件保留天数-->
        <maxHistory>15</maxHistory>
    </rollingPolicy>
</appender>
  • 以上配置代码中输出log即可,但是在多线程中需要处理下
CompletableFuture.supplyAsync(SupplierWrapper.of(() -> {
    log.info("业务逻辑开始");
    // TODO 业务逻辑
    return new TestDTO();
})).exceptionally(FunctionWrapper.of(throwable -> {
    log.error("请求失败", throwable);
    return null;
}));

// 如果多线程不需要返回值
CompletableFuture.runAsync(RunnableWrapper.of(() -> {
    log.info("业务逻辑开始");
    // TODO 业务逻辑
}));

skywalking是在jar启动时通过javaagent参数执行的

-javaagent:/home/appadmin/skywalking_agent/skywalking-agent.jar -Dskywalking.agent.service_name=TEST_CONFIG -Dskywalking.agent.instance_name=TEST_CONFIG_${ip}_${PORT}
指定jar包路径以及服务名和实例名

jasypt加密

整合SpringBoot项目

  • 引入依赖坐标
<dependency>
    <groupId>com.github.ulisesbocchio</groupId>
    <artifactId>jasypt-spring-boot-starter</artifactId>
    <version>2.1.0</version>
</dependency>
  • 启动参数添加jasypt密钥

本地启动:Idea Program arguments添加参数--jasypt.encryptor.password=密钥

服务器启动:SpringBoot启动参数添加--jasypt.encryptor.password=密钥

  • 通过代码生成密文,将生成的密文替换为原本的密码,格式为ENC(密文)