Resilience4J熔断器
- 引入依赖
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-cloud-starter-circuitbreaker-reactor-resilience4j</artifactId></dependency>
- Resilience4J 断路器介绍
- 三个一般性状态CLOSED:关闭状态,放过所有请求,记录请求状态 。OPEN:打开,异常请求达到阀值数量时,开启熔断,拒绝所有请求 。HALF_OPEN:半开,放开一定数量的请求,重新计算错误率 。
- 两个特定状态DISABLED:禁用FORCED_OPEN:强开
- 状态之间转换启动时断路器为CLOSE状态,在达到一定请求量之后计算请求失败率,达到或高于指定失败率后,断路进入open状态,阻拦所有请求,开启一段时间(自定义)时间后,断路器变为halfOpen状态,重新计算请求失败率 。halfOpen错误率低于指定失败率后,断路进入close状态,否则进入open状态 。
文章插图
状态转换
- 通过Resilience4J启用Spring Cloud Gateway断路器
ReactiveResilience4JCircuitBreakerFactory 。可以非常简单地去配置设置,下面使用默认配置进行测试
@Beanpublic Customizer<ReactiveResilience4JCircuitBreakerFactory> defaultCustomizer() {return factory -> factory.configureDefault(id -> new Resilience4JConfigBuilder(id).circuitBreakerConfig(CircuitBreakerConfig.custom()//统计失败率的请求总数.slidingwindowsize(5)//在半开状态下请求的次数.permittedNumberOfCallsInHalfOpenState(5)//断路器打开的成功率.failureRateThreshold(50.0F)//断路器打开的周期.waitDurationInOpenState(Duration.ofMillis(30))//属于慢请求的周期.slowCallDurationThreshold(Duration.ofMillis(200))//慢请求打开断路器的成功率.slowCallRateThreshold(50.0F).build()).timeLimiterConfig(TimeLimiterConfig.custom().timeoutDuration(Duration.ofMillis(200)).build()).build());}
- 测试Resilience4J断路器
@Beanpublic Customizer<ReactiveResilience4JCircuitBreakerFactory> defaultCustomizer() {return factory -> factory.configureDefault(id -> new Resilience4JConfigBuilder(id).circuitBreakerConfig(CircuitBreakerConfig.ofDefaults()).circuitBreakerConfig(CircuitBreakerConfig.custom().slowCallDurationThreshold(Duration.ofMillis(200)).build()).timeLimiterConfig(TimeLimiterConfig.custom().timeoutDuration(Duration.ofMillis(200)).build()).build());}
执行下面Test用例@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)@RunWith(SpringRunner.class)public class GatewayCircuitBreakerTest {private static final Logger LOGGER = LoggerFactory.getLogger(GatewayRateLimiterTest.class);@Rulepublic TestRule benchmarkRun = new BenchmarkRule();@ClassRulepublic static MockServerContainer mockServer = new MockServerContainer();@AutowiredTestRestTemplate template;final Random random = new Random();int i = 0;@BeforeClasspublic static void init() {System.setProperty("logging.level.org.springframework.cloud.gateway.filter.factory", "TRACE");System.setProperty("spring.cloud.gateway.routes[0].id", "account-service");System.setProperty("spring.cloud.gateway.routes[0].uri", "http://localhost:" + mockServer.getServerPort());System.setProperty("spring.cloud.gateway.routes[0].predicates[0]", "Path=/account/**");System.setProperty("spring.cloud.gateway.routes[0].filters[0]", "RewritePath=/account/(?<path>.*), /$\{path}");System.setProperty("spring.cloud.gateway.routes[0].filters[1].name", "CircuitBreaker");System.setProperty("spring.cloud.gateway.routes[0].filters[1].args.name", "exampleSlowCircuitBreaker");//System.setProperty("spring.cloud.gateway.routes[0].filters[1].args.slowCallDurationThreshold", "100");//System.setProperty("spring.cloud.gateway.routes[0].filters[1].args.slowCallRateThreshold", "9.0F");//System.setProperty("spring.cloud.gateway.routes[0].filters[1].args.fallbackUri", "forward:/fallback/account");MockServerClient client = new MockServerClient(mockServer.getContainerIpAddress(), mockServer.getServerPort());client.when(HttpRequest.request().withPath("/1")).respond(response().withBody("{"id":1,"number":"1234567890"}").withHeader("Content-Type", "application/json"));//client.when(HttpRequest.request()//.withPath("/2"), Times.exactly(3))//.respond(response()//.withBody("{"id":2,"number":"1"}")//.withDelay(TimeUnit.SECONDS, 1000)//.withHeader("Content-Type", "application/json"));client.when(HttpRequest.request().withPath("/2")).respond(response().withBody("{"id":2,"number":"1234567891"}").withDelay(TimeUnit.SECONDS, 200).withHeader("Content-Type", "application/json"));}@Test@BenchmarkOptions(warmupRounds = 0, concurrency = 1, benchmarkRounds = 600)public void testAccountService() {int gen = 1 + (i++ % 2);ResponseEntity<Account> r = template.exchange("/account/{id}", HttpMethod.GET, null, Account.class, gen);LOGGER.info("{}. Received: status->{}, payload->{}, call->{}", i, r.getStatusCodeValue(), r.getBody(), gen);}}
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- MySQL高级进阶:关于InnoDB存储结构,一文深入分析讲解
- 什么是搜索引擎营销?
- 程序员标配Springboot!终于有人把SpringBoot讲的通俗易懂了
- 还搞不清Spring 与 Spring MVC 容器之间的关系?
- SpringBoot事件监听:应用监听接口的使用
- SpringCloud Zookeeper配置中心详解
- 微信正在用的深度学习框架开源!支持稀疏张量,基于C++开发
- 幼儿也可以学习打太极?要注意什么
- 学习|119岁全球最长寿老人去世:生前最爱喝碳酸饮料 吃巧克力
- 比较出名的奶茶牌子,贵阳学习奶茶技术怎么样