Persistent configuration of Sentinel

In the previous chapter we used Dashboard to set up various rules for the Sentinel client, but these rules are stored in memory by default and are too unstable to be used in a build environment, so they need to be persisted.

Common implementations of the DataSource extension are:

  • Pull mode: Clients regularly poll pull rules to a rule manager, such as RDBMS, files, or even VCS. The way to do this is simple, but the disadvantage is that changes cannot be captured in a timely manner;
  • Push mode: the rule center pushes the rules uniformly, and the client monitors the changes constantly by registering listeners, such as using Nacos and Zookeeper configuration centers. This method has better real-time performance and consistency assurance.

Sentinel currently supports the following data source extensions:

  • Pull-based: file, Consul
  • Push-based: ZooKeeper, Redis, Nacos, Apollo, etcd

Push patterns are commonly used in production environments. Here we use Nacos to store rules. The correct way to push mode should be to configure the central console /Sentinel console → configure the center → Sentinel data source → Sentinel.

1.1 Synchronization nacOS configuration for Sentinel

  1. Add sentinel dependencies and NACOS storage extension dependencies
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
Copy the code
  1. Add nacOS-related configurations
spring:
  cloud:
    sentinel:
      datasource:
        # Arbitrary name
        javatrip:
          nacos:
            server-addr: 127.0. 01.: 8848
            dataId: ${spring.application.name}-rules
            groupId: SENTINEL_GROUP
            # The rule type can be:
            # org.springframework.cloud.alibaba.sentinel.datasource.RuleType
            rule-type: flow
Copy the code
  1. Provides interfaces for testing traffic limiting
@RestController
class test{

    @RequestMapping("/test")
    public String test(a){
        return "Java journey"; }}Copy the code
  1. Added the configuration of traffic limiting rules in nacOS

  • Resource: indicates the name of the resource, which is the object of the traffic limiting rule
  • LimitApp: call source of flow control. If it is default, call source is not differentiated
  • Grade: indicates the type of traffic limiting threshold (QPS or number of concurrent threads).0Represents limiting traffic according to the number of concurrent requests,1Represents flow control according to QPS
  • Count: traffic limiting threshold
  • Strategy: Invokes the relational traffic limiting policy
  • ControlBehavior: Flow control effect (direct reject, Warm Up, uniform queuing)
  • ClusterMode: indicates whether the clusterMode is used
  1. Test. Access the Test interface and find a flow control rule in Sentinel-Dashboard

1.2 Modify rules to synchronize to NACOS in Sentinel-Dashboard

To change the rules in Sentinel-Dashboard and synchronize to NACOS, we need to change the Sentinel service. First we went to the Sentinel website to download Sentinel.

  1. Example Modify poM files
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
    <scope>test</scope>
</dependency>
Copy the code

Comment out test, because this applies to the test directory.

<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
    <! --<scope>test</scope>-->
</dependency>
Copy the code
  1. findsentinel-dashboard/src/test/java/com/alibaba/csp/sentinel/dashboard/rule/nacosDirectory to copy the entire directory tosentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/rule/.
  2. findcom.alibaba.csp.sentinel.dashboard.controller.v2.FlowControllerV2Change the default dynamic rules to NACOS dynamic rules.
@Autowired
@Qualifier("flowRuleDefaultProvider")
private DynamicRuleProvider<List<FlowRuleEntity>> ruleProvider;
@Autowired
@Qualifier("flowRuleDefaultPublisher")
private DynamicRulePublisher<List<FlowRuleEntity>> rulePublisher;
Copy the code

Is amended as:

@Autowired
@Qualifier("flowRuleNacosProvider")
private DynamicRuleProvider<List<FlowRuleEntity>> ruleProvider;
@Autowired
@Qualifier("flowRuleNacosPublisher")
private DynamicRulePublisher<List<FlowRuleEntity>> rulePublisher;
Copy the code
  1. findsentinel-dashboard/src/main/webapp/resources/app/scripts/directives/sidebar/sidebar.html

Comment out the following

<! --<li ui-sref-active="active" ng-if="entry.appType==0">-->
    <! --<a ui-sref="dashboard.flow({app: entry.app})">-->
    	<! --<i class="glyphicon glyphicon-filter"></i>&nbsp; &nbsp; Flow control rule V1</a>
<! --</li>-->
Copy the code
  1. Recompile the package and run the packaged Sentinel-dashboard.jar.

  2. To test, we removed the traffic rule configuration in NACOS

  • Added a new rule in Sentinel-Dashboard — > Traffic rule V1.

  • Refresh nacOS and find one more configuration

  • Modify this configuration in NACOS to change the threshold to 1

  • Refresh sentinel-Dashboard, flow threshold changed to 1.

  • Restart the service and restart the Sentinel-Dashboard. The flow control rules still exist.

Note: This is just a demonstration of the persistence of flow control rules. Sentinel also supports other rules. If you want to implement any of these rules, you can implement them the same way!

Gateway Traffic limiting of the Gateway

Flow limiting: A customized fast response to a large number of requests, applied to the service provider itself.

Beginning with version 1.6.0, Sentinel provides adaptive modules for Spring Cloud Gateway, which can provide flow limiting for two resource dimensions:

  • Route dimension: the route entry configured in the Spring configuration file with the corresponding routeId resource name
  • Custom API dimensions: Users can customize some API groups using the API provided by Sentinel
  1. Add the dependent
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>
    <version>x.y.z</version>
