SpringCloudAlibaba基础学习--SpringCloud Sentinel服务保护

  •   服务保护的基本概念
     
  1.  服务降级
           在高并发情况下,防止用户一直等待,使用服务降级方式,直接走本地falback的方法,返回一个友好的提示。 
     
  2. 服务限流 
           服务限流就是对接口访问进行限制,常用服务限流算法令牌桶、漏桶。计数器也可以进行粗暴限流实现。
     
  3. 服务熔断
           熔断机制目的为了保护服务,在高并发的情况下,如果请求达到一定极限(可以自己设置阔值)如果流量超出了设置阈值,让后直接拒绝访问,保护当前服务。使用服务降级的falback方法返回一个友好提示,服务熔断和服务降级一起使用 
     
  4. 服务的雪崩效应
            服务雪崩效应产生与服务堆积在同一个线程池中,因为所有的请求都是同一个线程池进行处理,这时候如果在高并发情况下,所有的请求全部访问同一个接口, 就会导致其他服务不可用
     
     
  5.  服务的隔离的机制
     一  线程池隔离
          每个服务接口都有自己独立的线程池,互不影响,缺点就是占用cpu资源非常大。
     
     二 信号量隔离
          设置每个服务接口处理线程数的阈值,超过该阈值会拒绝请求。
     
  6.   Sentinel介绍
          分布式系统的流量防卫兵,随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。  
     
     Sentinel 控制台(Dashboard)提供了机器发现、配置规则、查看实时监控、查看调用链路信息等功能,使得用户可以非常方便地去查看监控和进行配置。 
     
     github介绍:  https://github.com/alibaba/Sentinel/wiki 
     
  7.  Sentinel 具有以下特征:

    丰富的应用场景:
          Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。

    完备的实时监控:
           Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。

    广泛的开源生态:
           Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。

    完善的 SPI 扩展点:
           Sentinel 提供简单易用、完善的 SPI 扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等。

  8.    Sentinel 与hytrix区别
     
     
    #SentinelHystrix
    隔离策略信号量隔离线程池隔离/信号量隔离
    熔断降级策略基于响应时间或失败比率基于失败比率
    实时指标实现滑动窗口滑动窗口(基于 RxJava)
    规则配置支持多种数据源支持多种数据源
    扩展性多个扩展点插件的形式
    基于注解的支持支持支持
    限流基于 QPS,支持基于调用关系的限流不支持
    流量整形支持慢启动、匀速器模式不支持
    系统负载保护支持不支持
    控制台开箱即用,可配置规则、查看秒级监控、机器发现等不完善
    常见框架的适配Servlet、Spring Cloud、Dubbo、gRPCServlet、Spring Cloud Netflix

     

  •   Sentinel 环境搭建
  1.  下载jar包
     https://github.com/alibaba/Sentinel/releases
  2.  启动
    java -jar sentinel-dashboard-1.7.1.jar
  3.   测试
    访问:  http://127.0.0.1:8080   默认账号/密码:  sentinel/sentinel 
     此时是没有服务
     
  4.   安装成功,接下来项目整合
     
     
  •   项目整合
     
  1.   创建boot项目
     pom.xml引入依赖:
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
      </parent>
    
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
                <version>0.2.2.RELEASE</version>
            </dependency>
             <!-- Sentinel服务保护-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-alibaba-sentinel</artifactId>
                <version>0.2.2.RELEASE</version>
            </dependency>
        </dependencies>

     application.yml配置: 
    spring:
      application:
        ###服务的名称
        name: pitch-order
      cloud:
        nacos:
          discovery:
            ###nacos注册地址
            server-addr: 127.0.0.1:8848
        sentinel:
          transport:
            ### sentinel连接地址
            dashboard: 127.0.0.1:8080
          eager: true
    server:
      port: 8001
      tomcat:
        ### 最大线程数
        max-threads: 20

     

  2.   测试类
        // mySentinelName:流控规则资源则名称(自定义)  mySentinelException: 超过阈值执行的方法
        @SentinelResource(value="mySentinelName", blockHandler = "mySentinelException" )
        @GetMapping("/my-sentinel")
        public String mySentinel(){
            return "hello mySentinel";
        }
        
        public String mySentinelException(BlockException e) {
            e.printStackTrace();
            return "访问次数过多,请稍后重试!!!";
        }
    mySentinelName:   定义流控规则的资源名,如果没有指定默认未@GetMapping的value值   
    mySentinelException:  定义客户端访问超过阈值的执行方法  
      
    注意:  @SentinelResource也可以不用加 
  3.   启动类
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.openfeign.EnableFeignClients;
    
    /**
     * Hello world!
     *
     */
    @SpringBootApplication
    @EnableFeignClients
    public class AppOrder {
    
    
        public static void main( String[] args ){
            SpringApplication.run(AppOrder.class);
        }
    }
    

     
  4.   测试
     测试请求地址: http://127.0.0.1:8001/my-sentinel    
     
     查询sentinel控制台,此时pitch-order就存在了
  5.   配置隔离规则
     选择流控规则-->新增流控规则
     
     资源名: 为代码中@SentinelResource注解的value值,如果方法中没有加@SentinelResource则默认为@GetMapping的value值。 
     
     QPS&&单机阈值:表示该接口每秒只能访问5次,超过访问次数则执行mySentinelException方法
     线程数&&单机阈值:表示该接口最多只能有5个线程处理请求,多余的请求则执行mySentinelException方法
  6.   访问测试
     http://127.0.0.1:8001/my-sentinel
     
     
  7.   success
  1. 介绍 
           除了流量控制以外,对调用链路中不稳定的资源进行熔断降级也是保障高可用的重要措施之一。由于调用关系的复杂性,如果调用链路中的某个资源不稳定,最终会导致请求发生堆积。Sentinel 熔断降级会在调用链路中某个资源出现不稳定状态时(例如调用超时或异常比例升高),对这个资源的调用进行限制,让请求快速失败,避免影响到其它的资源而导致级联错误。当资源被降级后,在接下来的降级时间窗口之内,对该资源的调用都自动熔断(默认行为是抛出 DegradeException)。
     
  2. 降级策略 
     

    平均响应时间 (DEGRADE_GRADE_RT):当 1s 内持续进入 5 个请求,对应时刻的平均响应时间(秒级)均超过阈值(count,以 ms 为单位),那么在接下的时间窗口(DegradeRule 中的 timeWindow,以 s 为单位)之内,对这个方法的调用都会自动地熔断(抛出 DegradeException)。注意 Sentinel 默认统计的 RT 上限是 4900 ms,超出此阈值的都会算作 4900 ms,若需要变更此上限可以通过启动配置项 -Dcsp.sentinel.statistic.max.rt=xxx 来配置。

    异常比例 (DEGRADE_GRADE_EXCEPTION_RATIO):当资源的每秒请求量 >= 5,并且每秒异常总数占通过量的比值超过阈值(DegradeRule 中的 count)之后,资源进入降级状态,即在接下的时间窗口(DegradeRule 中的 timeWindow,以 s 为单位)之内,对这个方法的调用都会自动地返回。异常比率的阈值范围是 [0.0, 1.0],代表 0% - 100%。

    异常数 (DEGRADE_GRADE_EXCEPTION_COUNT):当资源近 1 分钟的异常数目超过阈值之后会进行熔断。注意由于统计时间窗口是分钟级别的,若 timeWindow 小于 60s,则结束熔断状态后仍可能再进入熔断状态。

  3. 测试代码
         @SentinelResource(value="myTimeOutName", blockHandler = "mySentinelException" )
        @GetMapping("/my-timeout")
        public String myTimeout(){
            try {
                Thread.sleep(300);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return "success";
        }
    
        public String mySentinelException(BlockException e) {
            e.printStackTrace();
            return "超时了!!!";
        }
  4. 配置RT降级规则
    登录sentinel,选择'降级规则'-->‘新增降级规则’
     
      
    RT&&10毫秒&&时间窗口5秒  表示:  该接口的方法如果平均响应时间超过10毫秒,则在5秒内都不会执行该接口,直接服务降级提示方法
     
     
  5. 测试
    频繁刷新: http://127.0.0.1:8001/my-timeout
     
     
  6. 其他降级规则 
      异常比例: 
      
     表示规定时间(每秒)内访问的异常超过配置的比例,则在规定的时间窗口不能再访问。
      
     异常数:  
     
      表示1分钟内访问接口的异常数超过配置的值,则在规定的时间窗口不能再访问。
     
  •   Sentinel持久化
     

    默认的情况下Sentinel的规则是存放在内存中,如果Sentinel客户端重启后,Sentinel数据规则可能会丢失。

    Sentinel持久化机制支持四种持久化的机制。
    1. 本地文件
    2. 携程阿波罗
    3. Nacos
    4. Zookeeper

     
  1.   项目配置
     pom.xml添加依赖
    <!--sentinel 持久化整合nacos -->
    <dependency>
       <groupId>com.alibaba.csp</groupId>
       <artifactId>sentinel-datasource-nacos</artifactId>
       <version>1.5.2</version>
    </dependency>
    application.yml配置如下: 
     
    spring:
      application:
        ###服务的名称
        name: pitch-order
      cloud:
        nacos:
          discovery:
            ###nacos注册地址
            server-addr: 127.0.0.1:8848
        sentinel:
          transport:
            ### sentinel连接地址
            dashboard: 127.0.0.1:8080
          eager: true
          ### sentinel通过nacos实现持久化配置
          datasource:
            ds:
              nacos:
                ### nacos连接地址
                server-addr: localhost:8848
                ## nacos连接的分组
                group-id: DEFAULT_GROUP
                ###路由存储规则
                rule-type: flow
                ### 读取nacos配置文件的 data-id  须对应
                data-id: pitch-order-sentinel
                ###  读取培训文件类型为json
                data-type: json
    
    server:
      port: 8001

      
  2. 代码   
        // test流控规则资源则名称(自定义)  mySentinelException: 超过阈值执行的方法
        @SentinelResource(value="mySentinelName", blockHandler = "mySentinelException" )
        @GetMapping("/my-sentinel")
        public String mySentinel(){
            return "hello mySentinel";
        }

     
  3. 启动nacos
     登录nacos-->'配置列表'-->'+'
    [
        {
            "resource": "mySentinelName",
            "limitApp": "default",
            "grade": 1,
            "count": 5,
            "strategy": 0,
            "controlBehavior": 0,
            "clusterMode": false
        }
    ]
    Data ID: 需要与application.yml的data-id一致
    resource:资源名,为代码中@SentinelResource注解的value值
    limitApp:流控针对的调用来源,若为 default 则不区分调用来源
    grade:限流阈值类型(QPS 或并发线程数);0: 并发数量来限流,1:QPS来进行流量控制
    count:限流阈值
    strategy:调用关系限流策略
    controlBehavior:流量控制效果(直接拒绝、Warm Up、匀速排队)
    clusterMode:是否为集群模式 
    选择 '发布' 
  4.   测试
     http://127.0.0.1:8001/my-sentinel
     
     
  1.   创建网关项目
     pom.xml依赖
     
     <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.0.5.RELEASE</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-gateway</artifactId>
                <version>2.0.0.RELEASE</version>
            </dependency>
            <!-- nacos整合服务注册与发现-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
                <version>0.2.2.RELEASE</version>
            </dependency>
            <!-- gateway整合sentinel-->
            <dependency>
                <groupId>com.alibaba.csp</groupId>
                <artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>
                <version>1.6.0</version>
            </dependency>
    
        </dependencies>

     application.yml配置
    server:
      port: 80
    ####服务网关名称
    spring:
      application:
        name: pitch-gateway
      cloud:
        gateway:
          discovery:
            locator:
              ####允许从注册中心获取地址
              enabled: true
          routes:
            ###路由id  自定义唯一
            - id: pitch
              ####pitch-member为会员服务的名称
              uri: lb://pitch-order/
              filters:
                - StripPrefix=1
              ###路由匹配规则
              predicates:
                - Path=/order/**
        nacos:
          discovery:
            ###将网关服务注册到nacos
            server-addr: 127.0.0.1:8848
            enabled: true

     

  2.   核心配置类
    import com.alibaba.csp.sentinel.adapter.gateway.sc.SentinelGatewayFilter;
    import org.springframework.beans.factory.ObjectProvider;
    import org.springframework.cloud.gateway.filter.GlobalFilter;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.core.Ordered;
    import org.springframework.core.annotation.Order;
    import org.springframework.http.codec.ServerCodecConfigurer;
    import org.springframework.web.reactive.result.view.ViewResolver;
    import java.util.Collections;
    import java.util.List;
    
    /**
     * @author xiaobo
     * @Description GatewayConfiguration
     * @createTime 2020-04-01 21:41
     */
    @Configuration
    
    public class GatewayConfiguration {
    
        private final List<ViewResolver> viewResolvers;
        private final ServerCodecConfigurer serverCodecConfigurer;
    
        public GatewayConfiguration(ObjectProvider<List<ViewResolver>> viewResolversProvider,
                                    ServerCodecConfigurer serverCodecConfigurer) {
            this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
            this.serverCodecConfigurer = serverCodecConfigurer;
        }
    
        // 配置sentinel超过阈值的异常处理
        @Bean
        @Order(Ordered.HIGHEST_PRECEDENCE)
        public JsonSentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
            JsonSentinelGatewayBlockExceptionHandler jsonSentinelGatewayBlockExceptionHandler = new JsonSentinelGatewayBlockExceptionHandler(null, null);
            return jsonSentinelGatewayBlockExceptionHandler;
        }
    
        @Bean
        @Order(Ordered.HIGHEST_PRECEDENCE)
        public GlobalFilter sentinelGatewayFilter() {
            return new SentinelGatewayFilter();
        }
    }
    异常处理handler
    import org.springframework.core.io.buffer.DataBuffer;
    import org.springframework.http.codec.ServerCodecConfigurer;
    import org.springframework.http.server.reactive.ServerHttpResponse;
    import org.springframework.web.reactive.result.view.ViewResolver;
    import org.springframework.web.server.ServerWebExchange;
    import org.springframework.web.server.WebExceptionHandler;
    import reactor.core.publisher.Mono;
    import java.nio.charset.StandardCharsets;
    import java.util.List;
    
    public class JsonSentinelGatewayBlockExceptionHandler implements WebExceptionHandler {
        public JsonSentinelGatewayBlockExceptionHandler(List<ViewResolver> viewResolvers, ServerCodecConfigurer serverCodecConfigurer) {
        }
    
        @Override
        public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
            ServerHttpResponse serverHttpResponse = exchange.getResponse();
            serverHttpResponse.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
            byte[] datas = "{\"code\":403,\"msg\":\"访问次数过多,请稍后重试!!!\"}".getBytes(StandardCharsets.UTF_8);
            DataBuffer buffer = serverHttpResponse.bufferFactory().wrap(datas);
            return serverHttpResponse.writeWith(Mono.just(buffer));
        }
    }
  3.   加载限流规则
     
    import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule;
    import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayRuleManager;
    import org.springframework.boot.ApplicationArguments;
    import org.springframework.boot.ApplicationRunner;
    import org.springframework.stereotype.Component;
    import java.util.HashSet;
    import java.util.Set;
    
    @Component
    public class SentinelApplicationRunner implements ApplicationRunner {
    
        @Override
        public void run(ApplicationArguments args) throws Exception {
            // 项目启动是加载
            initGatewayRules();
        }
    
        /**
         * 配置限流规则
         */
        private void initGatewayRules() {
            Set<GatewayFlowRule> rules = new HashSet<>();
            // pitch : 对应application.yml的路由策略(routes -id)
            rules.add(new GatewayFlowRule("pitch")
                    // 限流阈值
                    .setCount(1)
                    // 统计时间窗口,单位是秒,默认是 1 秒
                    .setIntervalSec(1)
            );
            GatewayRuleManager.loadRules(rules);
        }
    }
     
     
  4.   启动测试 
     
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    
    @SpringBootApplication
    public class AppGateway {
        public static void main( String[] args ) {
            SpringApplication.run(AppGateway.class);
        }
    }

     
  5.   测试
     浏览器多次访问
     

     
     
     

     
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值