Spring cloud Alibaba series (6) practical application of sentinel

Time:2021-5-8

1、 Persistent configuration of sentinel

In the previous chapter, we used dashboard to set various rules for sentinel clients, but these rules are stored in memory by default, which is extremely unstable and cannot be used in the generation environment, so we need to persist them.

DataSourceThe common implementation methods of extension are as follows:

  • Pull mode: the client takes the initiative to poll and pull rules from a rule management center, which can be RDBMS, files, or even VCs. The way to do this is simple, but the disadvantage is that we can’t get the change in time;
  • Push mode: the rule center pushes the rules uniformly, and the client monitors the changes all the time by registering the listener, such as using theNacosAnd zookeeper. This method has better real-time and consistency guarantee.

Sentinel currently supports the following data source extensions:

In the production environment, it is commonly usedPush mode. Here we use the Nacos storage rule. The correct way of push mode should beConfiguration center console / sentinel console → configuration center → sentinel data source → Sentinel

1.1 sentinel synchronous Nacos configuration

  1. Increase the dependency of sentinel and Nacos storage expansion
com.alibaba.cloud
    spring-cloud-starter-alibaba-sentinel


    com.alibaba.csp
    sentinel-datasource-nacos


    org.springframework.boot
    spring-boot-starter-web
  1. Add Nacos related configuration
spring:
  cloud:
    sentinel:
      datasource:
        #Name at will
        javatrip:
          nacos:
            server-addr: 127.0.0.1:8848
            dataId: ${spring.application.name}-rules
            groupId: SENTINEL_GROUP
            #For rule type, please refer to:
            # org.springframework.cloud.alibaba.sentinel.datasource.RuleType
            rule-type: flow
  1. Provide interface for testing current limiting
@RestController
class test{

    @RequestMapping("/test")
    public String test(){
        Return "Java journey";
    }
}
  1. Configuration of adding current limiting rules in Nacos

  • Resource: the name of the resource, which is the object of the current limiting rule
  • Limitapp: call source for flow control. If it is default, call source will not be distinguished
  • Grade: current limiting threshold type (QPS or number of concurrent threads);0Represents to limit the current according to the number of concurrencies,1The representative controls the flow according to QPS
  • Count: current limiting threshold
  • Strategy: call relation current limiting strategy
  • Controlbehavior: flow control effect (direct rejection, warm up, uniform queuing)
  • Clustermode: cluster mode
  1. After testing and accessing the test interface, it is found that a flow control rule appears in sentinel dashboard

1.2 synchronization of modifying rules in sentinel dashboard to Nacos

In order to modify rules in sentinel dashboard and synchronize to Nacos, we need to modify sentinel services. First of all, let’s goOfficial websiteDownload sentinel.

  1. Modify POM file
com.alibaba.csp
    sentinel-datasource-nacos
    test

taketestComment it out, because it is used in the test directory.

com.alibaba.csp
    sentinel-datasource-nacos
  1. findsentinel-dashboard/src/test/java/com/alibaba/csp/sentinel/dashboard/rule/nacosDirectory, copy the entire directory to sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/rule/
  2. findcom.alibaba.csp.sentinel.dashboard.controller.v2.FlowControllerV2To change the default dynamic rule to Nacos dynamic rule.
@Autowired
@Qualifier("flowRuleDefaultProvider")
private DynamicRuleProvider> ruleProvider;
@Autowired
@Qualifier("flowRuleDefaultPublisher")
private DynamicRulePublisher> rulePublisher;

To be amended as follows:

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

Remove the following comments

  1. Recompile the package and run the packaged sentinel-dashboard.jar.

  2. Test, we delete the traffic rule configuration in Nacos

  • Add 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 the sentinel dashboard and change the flow threshold to 1.

  • Restart the service, restart sentinel dashboard, and find that the flow control rules still exist.

