帶有Resilience4j斷路器的Spring雲閘道器 - rome

banq發表於2019-12-27

該文介紹如何利用Spring Cloud閘道器將resilience4j斷路器與閘道器後面的後端服務結合使用,方法如下:

整個程式碼示例在github中

需要向您的Spring Cloud Gateway應用程式新增以下依賴項,以啟用Resilience4j斷路器整合:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
    <groupId>io.github.resilience4j</groupId>
    <artifactId>resilience4j-spring-boot2</artifactId>
    <version>1.1.0</version>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-circuitbreaker-reactor-resilience4j</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>


後端服務路由配置,如下所示:

spring:
  application:
    name: gateway-service
  output.ansi.enabled: ALWAYS
  cloud:
    gateway:
      routes:
        - id: test-service-withResilient4j
          uri: http://localhost:8091
          predicates:
            - Path=/testService/**
          filters:
            - RewritePath=/testService/(?<path>.*), /$\{path}


現在,Spring Cloud斷路器starter允許您透過Customizer用法來配置Resilience4j斷路器定義,這是程式碼優先的方法(透過程式碼進行定製是預設優先,而不是透過配置定製),但是如果要對其從外部進行配置,這樣可以透過分散式配置服務從外部控制其配置,那麼就使用Resilience4j spring boot starter發揮作用,它使斷路器的外部SpringBoot配置成為可能。
Resilience4j的Spring Boot Starter將根據您的外部配置建立CircuitBreakerRegistery bean,然後您可以將其注入Spring Cloud Starter的resilience4j工廠以實現整合,就是這樣!
Resilience4j的外部配置將類似於:

resilience4j.circuitbreaker:
  configs:
    default:
      slidingWindowSize: 10
      minimumNumberOfCalls: 5
      permittedNumberOfCallsInHalfOpenState: 3
      automaticTransitionFromOpenToHalfOpenEnabled: true
      waitDurationInOpenState: 2s
      failureRateThreshold: 50
      eventConsumerBufferSize: 10
      recordExceptions:
        - org.springframework.web.client.HttpServerErrorException
        - java.io.IOException
      ignoreExceptions:
        - java.lang.IllegalStateException
    shared:
      slidingWindowSize: 100
      permittedNumberOfCallsInHalfOpenState: 30
      waitDurationInOpenState: 1s
      failureRateThreshold: 50
      eventConsumerBufferSize: 10
      ignoreExceptions:
        - java.lang.IllegalStateException
  instances:
    backendA:
      baseConfig: default
    backendB:
      slidingWindowSize: 10
      minimumNumberOfCalls: 10
      permittedNumberOfCallsInHalfOpenState: 3
      waitDurationInOpenState: 1s
      failureRateThreshold: 50
      eventConsumerBufferSize: 10


載入Resilience4j的斷路器登錄檔與Spring Cloud ReactiveResilience4JCircuitBreakerFactory之間的整合將如下進行:

@Bean
public ReactiveResilience4JCircuitBreakerFactory reactiveResilience4JCircuitBreakerFactory(CircuitBreakerRegistry circuitBreakerRegistry) {
    ReactiveResilience4JCircuitBreakerFactory reactiveResilience4JCircuitBreakerFactory = new ReactiveResilience4JCircuitBreakerFactory();
    reactiveResilience4JCircuitBreakerFactory.configureCircuitBreakerRegistry(circuitBreakerRegistry);
    return reactiveResilience4JCircuitBreakerFactory;
}


現在是時候測試該整合並檢視其工作原理:
  • 我們將使用模擬伺服器測試容器模擬透過閘道器提供的目標後端服務
  • 我們將存根一些回應
  • 然後觸發測試並監視日誌,以瞭解ciruitbreaker的反應以及偏離路線,您可以透過Resilience4j支援的指標暴露和事件獲取大量指標

新增以下依賴項以啟用模擬Mock伺服器的使用:

<dependency>
     <groupId>org.testcontainers</groupId>
     <artifactId>mockserver</artifactId>
     <version>1.12.3</version>
     <scope>test</scope>
 </dependency>
 <dependency>
     <groupId>org.mock-server</groupId>
     <artifactId>mockserver-client-java</artifactId>
     <version>3.10.8</version>
     <scope>test</scope>
 </dependency>


現在,您需要配置測試容器starup,並在模擬伺服器啟動後注入路由的自定義配置:

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
@RunWith(SpringRunner.class)
@ContextConfiguration(initializers = {GatewayCircuitBreakerTest.Initializer.class})
public class GatewayCircuitBreakerTest {
 
    private static final Logger LOGGER = LoggerFactory.getLogger(GatewayCircuitBreakerTest.class);
    private static MockServerContainer mockServerContainer;
 
    static {
        mockServerContainer = new MockServerContainer();
        mockServerContainer.start();
 
    }
 
    static class Initializer
            implements ApplicationContextInitializer<ConfigurableApplicationContext> {
        public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
            TestPropertyValues.of(
                    "spring.cloud.gateway.routes[0].id=test-service-withResilient4j",
                    "spring.cloud.gateway.routes[0].uri=" + mockServerContainer.getEndpoint(),
                    "spring.cloud.gateway.routes[0].predicates[0]=" + "Path=/testService/**",
                    "spring.cloud.gateway.routes[0].filters[0]=" + "RewritePath=/testService/(?<path>.*), /$\\{path}",
                    "spring.cloud.gateway.routes[0].filters[1].name=" + "CircuitBreaker",
                    "spring.cloud.gateway.routes[0].filters[1].args.name=" + "backendA",
                    "spring.cloud.gateway.routes[0].filters[1].args.fallbackUri=" + "forward:/fallback/testService"
            ).applyTo(configurableApplicationContext.getEnvironment());
        }
    }
 
    private MockServerClient client = new MockServerClient(mockServerContainer.getContainerIpAddress(), mockServerContainer.getServerPort());
    @Autowired
    private TestRestTemplate template;
 
    @AfterClass
    public static void close(){
        mockServerContainer.close();
    }
}


最後,您可以在類GatewayCircuitBreakerTest中觸發受保護端點的測試,並透過分析控制檯中報告的事件來檢視它正在透過Resilience4j斷路器.

 

相關文章