美文网首页SpringCloud
sentinel之SpringCloudAlibaba服务集成

sentinel之SpringCloudAlibaba服务集成

作者: bear_small | 来源:发表于2021-08-31 17:16 被阅读0次

    引入依赖

    <!--Sentinel-->
    <!--和sentinel starter 配合使用 ,集成sentinel相关自动化配置依赖项-->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        <!--去除jackson-dataformat-xml,否则会返回xml文件,而不是JSON-->
        <exclusions>
            <exclusion>
                <groupId>com.fasterxml.jackson.dataformat</groupId>
                <artifactId>jackson-dataformat-xml</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <!--配置sentinel规则持久化至nacos依赖-->
    <dependency>
        <groupId>com.alibaba.csp</groupId>
        <artifactId>sentinel-datasource-nacos</artifactId>
    </dependency>
    <!--和sentinel starter 配合使用,集成sentinel网关控制相关自动化配置依赖项(仅网关模块才需要依赖)-->
    <dependency>
         <groupId>com.alibaba.cloud</groupId>
         <artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
    </dependency>
    

    关于依赖,普通服务引入 spring-cloud-starter-alibaba-sentinel, sentinel-datasource-nacos, 网关服务引入 spring-cloud-starter-alibaba-sentinel, sentinel-datasource-nacos, spring-cloud-alibaba-sentinel-gateway ,普通服务流控使用注解@SentinelResource,网关针对请求链路做流控

    普通资源流控

    自定义资源@SentinelResource,我们只需要在相关方法上加上@SentinelResource注解,让其可以成为sentinel识别的资源

    • 定义资源
      以下远程服务接口实现为简化实现方式,可直接实现远程服务接口,以实现类的方式做具体业务实现类,不必单独写控制层接口实现类

      • 远程服务接口部分
      @FeignClient(name = "user")
      public interface IUserRemote {
          @GetMapping("/user")
          R<UserVO> user(@RequestParam("userId") Integer userId);
      }
      
      • 远程服务接口业务实现部分
      @RestController
      @Slf4j
      public class UserRemote implements IUserRemote {
          @Resource
          private IUserService userService;
      
          @SentinelResource(value = "user")
          @Override
          public R<UserVO> user(@RequestParam("userId") Integer userId) {
              UserDetail user = userService.getUser(userId);
              UserVO userVO = new UserVO();
              BeanUtils.copyProperties(user,userVO,UserVO.class);
              return R.data(userVO);
          }
      }
      
    • sentinel-dashboard 控制台流控配置

      自定义资源流控配置@SentinelResource 如图
      将user的QPS单机阈值设置成5,如果每秒QPS超过5,直接丢弃。这里的资源名就是我们使用@SentinelResource注解自定义的资源
      触发流控会报出FlowException异常,这说明我们的目的达到了,限流成功
    • 我们大部分接口都是json形式的,此处对于流控部分做异常处理

    @RestController
    @Slf4j
    public class UserRemote implements IUserRemote {
        @Resource
        private IUserService userService;
    
        @SentinelResource(value = "user", blockHandler = "handlerException")
        @Override
        public R<UserVO> user(@RequestParam("userId") Integer userId) {
            UserDetail user = userService.getUser(userId);
            UserVO userVO = new UserVO();
            BeanUtils.copyProperties(user,userVO,UserVO.class);
            return R.data(userVO);
        }
    
        public R<UserVO> handlerException(Integer userId, BlockException exception){
            log.info("flow exception {}",exception.getClass().getCanonicalName());
            return R.fail(500,"请求过于频繁,稍后再试试!");
        }
    }
    

    注意,自定义的异常方法的参数和返回值要跟目标方法一样,参数追加BlockException

    • 使用持久化配置
      Sentinel配置默认是放在内存中的,每当应用重启或者sentinel重启都会丢失数据,这里使用Nacos作为配置中心持久化限流配置(见上一篇-sentinel之dashboard改造
    1. 修改bootstrap.yml,配置sentinel的数据源
    spring:
      application:
        name: user
      cloud:
        nacos:
          config:
            server-addr: ${star.nacos.ip}:${star.nacos.port}
            file-extension: yml
            namespace: ${star.nacos.namespace}
            group: ${star.nacos.group}
        sentinel:
          filter:
            enabled: false
          transport:
            dashboard: ${star.sentinel.ip}:${star.sentinel.port} # sentinel服务端地址
          enabled: true
          eager: true # 取消延迟加载
          datasource:
            # 名称随意
            flow: # 流控规则
              nacos:
                server-addr: ${star.nacos.ip}:${star.nacos.port}
                namespace: ${star.nacos.namespace}
                data-id: ${spring.application.name}-flow-rules
                group-id: ${star.sentinel.group}
                # 规则类型,取值见:
                # org.springframework.cloud.alibaba.sentinel.datasource.RuleType
                rule-type: flow
            degrade: # 降级规则
              nacos:
                server-addr: ${star.nacos.ip}:${star.nacos.port}
                namespace: ${star.nacos.namespace}
                data-id: ${spring.application.name}-degrade-rules
                group-id: ${star.sentinel.group}
                rule-type: degrade
            system: # 系统规则
              nacos:
                server-addr: ${star.nacos.ip}:${star.nacos.port}
                namespace: ${star.nacos.namespace}
                data-id: ${spring.application.name}-system-rules
                group-id: ${star.sentinel.group}
                rule-type: system
            authority: # 授权规则
              nacos:
                server-addr: ${star.nacos.ip}:${star.nacos.port}
                namespace: ${star.nacos.namespace}
                data-id: ${spring.application.name}-authority-rules
                group-id: ${star.sentinel.group}
                rule-type: authority
            param-flow: # 热点参数规则
              nacos:
                server-addr: ${star.nacos.ip}:${star.nacos.port}
                namespace: ${star.nacos.namespace}
                data-id: ${spring.application.name}-param-flow-rules
                group-id: ${star.sentinel.group}
                rule-type: param-flow
    

    配置项说明:
    datasource 下的名称是我自己起的一个名字,这一层名字可以随便起,要具有辨识性
    查看源码SentinelProperties的datasource属性
    datasource的类型为:Map<String, DataSourcePropertiesConfiguration> datasource,此处map的key为上面的flow等,value继续查看
    查看DataSourcePropertiesConfiguration,发现sentinel配置支持的限流配置文件数据源支持(file,nacos,zk,apollo,redis,consul
    我们使用nacos作为配置源,继续查看NacosDataSourceProperties,对应上图nacos下的配置项都为NacosDataSourceProperties里的属性

    1. sentinel-dashboard控制台增加流控规则,如图


      普通服务流控规则
    1. 运行查看结果生效
      我是用JMeter做了测试,会发现,并发情况下,流控效果并不会很精准,当然流控肯定是生效了,只是控制的结果不是预设的值,会存在一些偏差,具体原因呢,可以参考Sentinel并发限流不精确-之责任链 的博文说明,主要问题还是并发的原因
      附上流控过程中责任链的执行顺序
      责任链执行顺序

    网关流控

    sentinel-dashboard各类规则分为两种类型,根据属性appType确定:

    • 0: 普通服务
    • 1: Api Gateway 网关服务

    服务集成sentinel时默认是作为普通服务,此处网关需设置为网关服务,网关服务启动参数增加:
    -Dcsp.sentinel.app.type=1

    Sentinel对Spring Cloud Gateway限流的支持其实是一个全局的过滤器,使用过程中我们将全局过滤器注入到容器中,然后全局过滤器就会生效

    参数配置项
    spring:
      # 必须放在bootstrap中,放在application中不生效
      application:
        # 应用名
        name: gateway
      cloud:
        nacos:
          discovery:
            # 服务注册地址
            server-addr: ${star.nacos.ip}:${star.nacos.port}
            namespace: ${star.nacos.namespace}
            group: ${star.nacos.server.group}
            cluster-name: ${star.nacos.cluster}
            metadata:
              target-version: ${star.nacos.metadata.version}
          config:
            # 配置中心地址
            server-addr: ${star.nacos.ip}:${star.nacos.port}
            # namespace 的ID,区分部署环境
            namespace: ${star.nacos.namespace}
            # 分组 区分业务项目
            group: ${star.nacos.group}
            prefix: ${spring.application.name} #缺省值
            #文件后缀名     很根据本定文件名称拼接
            file-extension: yml
        gateway:
          discovery:
            locator:
              enabled: true #开启从注册中心动态创建路由的功能,利用微服务名称进行路由
              lower-case-service-id: true # 将服务名称转小写
              # routeId的前缀,不配置的话,默认以(discoveryClient.getClass().getSimpleName() + "_". Service Id)格式,结合sentinel使用时,sentinel控制台请求链路中api名称就是网关注册的routeId(不看也不影响功能就是)
              route-id-prefix: sisyphus_
          routes:
            - id: user #路由唯一标识
              uri: lb://user #从nacos进行转发,lb: 负载均衡
              predicates: #断言 配置哪个路径才转发
                - Path=/user/**
            - id: order
              uri: lb://order
              predicates:
                - Path=/order/**
        sentinel:
          filter:
            enabled: false # 网关流控控制台不展示URL资源,即不对gateway进行限流,我们只需要对网关下的服务进行限流
          transport:
            dashboard: ${star.sentinel.ip}:${star.sentinel.port}
          eager: true # 是否提前触发 Sentinel 初始化(取消延迟加载) 默认false
          datasource:
            gw-flow:
              nacos:
                server-addr: ${star.nacos.ip}:${star.nacos.port}
                namespace: ${star.nacos.namespace}
                data-id: ${spring.application.name}-gateway-flow-rules # 在修改的sentinel 源码中定义的规则名
                group-id: ${star.sentinel.group}
                rule-type: gw-flow
            gw-api-group:
              nacos:
                server-addr: ${star.nacos.ip}:${star.nacos.port}
                namespace: ${star.nacos.namespace}
                dataId: ${spring.application.name}-gateway-flow-rules # 在修改的sentinel 源码中定义的规则名
                group-id: ${star.sentinel.group}
                rule-type: gw-api-group
      main:
        #出现重名直接复写
        allow-bean-definition-overriding: true
    
    # Endpoint 支持(暴露的 endpoint 路径为 /actuator/sentinel),Sentinel Endpoint暴露的信息包括当前应用的所有规则信息、日志目录、当前实例的 IP,Sentinel Dashboard 地址,Block Page,应用与 Sentinel Dashboard 的心跳频率等等信息
    management:
      endpoints:
        web:
          exposure:
            include: "*"
    
    #开启Feign对Sentinel的支持
    feign:
      sentinel:
        enabled: true
    
    运行测试

    请求相关网关接口,此时请求链路会看到记录,我们在对应链路增加流控规则,如图:


    请求链路 流控规则

    多次请求接口查看情况

    实时监控
    以14:21:02数据观察接口,一秒钟内仅接收两个请求,其他全部拒绝,另外两个时间节点没有可比性,O了,达到我们要的效果
    其他事项说明

    请求网关任意接口,sentinel控制台,请求链路会出现如下


    img.png

    会发现带了一长串前缀 ReactiveCompositeDiscoveryClient_,原因呢,查询源码 DiscoveryLocatorProperties 如下:

    img_1.png

    意思呢是说,routeId的前缀默认为 discoveryClient.getClass().getSimpleName() + "_". Service Id ,如果你不设置呢,就会给拼接这一大串前缀


    解决方法呢,上面配置文件也说明过,即route-id-prefix,routeId的前缀,不配置的话,默认以(discoveryClient.getClass().getSimpleName() + "_". Service Id)格式,结合sentinel使用时,sentinel控制台请求链路中api名称就是网关注册的routeId(不看也不影响功能就是), 新增流控规则的时候Api名称是需要和请求链路部分匹配一致的,建议更改哈

    谢谢大家关注,点个赞呗~
    如需转载请标明出处,谢谢~~

    相关文章

      网友评论

        本文标题:sentinel之SpringCloudAlibaba服务集成

        本文链接:https://www.haomeiwen.com/subject/paqziltx.html