Note: the above only demonstrates the persistence of flow control rules. Sentinel also supports other rules. If you want to implement any rule, you can implement it in the same way!

2、 Gateway current limiting

Current limiting: when there are too many requests, a customized fast response processing is applied to the service provider itself.

Starting from version 1.6.0, sentinel provides the adaptation module of spring cloud gateway, which can provide two resource dimensions of current limiting

  • Route dimension: the route entry configured in the spring configuration file. The resource name is the corresponding route ID
  • User defined API dimension: users can use the API provided by sentinel to define some API groups
  1. Add dependency
com.alibaba.csp
    sentinel-spring-cloud-gateway-adapter
    x.y.z


    com.alibaba.csp
    sentinel-transport-simple-http
  1. Inject the correspondingSentinelGatewayFilterExamples andSentinelGatewayBlockExceptionHandlerexample.
@Configuration
public class GatewayConfiguration {

    private final List 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() {
        // Register the block exception handler for Spring Cloud Gateway.
        return new MySentinelGatewayBlockExceptionHandler(viewResolvers,serverCodecConfigurer);
    }

    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public GlobalFilter sentinelGatewayFilter() {
        return new SentinelGatewayFilter();
    }
}
  1. Custom exception handling
public class MySentinelGatewayBlockExceptionHandler extends SentinelGatewayBlockExceptionHandler {

    private List viewResolvers;
    private List> messageWriters;
    public MySentinelGatewayBlockExceptionHandler(List viewResolvers, ServerCodecConfigurer serverCodecConfigurer) {
        super(viewResolvers,serverCodecConfigurer);
        this.viewResolvers = viewResolvers;
        this.messageWriters = serverCodecConfigurer.getWriters();
    }
    @Override
    public Mono 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 handleBlockedRequest(ServerWebExchange exchange, Throwable throwable) {
        return GatewayCallbackManager.getBlockHandler().handleRequest(exchange, throwable);
    }

    private final Supplier contextSupplier = () -> new ServerResponse.Context() {
        @Override
        public List> messageWriters() {
            return MySentinelGatewayBlockExceptionHandler.this.messageWriters;
        }

        @Override
        public List viewResolvers() {
            return MySentinelGatewayBlockExceptionHandler.this.viewResolvers;
        }
     };

    private Mono 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 \ ": \" too many visits, please try again later \ "}";
        DataBuffer buffer = resp.bufferFactory().wrap(json.getBytes(StandardCharsets.UTF_8));
        return resp.writeWith(Mono.just(buffer));
    }
}
  1. Configure routing
server:
  port: 7003
spring:
  application:
    name: alibaba-gateway
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    gateway:
      enabled: true
      discovery:
        locator:
          Enabled: true # enables the function of dynamically creating a route from the registry, and uses the microservice name to route
      routes:
      -ID: sentinel Nacos # routing ID, it is recommended to match the service name
        Uri: LB: // sentinel Nacos # match route name
        predicates:
          -Path = / sentinel / * # assertion, route if path matches
        filters:
          - StripPrefix=1
  1. Add startup parameters
-Dcsp.sentinel.app.type=1 -Dcsp.sentinel.dashboard.server=localhost:8081 -Dproject.name=alibaba-gateway

  1. Visit the interface to see the effect

3、 Using feign call to realize fuse degradation

DemotionThe service crashed, soDemotion logic should be applied to consumers (callers)It makes no sense to add to the service provider itself, because the service has been disconnected.

We configure the degradation rules in sentinel dashboard according to the actual needs, and then write the code.

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

To abbreviate fallback, we prefer fallbackfactory = rmotetestfallbackfactory. Class

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

Recommended Today

Looking for frustration 1.0

I believe you have a basic understanding of trust in yesterday’s article. Today we will give a complete introduction to trust. Why choose rust It’s a language that gives everyone the ability to build reliable and efficient software. You can’t write unsafe code here (unsafe block is not in the scope of discussion). Most of […]