docker 安装sentinel

docker run -d -p 8858:8858 \
--name sentinel-dashboard \
-e AUTH_USERNAME=sentinel \
-e AUTH_PASSWORD=sentinel \
-e NACOS_SERVER_ADDR=192.168.16.161:8848 \
bladex/sentinel-dashboard:latest

pom 依赖

<!-- 容错 sentinel -->
<dependency>
	<groupId>com.alibaba.cloud</groupId>
	<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

<!--    sentinel核心库    -->
<dependency>
	<groupId>com.alibaba.csp</groupId>
	<artifactId>sentinel-core</artifactId>
	<version>1.8.4</version>
</dependency>
<!--    如果要使用@SentinelResource必须添加此依赖    -->
<dependency>
	<groupId>com.alibaba.csp</groupId>
	<artifactId>sentinel-annotation-aspectj</artifactId>
	<version>1.8.4</version>
</dependency>
<!--    整合sentinel控制台    -->
<dependency>
	<groupId>com.alibaba.csp</groupId>
	<artifactId>sentinel-transport-simple-http</artifactId>
	<version>1.8.4</version>
</dependency>
<!--sentinel配置持久化到nacos所需依赖-->
<dependency>
	<groupId>com.alibaba.csp</groupId>
	<artifactId>sentinel-datasource-nacos</artifactId>
	<version>1.8.4</version>
</dependency>

<!-- 监控 -->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

<!-- 集群限流 -->
<dependency>
	<groupId>com.alibaba.csp</groupId>
	<artifactId>sentinel-cluster-client-default</artifactId>
	<version>1.8.4</version>
</dependency>

<dependency>
	<groupId>com.alibaba.csp</groupId>
	<artifactId>sentinel-cluster-server-default</artifactId>
	<version>1.8.4</version>
</dependency>

application.yml配置

spring:
  application:
    name: sys
  cloud:
    sentinel:
      enabled: true
      transport:
        port: 8730
        dashboard: 192.168.16.161:8858
        # client-ip 服务器ip
        client-ip: 127.0.0.1
      datasource:
        ds1:
          nacos:
            server-addr: 192.168.16.161:8848
            data-id: ${spring.application.name}-sentinel-rules
            namespace: c157a644-7f46-4a63-9c81-25e890f15736
            group-id: DEFAULT_GROUP
            data-type: json
            rule-type: flow
			
启动脚本
	
clientip=`ifconfig -a|grep inet|grep -v $*.0.1|grep -v inet6|awk '{print $2}'|tr -d "addr:"`
echo "-------clientip $clientip--------"
nohup java -jar -Xms512M -Xms512M -XX:PermSize=512M -XX:MaxPermSize=512M $PWD/$jar*.jar --spring.profiles.active=prod --spring.cloud.sentinel.transport.client-ip=$clientip >/dev/null 2>&1 &
echo "$jar restart success"


nacos配置

  • QPS 非集群
[
    {
    	"app":"service-sys",
        "resource": "/verification/send",
        "count": 10,
        "grade": 1,
        "limitApp": "default",
        "strategy": 0,
        "controlBehavior": 0,
        "clusterMode" :  true,
        "clusterConfig" : {
            "flowId" : 901,
            "thresholdType" : 1,
            "fallbackToLocalWhenFail" : true
        }
    },
    {
    	"app":"service-sys",
        "resource": "/captcha/get",
        "count": 10,
        "grade": 1,
        "limitApp": "default",
        "strategy": 0,
        "controlBehavior": 0,
        "clusterMode" :  true,
        "clusterConfig" : {
            "flowId" : 902,
            "thresholdType" : 1,
            "fallbackToLocalWhenFail" : true
        }
    }
]

  • 集群阀值

resource API 名称 count QPS 阀值 intervalSec 秒

[
  {
    "resource": "service-tenant",
    "resourceMode": 0,
    "count": 1000,
    "intervalSec": 1
  },
  {
    "resource": "service-sys",
    "resourceMode": 0,
    "count": 1000,
    "intervalSec": 1
  }
  ,
  {
    "resource": "service-auth",
    "resourceMode": 0,
    "count": 1000,
    "intervalSec": 1
  }
  ,
  {
    "resource": "service-user",
    "resourceMode": 0,
    "count": 1000,
    "intervalSec": 1
  }
]

