如何优化Spring Boot应用以处理每秒百万请求 在当今高流量的互联网环境中,应用程序需要处理的请求量正在迅速增长。作为Java开发者,我们经常面临如何扩展Spring Boot应用以处理大量并发请求的挑战。本文将探讨如何将Spring Boot应用从处理每秒5万请求优化到每秒100万请求的实用策略,并提供详细的代码示例和实施步骤。
面临的挑战 想象一下这样的场景:你的团队被告知应用需要在三个月内实现20倍的流量增长,从每秒5万请求提升到每秒100万请求,而且硬件预算有限。这听起来几乎是不可能完成的任务。然而,通过深入分析性能瓶颈和应用一系列优化技术,我们可以达成这一目标。
在开始优化之前,我们需要了解系统的现状:
基于Spring Boot 2.x的传统MVC架构
使用内嵌的Tomcat服务器
采用JPA进行数据库访问
典型的N层架构(Controller > Service > Repository)
高峰期出现频繁的GC暂停和超时错误
关键性能指标 在开始优化过程之前,了解我们的目标至关重要。成功优化后的应用应该达到以下性能指标:
最大吞吐量:每秒120万请求
平均响应时间:85毫秒(优化前为350毫秒)
95%响应时间:120毫秒(优化前为850毫秒)
峰值CPU使用率:60-70%(优化前为85-95%)
内存使用:可用堆的50%(优化前为75%)
数据库查询:通过缓存减少70%
优化策略 1. 采用响应式编程模型(Spring WebFlux) 最有影响力的变化是采用Spring WebFlux进行响应式编程。这不仅仅是简单的替换,而是需要重新思考应用程序的结构。首先,更新项目依赖:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-webflux</artifactId > <version > 2.7.5</version > </dependency > <dependency > <groupId > io.projectreactor.netty</groupId > <artifactId > reactor-netty</artifactId > <version > 1.0.24</version > </dependency > <dependency > <groupId > io.projectreactor</groupId > <artifactId > reactor-test</artifactId > <scope > test</scope > </dependency >
然后,改变控制器实现方式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 @RestController @RequestMapping("/api/products") public class ProductController { @Autowired private ProductService productService; @GetMapping("/{id}") public ResponseEntity<Product> getProduct (@PathVariable Long id) { Product product = productService.getProductById(id); return ResponseEntity.ok(product); } @GetMapping public ResponseEntity<List<Product>> getAllProducts () { List<Product> products = productService.getAllProducts(); return ResponseEntity.ok(products); } } @RestController @RequestMapping("/api/products") public class ReactiveProductController { @Autowired private ReactiveProductService productService; @GetMapping("/{id}") public Mono<ResponseEntity<Product>> getProduct (@PathVariable Long id) { return productService.getProductById(id) .map(ResponseEntity::ok) .defaultIfEmpty(ResponseEntity.notFound().build()); } @GetMapping public Mono<ResponseEntity<List<Product>>> getAllProducts () { return productService.getAllProducts() .collectList() .map(ResponseEntity::ok) .defaultIfEmpty(ResponseEntity.notFound().build()); } }
服务层也需要相应改变:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 @Service public class ProductService { @Autowired private ProductRepository repository; public Product getProductById (Long id) { return repository.findById(id) .orElseThrow(() -> new ProductNotFoundException (id)); } public List<Product> getAllProducts () { return repository.findAll(); } } @Service public class ReactiveProductService { @Autowired private ReactiveProductRepository repository; public Mono<Product> getProductById (Long id) { return repository.findById(id) .switchIfEmpty(Mono.error(new ProductNotFoundException (id))); } public Flux<Product> getAllProducts () { return repository.findAll(); } }
2. 优化数据库访问 数据库通常是系统的主要瓶颈。以下是一些优化数据库访问的详细策略:
2.1 采用响应式数据库驱动 将传统的JDBC驱动替换为响应式数据库驱动:
1 2 3 4 5 6 7 8 9 10 11 12 <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-data-r2dbc</artifactId > </dependency > <dependency > <groupId > dev.miku</groupId > <artifactId > r2dbc-mysql</artifactId > <version > 0.8.2.RELEASE</version > </dependency >
配置R2DBC连接:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 @Configuration public class R2dbcConfig { @Bean public ConnectionFactory connectionFactory () { return MySqlConnectionFactory.from( MySqlConnectionConfiguration.builder() .host("localhost" ) .port(3306 ) .username("root" ) .password("password" ) .database("reactive_demo" ) .build() ); } @Bean public R2dbcEntityTemplate r2dbcEntityTemplate (ConnectionFactory connectionFactory) { return new R2dbcEntityTemplate (connectionFactory); } }
创建响应式Repository:
1 2 3 4 5 6 7 8 9 public interface ReactiveProductRepository extends ReactiveCrudRepository <Product, Long> { Flux<Product> findByCategory (String category) ; Mono<Product> findByName (String name) ; @Query("SELECT * FROM products WHERE price > :minPrice") Flux<Product> findExpensiveProducts (BigDecimal minPrice) ; }
2.2 实施多级缓存策略 引入Redis缓存:
1 2 3 4 5 <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-data-redis-reactive</artifactId > </dependency >
配置Redis缓存:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 @Configuration @EnableRedisRepositories public class RedisConfig { @Bean public ReactiveRedisConnectionFactory reactiveRedisConnectionFactory () { return new LettuceConnectionFactory ("localhost" , 6379 ); } @Bean public ReactiveRedisTemplate<String, Product> reactiveRedisTemplate ( ReactiveRedisConnectionFactory factory) { StringRedisSerializer keySerializer = new StringRedisSerializer (); Jackson2JsonRedisSerializer<Product> valueSerializer = new Jackson2JsonRedisSerializer <>(Product.class); RedisSerializationContext.RedisSerializationContextBuilder<String, Product> builder = RedisSerializationContext.newSerializationContext(keySerializer); RedisSerializationContext<String, Product> context = builder.value(valueSerializer).build(); return new ReactiveRedisTemplate <>(factory, context); } }
在服务层实现缓存:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 @Service public class CachedProductService { private static final String CACHE_KEY_PREFIX = "product:" ; private static final Duration CACHE_TTL = Duration.ofMinutes(10 ); @Autowired private ReactiveProductRepository repository; @Autowired private ReactiveRedisTemplate<String, Product> redisTemplate; public Mono<Product> getProductById (Long id) { String cacheKey = CACHE_KEY_PREFIX + id; return redisTemplate.opsForValue().get(cacheKey) .switchIfEmpty( repository.findById(id) .flatMap(product -> { return redisTemplate.opsForValue() .set(cacheKey, product, CACHE_TTL) .thenReturn(product); }) ); } public Flux<Product> getAllProducts () { return repository.findAll(); } public Mono<Void> invalidateCache (Long id) { String cacheKey = CACHE_KEY_PREFIX + id; return redisTemplate.delete(cacheKey); } }
2.3 优化SQL查询 使用索引优化:
1 2 3 4 CREATE INDEX idx_product_category ON products(category);CREATE INDEX idx_product_price ON products(price);CREATE INDEX idx_product_name ON products(name);
优化查询方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public Mono<Boolean> existsByCategory (String category) { return repository.findFirstByCategory(category) .map(product -> true ) .defaultIfEmpty(false ); } public Flux<Product> getProductsByCategory (String category, int page, int size) { return repository.findByCategory(category, PageRequest.of(page, size, Sort.by("name" ).ascending())); } @Query("SELECT id, name, price FROM products WHERE category = :category") Flux<ProductSummary> findProductSummariesByCategory (String category) ;
2.4 实现读写分离 配置主从数据源:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 @Configuration public class DatabaseConfig { @Bean @Primary @Qualifier("masterConnectionFactory") public ConnectionFactory masterConnectionFactory () { return MySqlConnectionFactory.from( MySqlConnectionConfiguration.builder() .host("master-db.example.com" ) .port(3306 ) .username("master_user" ) .password("master_pass" ) .database("products" ) .build() ); } @Bean @Qualifier("slaveConnectionFactory") public ConnectionFactory slaveConnectionFactory () { return MySqlConnectionFactory.from( MySqlConnectionConfiguration.builder() .host("slave-db.example.com" ) .port(3306 ) .username("read_user" ) .password("read_pass" ) .database("products" ) .build() ); } @Bean public TransactionManager transactionManager ( @Qualifier("masterConnectionFactory") ConnectionFactory connectionFactory) { return new R2dbcTransactionManager (connectionFactory); } }
创建读写分离的Repository:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 @Repository public class ReadWriteProductRepository { private final R2dbcEntityTemplate masterTemplate; private final R2dbcEntityTemplate slaveTemplate; public ReadWriteProductRepository ( @Qualifier("masterConnectionFactory") ConnectionFactory masterFactory, @Qualifier("slaveConnectionFactory") ConnectionFactory slaveFactory) { this .masterTemplate = new R2dbcEntityTemplate (masterFactory); this .slaveTemplate = new R2dbcEntityTemplate (slaveFactory); } @Transactional public Mono<Product> save (Product product) { return masterTemplate.insert(Product.class) .into("products" ) .using(product); } public Mono<Product> findById (Long id) { return slaveTemplate.select(Product.class) .from("products" ) .matching(Query.query(Criteria.where("id" ).is(id))) .one(); } public Flux<Product> findAll () { return slaveTemplate.select(Product.class) .from("products" ) .all(); } }
3. 配置调优 性能提升往往来自于正确的配置调整。以下是详细的配置优化步骤:
3.1 调整Netty服务器参数 在application.yml
中配置Netty参数:
1 2 3 4 5 6 7 8 9 10 11 12 13 spring: webflux: base-path: /api netty: connection: timeout: 5000 worker: count: 16 boss: count: 2 buffer: size: 32768
在Java代码中自定义Netty配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 @Configuration public class NettyConfig { @Bean public NettyReactiveWebServerFactory nettyReactiveWebServerFactory () { NettyReactiveWebServerFactory factory = new NettyReactiveWebServerFactory (); factory.addServerCustomizers(server -> { HttpServer httpServer = (HttpServer) server; httpServer.tcpConfiguration(tcpServer -> tcpServer.option(ChannelOption.SO_RCVBUF, 128 * 1024 ) .option(ChannelOption.SO_SNDBUF, 128 * 1024 ) .option(ChannelOption.SO_KEEPALIVE, true ) .option(ChannelOption.SO_REUSEADDR, true ) .option(ChannelOption.TCP_NODELAY, true )); return httpServer; }); return factory; } }
3.2 优化JVM堆和垃圾收集器 在application.properties
中添加JVM参数,或者直接在启动脚本中配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 # 堆内存设置 -Xms4g -Xmx4g # 年轻代大小,建议为堆的1/3到1/2 -Xmn2g # GC相关设置,使用G1收集器 -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:ParallelGCThreads=8 -XX:ConcGCThreads=2 -XX:InitiatingHeapOccupancyPercent=70 # 禁用类元数据的GC,防止Full GC -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m # 优化内存分配 -XX:+AlwaysPreTouch -XX:+DisableExplicitGC # 开启GC日志记录 -Xlog:gc*:file=logs/gc-%t.log:time,uptime,level,tags:filecount=5,filesize=100m
3.3 连接池优化 配置R2DBC连接池:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 @Configuration public class ConnectionPoolConfig { @Bean public ConnectionFactory connectionFactory () { ConnectionPoolConfiguration configuration = ConnectionPoolConfiguration.builder() .connectionFactory(createConnectionFactory()) .maxIdleTime(Duration.ofMinutes(30 )) .maxLifeTime(Duration.ofHours(2 )) .maxAcquireTime(Duration.ofSeconds(3 )) .initialSize(10 ) .maxSize(50 ) .minIdle(10 ) .build(); return new ConnectionPool (configuration); } private ConnectionFactory createConnectionFactory () { return MySqlConnectionFactory.from( MySqlConnectionConfiguration.builder() .host("localhost" ) .port(3306 ) .username("root" ) .password("password" ) .database("reactive_demo" ) .connectTimeout(Duration.ofSeconds(3 )) .build() ); } }
配置Redis连接池:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 @Configuration public class RedisConnectionConfig { @Bean public ReactiveRedisConnectionFactory reactiveRedisConnectionFactory () { LettuceClientConfiguration clientConfig = LettuceClientConfiguration.builder() .commandTimeout(Duration.ofMillis(100 )) .shutdownTimeout(Duration.ZERO) .clientOptions(ClientOptions.builder() .socketOptions(SocketOptions.builder() .connectTimeout(Duration.ofMillis(100 )) .keepAlive(true ) .build()) .build()) .clientResources(DefaultClientResources.builder() .ioThreadPoolSize(4 ) .computationThreadPoolSize(4 ) .build()) .build(); RedisStandaloneConfiguration serverConfig = new RedisStandaloneConfiguration (); serverConfig.setHostName("localhost" ); serverConfig.setPort(6379 ); return new LettuceConnectionFactory (serverConfig, clientConfig); } }
3.4 HTTP客户端调优 配置WebClient高性能连接池:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 @Configuration public class WebClientConfig { @Bean public WebClient webClient () { HttpClient httpClient = HttpClient.create() .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000 ) .option(ChannelOption.SO_KEEPALIVE, true ) .option(ChannelOption.TCP_NODELAY, true ) .doOnConnected(conn -> conn.addHandlerLast(new ReadTimeoutHandler (10 )) .addHandlerLast(new WriteTimeoutHandler (10 ))) .responseTimeout(Duration.ofSeconds(5 )) .compress(true ) .wiretap(true ) .keepAlive(true ) .poolResources(ConnectionProvider.builder("custom" ) .maxConnections(500 ) .pendingAcquireTimeout(Duration.ofMillis(5000 )) .pendingAcquireMaxCount(1000 ) .maxIdleTime(Duration.ofMillis(8000 )) .build()); return WebClient.builder() .clientConnector(new ReactorClientHttpConnector (httpClient)) .codecs(configurer -> configurer.defaultCodecs().maxInMemorySize(16 * 1024 * 1024 )) .build(); } }
4. 混合架构方法 不是所有的端点都需要改为响应式的。下面是混合架构的详细实现:
4.1 定义混合架构路由 使用Spring的路由器函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 @Configuration public class RouterConfig { @Bean public RouterFunction<ServerResponse> highTrafficRoutes ( ReactiveProductHandler productHandler) { return RouterFunctions .route(GET("/api/products" ).and(accept(APPLICATION_JSON)), productHandler::getAllProducts) .andRoute(GET("/api/products/{id}" ).and(accept(APPLICATION_JSON)), productHandler::getProduct) .andRoute(GET("/api/products/category/{category}" ).and(accept(APPLICATION_JSON)), productHandler::getProductsByCategory); } @Bean public WebMvcConfigurer mvcConfigurer () { return new WebMvcConfigurer () { @Override public void addViewControllers (ViewControllerRegistry registry) { registry.addViewController("/admin" ).setViewName("admin" ); registry.addViewController("/dashboard" ).setViewName("dashboard" ); } }; } }
4.2 响应式处理器实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 @Component public class ReactiveProductHandler { private final ReactiveProductService productService; public ReactiveProductHandler(ReactiveProductService productService) { this.productService = productService; } public Mono<ServerResponse> getProduct(ServerRequest request) { Long productId = Long.valueOf(request.pathVariable("id")); return productService.getProductById(productId) .flatMap(product -> ServerResponse.ok() .contentType(APPLICATION_JSON) .bodyValue(product)) .switchIfEmpty(ServerResponse.notFound().build()); } public Mono<ServerResponse> getAllProducts(ServerRequest request) { return productService.getAllProducts() .collectList() .flatMap(products -> ServerResponse.ok() .contentType(APPLICATION_JSON) .bodyValue(products)) .switchIfEmpty(ServerResponse.notFound().build()); } public Mono<ServerResponse> getProductsByCategory(ServerRequest request) { String category = request.pathVariable("category"); return productService.getProductsByCategory(category) .collectList() .flatMap(products -> ServerResponse.ok() .contentType(APPLICATION_JSON) .bodyValue(products)) .switchIfEmpty(ServerResponse.notFound().build()); } }
4.3 实现逐步迁移策略 创建适配器以支持新旧代码互操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 @Component public class ProductServiceAdapter { private final ReactiveProductService reactiveService; private final LegacyProductService legacyService; @Autowired public ProductServiceAdapter( ReactiveProductService reactiveService, LegacyProductService legacyService) { this.reactiveService = reactiveService; this.legacyService = legacyService; } // 将响应式服务适配到传统服务 public Product getProductSync(Long id) { return reactiveService.getProductById(id).block(); } // 将传统服务适配到响应式服务 public Mono<Product> getProductReactive(Long id) { return Mono.fromCallable(() -> legacyService.getProductById(id)) .subscribeOn(Schedulers.boundedElastic()); } // 批量操作适配 public List<Product> getAllProductsSync() { return reactiveService.getAllProducts().collectList().block(); } public Flux<Product> getAllProductsReactive() { return Flux.defer(() -> Flux.fromIterable(legacyService.getAllProducts())) .subscribeOn(Schedulers.boundedElastic()); } }
5. 水平扩展与Kubernetes 在优化应用程序之后,可以通过Kubernetes进行智能水平扩展。以下是详细的配置和实现:
5.1 创建Dockerfile 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 FROM openjdk:17 -jdk-slimWORKDIR /app COPY target/reactive-product-service-0.0.1-SNAPSHOT.jar app.jar ENV JAVA_OPTS="-XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:+UseStringDeduplication -Xms1g -Xmx1g -XX:+AlwaysPreTouch" EXPOSE 8080 HEALTHCHECK --interval=5s --timeout =3s --retries=3 CMD curl -f http://localhost:8080/actuator/health || exit 1 ENTRYPOINT ["sh" , "-c" , "java $JAVA_OPTS -jar app.jar" ]
5.2 创建Kubernetes部署配置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 apiVersion: apps/v1 kind: Deployment metadata: name: product-service namespace: ecommerce spec: replicas: 3 selector: matchLabels: app: product-service strategy: rollingUpdate: maxSurge: 1 maxUnavailable: 0 type: RollingUpdate template: metadata: labels: app: product-service spec: containers: - name: product-service image: my-registry/product-service:latest imagePullPolicy: Always ports: - containerPort: 8080 resources: requests: cpu: "500m" memory: "1Gi" limits: cpu: "1000m" memory: "2Gi" readinessProbe: httpGet: path: /actuator/health/readiness port: 8080 initialDelaySeconds: 20 periodSeconds: 10 timeoutSeconds: 2 failureThreshold: 3 livenessProbe: httpGet: path: /actuator/health/liveness port: 8080 initialDelaySeconds: 60 periodSeconds: 20 timeoutSeconds: 5 failureThreshold: 3 env: - name: SPRING_PROFILES_ACTIVE value: "prod" - name: SERVER_PORT value: "8080" - name: JAVA_OPTS value: "-XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:+UseStringDeduplication -Xms1g -Xmx1g -XX:+AlwaysPreTouch"
5.3 创建服务和入口配置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 apiVersion: v1 kind: Service metadata: name: product-service namespace: ecommerce spec: selector: app: product-service ports: - port: 80 targetPort: 8080 type: ClusterIP --- apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: product-service-ingress namespace: ecommerce annotations: kubernetes.io/ingress.class: "nginx" nginx.ingress.kubernetes.io/ssl-redirect: "true" nginx.ingress.kubernetes.io/proxy-body-size: "10m" nginx.ingress.kubernetes.io/proxy-read-timeout: "60" nginx.ingress.kubernetes.io/proxy-send-timeout: "60" spec: rules: - host: api.example.com http: paths: - path: /api/products pathType: Prefix backend: service: name: product-service port: number: 80
5.4 配置自动扩缩容 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: product-service-hpa namespace: ecommerce spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: product-service minReplicas: 3 maxReplicas: 20 metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 70 - type: Resource resource: name: memory target: type: Utilization averageUtilization: 80 behavior: scaleUp: stabilizationWindowSeconds: 30 policies: - type: Percent value: 100 periodSeconds: 15 scaleDown: stabilizationWindowSeconds: 300 policies: - type: Percent value: 20 periodSeconds: 60
5.5 实现优雅降级机制 在应用程序中添加断路器模式:
1 2 3 4 5 6 7 8 9 10 11 <!-- 添加Resilience4j依赖 --> <dependency> <groupId>io.github.resilience4j</groupId> <artifactId>resilience4j-spring-boot2</artifactId> <version>1.7.1</version> </dependency> <dependency> <groupId>io.github.resilience4j</groupId> <artifactId>resilience4j-reactor</artifactId> <version>1.7.1</version> </dependency>
配置断路器:
1 2 3 4 5 6 7 8 9 10 11 12 @Configuration public class ResilienceConfig { @Bean public CircuitBreakerRegistry circuitBreakerRegistry() { CircuitBreakerConfig circuitBreakerConfig = CircuitBreakerConfig.custom() .failureRateThreshold(50) .slowCallRateThreshold(50) .slowCallDurationThreshold(Duration.ofSeconds(1)) .permittedNumberOfCallsInHalfOpenState(10) .minimumNumberOfCalls(20) .slidingWindowType(CircuitBreakerConfig.SlidingWindowType.
参考 https://medium.com/javarevisited/how-i-optimized-a-spring-boot-application-to-handle-1m-requests-second-0cbb2f2823ed