# 超时和阻塞问题分析与解决方案 ## 问题概述 经过全面检查,发现以下几个可能导致超时和阻塞的问题: ## 1. WebClient 连接池配置缺失 ⚠️ 高优先级 ### 问题描述 `ScriptClient.java` 中的 WebClient 没有配置底层 HTTP 客户端的连接池参数,可能导致: - 连接数耗尽,新请求被阻塞 - 连接泄漏 - 超时设置未生效 ### 当前代码 ```java this.webClient = WebClient.builder() .baseUrl(baseUrl) .exchangeStrategies(ExchangeStrategies.builder() .codecs(cfg -> cfg.defaultCodecs().maxInMemorySize(2 * 1024 * 1024)) .build()) .build(); ``` ### 解决方案 需要配置 Reactor Netty HttpClient: ```java HttpClient httpClient = HttpClient.create() .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, connectTimeoutMs) .responseTimeout(Duration.ofMillis(readTimeoutMs)) .doOnConnected(conn -> conn.addHandlerLast(new ReadTimeoutHandler(readTimeoutMs, TimeUnit.MILLISECONDS)) .addHandlerLast(new WriteTimeoutHandler(connectTimeoutMs, TimeUnit.MILLISECONDS))) .wiretap(true); // 开启日志追踪 this.webClient = WebClient.builder() .baseUrl(baseUrl) .clientConnector(new ReactorClientHttpConnector(httpClient)) .exchangeStrategies(ExchangeStrategies.builder() .codecs(cfg -> cfg.defaultCodecs().maxInMemorySize(2 * 1024 * 1024)) .build()) .build(); ``` ## 2. Tomcat 线程池配置缺失 ⚠️ 高优先级 ### 问题描述 Spring Boot 内嵌 Tomcat 使用默认线程池配置,可能不足以处理高并发场景。 ### 解决方案 在 `application.yml` 中添加: ```yaml server: port: 18080 tomcat: threads: max: 200 # 最大工作线程数 min-spare: 20 # 最小空闲线程数 max-connections: 10000 # 最大连接数 accept-count: 100 # 队列长度 connection-timeout: 20000 # 连接超时(ms) shutdown: graceful # 优雅关闭 spring: lifecycle: timeout-per-shutdown-phase: 30s # 关闭超时 ``` ## 3. WebFlux 配置优化 ⚠️ 中优先级 ### 问题描述 如果项目使用了 WebFlux,需要配置 Reactor 线程池。 ### 解决方案 在 `application.yml` 中添加: ```yaml spring: webflux: # WebFlux 相关配置(如果使用) base-path: / reactor: # Reactor 线程池配置 netty: pool: type: elastic # 使用弹性线程池 ``` ## 4. 数据库连接池优化 ⚠️ 中优先级 ### 当前配置 ```yaml hikari: maximum-pool-size: 50 minimum-idle: 10 connection-timeout: 30000 # 30秒 idle-timeout: 600000 # 10分钟 max-lifetime: 1800000 # 30分钟 ``` ### 问题 - `connection-timeout` 设置为 30 秒过长,可能导致请求堆积 - MySQL 锁等待超时设置为 30 秒也偏长 ### 建议优化 ```yaml hikari: maximum-pool-size: 80 # 增加连接池大小 minimum-idle: 20 # 增加最小空闲连接 connection-timeout: 10000 # 降低到10秒 idle-timeout: 300000 # 5分钟 max-lifetime: 1800000 # 30分钟 leak-detection-threshold: 30000 # 30秒检测连接泄漏(从60秒降低) validation-timeout: 3000 # 降低到3秒 ``` 同时优化 MySQL 会话参数: ```yaml datasource: url: jdbc:mysql://...?sessionVariables=innodb_lock_wait_timeout=10,wait_timeout=300,interactive_timeout=300 ``` ## 5. 异步线程池拒绝策略优化 ⚠️ 中优先级 ### 当前配置 ```java executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); ``` ### 问题 CallerRunsPolicy 会让调用线程(通常是 HTTP 线程)执行任务,可能导致 HTTP 线程池阻塞。 ### 建议 根据业务需求选择: **方案 A:丢弃策略(不重要的任务)** ```java executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy()); ``` **方案 B:增加队列并监控(重要任务)** ```java executor.setQueueCapacity(500); // 从100增加到500 executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy()); // 添加拒绝处理监控 ``` ## 6. 事务超时优化 ⚠️ 中优先级 ### 问题 部分事务方法可能执行时间过长,持有数据库连接。 ### 建议 1. 为不同类型的事务设置不同超时: ```java @Transactional(timeout = 5) // 快速查询/更新 @Transactional(timeout = 15) // 批量操作 @Transactional(timeout = 30) // 复杂业务逻辑 ``` 2. 避免在事务中调用外部 HTTP 接口: ```java // ❌ 不好的做法 @Transactional public Mono process() { // 事务内调用外部 HTTP return externalService.call().map(data -> { repository.save(data); // 持有连接时间过长 }); } // ✅ 推荐做法 public Mono process() { // 先调用外部接口 return externalService.call() .flatMap(data -> { // 再开启事务保存 return Mono.fromCallable(() -> saveInTransaction(data)) .subscribeOn(Schedulers.boundedElastic()); }); } @Transactional(timeout = 5) private Result saveInTransaction(Data data) { return repository.save(data); } ``` ## 7. 添加请求超时和监控 ⚠️ 中优先级 ### 建议配置 在 `application.yml` 中添加: ```yaml spring: mvc: async: request-timeout: 60000 # 60秒异步请求超时 management: endpoints: web: exposure: include: health,info,metrics,threaddump,heapdump metrics: enable: tomcat: true hikaricp: true jvm: true ``` ## 8. 日志优化建议 添加性能监控日志: ```yaml logging: level: reactor.netty: INFO # Reactor Netty 日志 io.netty: INFO # Netty 日志 com.zaxxer.hikari: INFO # HikariCP 日志 org.springframework.web.reactive: INFO # WebFlux 日志 ``` ## 实施优先级 ### 立即实施(高优先级) 1. ✅ 配置 WebClient 连接池和超时 2. ✅ 配置 Tomcat 线程池 3. ✅ 优化数据库连接池参数 ### 短期实施(中优先级) 4. 优化异步线程池拒绝策略 5. 检查并优化事务边界 6. 添加性能监控端点 ### 长期优化 7. 添加分布式追踪(如 Sleuth + Zipkin) 8. 添加断路器(如 Resilience4j) 9. 考虑使用 Redis 缓存热点数据 ## 监控建议 ### 1. 添加健康检查 ```java @Component public class CustomHealthIndicator implements HealthIndicator { @Override public Health health() { // 检查数据库连接 // 检查外部服务 // 检查线程池状态 return Health.up().build(); } } ``` ### 2. 添加性能指标 ```java @Timed(value = "api.calls", description = "API调用耗时") public Mono apiMethod() { // ... } ``` ### 3. 监控关键指标 - HTTP 线程池使用率 - 数据库连接池使用率 - 异步线程池队列长度 - 外部接口响应时间 - 事务执行时间 ## 总结 主要问题集中在: 1. **HTTP 客户端配置不完整** - 导致连接管理问题 2. **服务器线程池未配置** - 默认值可能不适合生产环境 3. **数据库连接和事务管理** - 超时设置偏保守 4. **缺少监控和告警** - 难以及时发现问题 建议按优先级逐步实施优化措施。