自定义@SentinelResource 使用

  • Handler异常的返回方法要和Controller 方法一样
@Slf4j
@Service
public class TestService {

    // 限流与阻塞处理
    @SentinelResource(value = "doSomeThing", blockHandler = "exceptionHandler")
    public void doSomeThing(String str) {
        log.info(str);
    }

    public void exceptionHandler(String str, BlockException ex) {
        log.error("blockHandler:" + str, ex);
    }

    // 熔断与降级处理
    @SentinelResource(value = "doSomeThing2", fallback = "fallbackHandler")
    public void doSomeThing2(String str) {
        log.info(str);
        throw new RuntimeException("发生异常");
    }

    public void fallbackHandler(String str) {
        log.error("fallbackHandler:" + str);
    }
}

全局异常

@Configuration
public class SysBlockExceptionHandler implements BlockExceptionHandler {
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {
        throw new AppBusinessException("S01000", "您操作行为异常,请稍后再试");
//        String json = "{\"code\": -1, \"data\": null, \"message\": \"行为验证码异常,请稍后再试\"}";
//        response.setHeader("Content-Type", "application/json;charset=UTF-8");
//        response.getWriter().write(JSONUtil.toJsonStr(json));
    }
}

sentinel gateway 使用

<!--    sentinel核心库    -->
<dependency>
	<groupId>com.alibaba.csp</groupId>
	<artifactId>sentinel-core</artifactId>
	<version>1.8.4</version>
</dependency>

<dependency>
	<groupId>com.alibaba.cloud</groupId>
	<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

<!-- https://mvnrepository.com/artifact/com.alibaba.cloud/spring-cloud-alibaba-sentinel-gateway -->
<dependency>
	<groupId>com.alibaba.cloud</groupId>
	<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
	<version>2.2.1.RELEASE</version>
</dependency>

<dependency>
	<groupId>com.alibaba.csp</groupId>
	<artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>
	<version>1.8.4</version>
</dependency>
<dependency>
	<groupId>com.alibaba.csp</groupId>
	<artifactId>sentinel-transport-simple-http</artifactId>
	<version>1.8.4</version>
</dependency>
<!-- sentilen用 nacos 做 持久化-->
<!-- https://mvnrepository.com/artifact/com.alibaba.csp/sentinel-datasource-nacos -->
<dependency>
	<groupId>com.alibaba.csp</groupId>
	<artifactId>sentinel-datasource-nacos</artifactId>
	<version>1.8.4</version>
</dependency>

gateway 全局限流配置

@Configuration
public class SysGatewayConfiguration {

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

    public SysGatewayConfiguration(ObjectProvider<List<ViewResolver>> 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 SysSentinelGatewayBlockExceptionHandler(viewResolvers,serverCodecConfigurer);
    }

    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public GlobalFilter sentinelGatewayFilter() {
        return new SentinelGatewayFilter();
    }
}


public class SysSentinelGatewayBlockExceptionHandler extends SentinelGatewayBlockExceptionHandler {

    private List<ViewResolver> viewResolvers;
    private List<HttpMessageWriter<?>> messageWriters;
    public SysSentinelGatewayBlockExceptionHandler(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 -> {
            try {
                return writeResponse(response, serverWebExchange);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        });
    }
    private Mono<ServerResponse> handleBlockedRequest(ServerWebExchange exchange, Throwable throwable) {
        return GatewayCallbackManager.getBlockHandler().handleRequest(exchange, throwable);
    }

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

        @Override
        public List<ViewResolver> viewResolvers() {
            return SysSentinelGatewayBlockExceptionHandler.this.viewResolvers;
        }
     };

    private Mono<Void> writeResponse(ServerResponse response, ServerWebExchange exchange) throws Exception {
        //throw new Exception("您操作行为异常,请稍后再试");
        ServerHttpResponse resp = exchange.getResponse();
        resp.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
        String json = "{\"code\": -1, \"data\": null, \"message\": \"您操作行为异常,请稍后再试\"}";
        DataBuffer buffer = resp.bufferFactory().wrap(json.getBytes(StandardCharsets.UTF_8));
        return resp.writeWith(Mono.just(buffer));
    }
}