</dependency>
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-transport-simple-http</artifactId>
</dependency>
Copy the code
  1. Inject correspondingSentinelGatewayFilterInstances andSentinelGatewayBlockExceptionHandlerInstance.
@Configuration
public class GatewayConfiguration {

    private final List<ViewResolver> viewResolvers;
    private final ServerCodecConfigurer serverCodecConfigurer;

    public GatewayConfiguration(ObjectProvider
       
        > viewResolversProvider, ServerCodecConfigurer serverCodecConfigurer)
        {
        this.viewResolvers=viewResolversProvider.getIfAvailable(Collections::emptyList);
        this.serverCodecConfigurer = serverCodecConfigurer;
    }

    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler(a) {
        // Register the block exception handler for Spring Cloud Gateway.
        return new MySentinelGatewayBlockExceptionHandler(viewResolvers,serverCodecConfigurer);
    }

    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public GlobalFilter sentinelGatewayFilter(a) {
        return newSentinelGatewayFilter(); }}Copy the code
  1. Custom exception handling
public class MySentinelGatewayBlockExceptionHandler extends SentinelGatewayBlockExceptionHandler {

    private List<ViewResolver> viewResolvers;
    privateList<HttpMessageWriter<? >> messageWriters;public MySentinelGatewayBlockExceptionHandler(List<ViewResolver> viewResolvers, ServerCodecConfigurer serverCodecConfigurer) {
        super(viewResolvers,serverCodecConfigurer);
        this.viewResolvers = viewResolvers;
        this.messageWriters = serverCodecConfigurer.getWriters();
    }
    @Override
    public Mono<Void> handle(ServerWebExchange serverWebExchange, Throwable throwable) {

        if(serverWebExchange.getResponse().isCommitted()){
            return Mono.error(throwable);
        }
        if(! BlockException.isBlockException(throwable)){return Mono.error(throwable);
        }
        return handleBlockedRequest(serverWebExchange, throwable).flatMap(response -> writeResponse(response, serverWebExchange));
    }
    private Mono<ServerResponse> handleBlockedRequest(ServerWebExchange exchange, Throwable throwable) {
        return GatewayCallbackManager.getBlockHandler().handleRequest(exchange, throwable);
    }

    private final Supplier<ServerResponse.Context> contextSupplier = () -> new ServerResponse.Context() {
        @Override
        publicList<HttpMessageWriter<? >> messageWriters() {return MySentinelGatewayBlockExceptionHandler.this.messageWriters;
        }

        @Override
        public List<ViewResolver> viewResolvers(a) {
            return MySentinelGatewayBlockExceptionHandler.this.viewResolvers; }};private Mono<Void> writeResponse(ServerResponse response, ServerWebExchange exchange) {
        ServerHttpResponse resp = exchange.getResponse();
        resp.getHeaders().add("Content-Type"."application/json; charset=UTF-8");
        String json = "{\" code \ ": 1, \" data \ ": null, \" MSG \ ": \" traffic is too big, please try again later \ "}";
        DataBuffer buffer = resp.bufferFactory().wrap(json.getBytes(StandardCharsets.UTF_8));
        returnresp.writeWith(Mono.just(buffer)); }}Copy the code
  1. Configure the routing
server:
  port: 7003
spring:
  application:
    name: alibaba-gateway
  cloud:
    nacos:
      discovery:
        server-addr: 127.0. 01.: 8848
    gateway:
      enabled: true
      discovery:
        locator:
          enabled: true # enable dynamic route creation from registry using microservice names
      routes:
      - id: sentinel-nacos # Route ID. It is recommended to match the service name
        uri: lb://sentinel-nacos # Match the route name
        predicates:
          - Path=/sentinel/** # assert that the path matches the route
        filters:
          - StripPrefix=1
Copy the code
  1. Add startup Parameters
-Dcsp.sentinel.app.type=1 -Dcsp.sentinel.dashboard.server=localhost:8081 -Dproject.name=alibaba-gateway
Copy the code

  1. Access the interface to see the effect

Feign call to achieve fuse downgrading

Degradation: The service is broken, so the degradation logic should be applied to the consumer (caller), adding the service provider itself is meaningless because the service is disconnected.

We configured degradation rules in Sentinel-Dashboard based on actual requirements and then wrote the code.

  1. Defines the interface
@RequestMapping("/test")
public String test(a){
    return "Java journey";
}
Copy the code
  1. Define the remote service invocation interface
@FeignClient(name = "nacos-sentinel",fallback = RmoteTestFallback.class)
interface RemoteTest{
    @RequestMapping("/test")
    public String test(a);
}
Copy the code

For short fallback, we tend to use fallbackFactory = RmoteTestFallbackFactory. Class

@FeignClient(name = "nacos-sentinel",fallbackFactory = RmoteTestFallbackFactory.class)
interface RemoteTest{
    @RequestMapping("/test")
    public String test(a);
}
Copy the code
  1. Service degradation processing fallback
@Component
class RmoteTestFallback implements RemoteTest{
    @Override
    public String test(a) {
        return null; }}Copy the code
  1. Service degradation processing fallbackFactory
@Component
class RmoteTestFallbackFactory implements FallbackFactory<RemoteTest> {
    @Override
    public RemoteTest create(Throwable throwable) {
        return null; }}Copy the code