Tomcat线程池参数调优:压测数据说话
Spring Boot默认内嵌Tomcat线程池配置对低负载场景够用,但面对高并发时就暴露短板。调优前先用压测工具拿到基线数据。
# 用wrk压测获取基线
wrk -t8 -c500 -d30s http://localhost:8080/api/orders
关键参数在application.yml中配置:
server:
tomcat:
threads:
max: 400 # 最大工作线程数,默认200
min-spare: 50 # 最小空闲线程数,默认10
max-connections: 8000 # 最大连接数,默认8192
accept-count: 200 # 等待队列长度,默认100
connection-timeout: 5000
线程数不是越大越好。CPU密集型任务线程数=CPU核数+1;IO密集型任务线程数=CPU核数×(1+等待时间/计算时间)。实际值要通过压测调整,观察CPU利用率和线程等待时间。
监控线程池状态:
@RestController
public class TomcatMetricsController {
@Autowired
private ServerProperties serverProperties;
@GetMapping("/metrics/tomcat")
public Map<String, Object> tomcatMetrics() {
ThreadPoolExecutor executor = (ThreadPoolExecutor)
ManagementFactory.getPlatformMBeanServer().getAttribute(
new ObjectName("Tomcat:type=ThreadPool,name="http-nio-*""),
"activeCount"
);
return Map.of(
"activeThreads", executor.getActiveCount(),
"poolSize", executor.getPoolSize(),
"queueSize", executor.getQueue().size(),
"completedTasks", executor.getCompletedTaskCount()
);
}
}
接口级限流:Sentinel配置与自定义规则
高并发场景下限流是第一道防线。Sentinel相比Guava RateLimiter的优势是支持集群限流和丰富的流控效果。
// 引入依赖
// implementation 'com.alibaba.csp:sentinel-spring-boot-starter:1.8.7'
// 自定义限流规则配置
@Configuration
public class SentinelConfig {
@PostConstruct
public void initRules() {
List<FlowRule> rules = new ArrayList<>();
// 订单创建接口:QPS限流200
FlowRule orderRule = new FlowRule();
orderRule.setResource("POST:/api/orders");
orderRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
orderRule.setCount(200);
orderRule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_WARM_UP);
orderRule.setWarmUpPeriodSec(10); // 预热10秒
rules.add(orderRule);
// 支付接口:更严格限流
FlowRule payRule = new FlowRule();
payRule.setResource("POST:/api/payments");
payRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
payRule.setCount(50);
payRule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER);
payRule.setMaxQueueingTimeMs(2000); // 排队超时2秒
rules.add(payRule);
FlowRuleManager.loadRules(rules);
}
}
// 控制器中使用
@RestController
public class OrderController {
@SentinelResource(value = "POST:/api/orders",
blockHandler = "createOrderBlock",
fallback = "createOrderFallback")
@PostMapping("/api/orders")
public Order createOrder(@RequestBody OrderRequest req) {
return orderService.create(req);
}
public Order createOrderBlock(BlockException ex) {
throw new BusinessException("SYSTEM_BUSY", "系统繁忙,请稍后重试");
}
public Order createOrderFallback(Throwable ex) {
log.error("订单创建异常", ex);
throw new BusinessException("SYSTEM_ERROR", "系统异常");
}
}
熔断降级:Resilience4j断路器配置
当下游服务异常率升高时,断路器打开,快速失败而非让请求堆积超时。
// application.yml配置
resilience4j:
circuitbreaker:
instances:
paymentService:
sliding-window-type: COUNT_BASED
sliding-window-size: 20
failure-rate-threshold: 50
slow-call-duration-threshold: 3s
slow-call-rate-threshold: 60
permitted-number-of-calls-in-half-open-state: 5
wait-duration-in-open-state: 30s
minimum-number-of-calls: 10
// 在服务调用处使用
@Service
public class PaymentServiceClient {
@CircuitBreaker(name = "paymentService", fallbackMethod = "payFallback")
@TimeLimiter(name = "paymentService")
public CompletableFuture<PaymentResult> pay(PaymentRequest req) {
return CompletableFuture.supplyAsync(() -> {
return restTemplate.postForObject(
"http://payment-service/api/pay", req, PaymentResult.class);
});
}
private PaymentResult payFallback(Throwable t) {
log.warn("支付服务熔断降级: {}", t.getMessage());
return PaymentResult.degrade("支付服务暂时不可用");
}
}
RabbitMQ异步消息处理架构
高并发写操作不适合同步处理。用消息队列削峰填谷,核心流程同步返回,后续处理异步化。
// 消息生产者
@Service
public class OrderMessageProducer {
@Autowired
private RabbitTemplate rabbitTemplate;
public void sendOrderCreatedEvent(Order order) {
OrderEvent event = OrderEvent.from(order);
rabbitTemplate.convertAndSend(
"order.exchange",
"order.created",
event,
msg -> {
msg.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT);
return msg;
}
);
}
}
// 消息消费者(手动ACK + 重试)
@Component
@RabbitListener(queues = "order.created.queue")
public class OrderCreatedConsumer {
@RabbitHandler
public void handle(OrderEvent event, Channel channel,
@Header(AmqpHeaders.DELIVERY_TAG) long tag) throws IOException {
try {
inventoryService.deduct(event);
pointsService.earn(event);
channel.basicAck(tag, false);
} catch (BusinessException e) {
// 业务异常,不重试,进死信队列
channel.basicReject(tag, false);
} catch (Exception e) {
// 系统异常,重试
channel.basicNack(tag, false, true);
}
}
}
// 死信队列配置
@Configuration
public class DLQConfig {
@Bean
public Queue orderDeadLetterQueue() {
return QueueBuilder.durable("order.dlq")
.withArgument("x-message-ttl", 86400000) // 24小时过期
.build();
}
@Bean
public DirectExchange orderExchange() {
return new DirectExchange("order.exchange");
}
}
并发安全与本地缓存设计
Spring Boot的@Cacheable在高并发下有缓存击穿风险——大量线程同时穿透到数据库。用互锁加载解决:
@Service
public class ProductService {
private final Map<String, CompletableFuture<Product>> loadingMap =
new ConcurrentHashMap<>();
@Cacheable(value = "products", key = "#id")
public Product getProduct(String id) {
// 防止缓存击穿:同一个key只允许一个线程加载
while (true) {
CompletableFuture<Product> existing = loadingMap.get(id);
if (existing != null) {
try {
return existing.get();
} catch (Exception e) {
loadingMap.remove(id);
throw new BusinessException("PRODUCT_LOAD_ERROR");
}
}
CompletableFuture<Product> future = new CompletableFuture<>();
if (loadingMap.putIfAbsent(id, future) == null) {
try {
Product product = productRepository.findById(id);
future.complete(product);
return product;
} catch (Exception e) {
future.completeExceptionally(e);
throw e;
} finally {
loadingMap.remove(id);
}
}
}
}
}
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/springboot-gao-bing-fa-she-ji-shi-zhan-xian-cheng-chi-diao/