本次最佳实践将为您介绍如何使用Sentinel对微服务的限流降级。

背景信息

  • 场景描述:

    Hystrix通过代码注入的形式实现应用的熔断降级功能,而Sentinel只需要导入一个SDK,无需业务代码中添加限流降级注解或代码块,无侵入式的实现对微服务的限流降级。

  • Sentinel特征:
    • 丰富的应用场景:

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

    • 完备的实时监控:

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

    • 广泛的开源生态:

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

    • 完善的SPI扩展点:

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

  • 最佳实践价值:

    在微服务场景中,由于微服务调用的复杂性,希望尽量减少代码的修改,并且希望以可视化的形式对微服务进行管理。因此使用Sentinel实现限流降级功能变得恰当且友好,不仅简化了开发人员的开发工作,对于运维人员管理微服务的限流降级也更容易,同时对微服务应用的限流降级配置规则也可以在控制台修改,无需对代码的改动,减小微服务部署重启等对业务有重大影响的操作。

迁移指导

  1. Spring Cloud请求熔断迁移至Sentinel。因Sentinel无代码侵入,所以不需要修改业务代码,
    1. 在使用Hystrix工程中找到熔断的依赖及代码块,替换maven工程中pom.xml文件的导入依赖包。

      Spring Cloud Hystrix的pom.xml文件的配置:

      <dependency>
             <groupId>org.springframework.cloud</groupId>
             <artifactId>spring-cloud-starter-hystrix</artifactId>
      </dependency>

      Spring Cloud Sentinel的pom.xml的文件配置:

      <dependency>
             <groupId>com.alibaba.cloud</groupId>
             <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
      </dependency>
    2. 微服务新增熔断机制。

      Hystrix熔断机制注解@HystrixCommand:

      @RequestMapping(value = "/dept/get/{id}", method = RequestMethod.GET)
      //一旦调用服务方法失败并抛出了错误信息后,会自动调用@HystrixCommand标注好的fallbackMethod调用类中的指定方法
      @HystrixCommand(fallbackMethod = "processHystrix_Get")
      public Dept get(@PathVariable("id") Long id) 
      {
      
                    Dept dept = this.deptService.get(id);
      
                    if (null == dept) {
                           throw new RuntimeException("该ID:" + id + "没有没有对应的信息");
                    }
                    return dept;
      }
      
      public Dept processHystrix_Get(@PathVariable("id") Long id)
      {
                    Dept dept = new Dept();
                    dept.setDeptno(id);
                    dept.setDname("该ID:" + id + "没有没有对应的信息,null--@HystrixCommand");
                    dept.setDb_source("no this database in MySQL");
                    return dept;
      }
    3. Spring Cloud Hystrix应用主程序类添加注解@EnableCircuitBreaker。

      Hystrix启动类注解:

      @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class,HibernateJpaAutoConfiguration.class})
      @MapperScan(basePackages="com.poc.springcloud.dao")
      @EnableEurekaClient
      //@EnableDiscoveryClient  //服务发现
      @EnableCircuitBreaker
      //对Hystrix熔断机制支持
      public class DeptProvider_App {
      
             public static void main(String[] args) {
                    SpringApplication.run(DeptProvider8001_App.class,args);
             }
      }
    4. 登录Sentinel控制台。
    5. 在左侧导航栏单击簇点链路
    6. 簇点链路页面,找到想要操作的资源,单击操作栏中的流控
      流控
  2. Spring Cloud服务降级迁移至Sentinel。
    说明 服务降级:整体资源快不够用时,将某些服务先关掉,当可用资源恢复后再开启。所谓降级,就是从整体考虑,当某个服务熔断之后,服务器将不再被调用,此刻客户端可以自己准备一个本地的Fallback回调,返回一个默认值,即使短期内使服务水平下降,但可以将服务器一直维持在可用状态。
    1. 在使用Hystrix工程中找到服务降级的依赖及代码块,替换pom.xml文件的导入依赖包。
      Spring Cloud Hystrix的pom.xml文件的配置:
      <dependency>
             <groupId>org.springframework.cloud</groupId>
             <artifactId>spring-cloud-starter-hystrix</artifactId>
      </dependency>

      Spring Cloud Sentinel的pom.xml的文件配置:

      <dependency>
             <groupId>com.alibaba.cloud</groupId>
             <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
      </dependency>
    2. 微服务新增服务降级处理类。

      Service接口实现一个FallbackFactory接口类DeptClientServiceFallbackFactory。

      Spring Cloud Hystrix的DeptClientServiceFallbackFactory实现代码:

      @Component // 不要忘记添加
      public class DeptClientServiceFallbackFactory implements FallbackFactory<DeptClientService>
      {
             @Override
             public DeptClientService create(Throwable throwable)
             {
                    return new DeptClientService() {
                           @Override
                           public Dept get(long id)
                           {
                                  Dept dept = new Dept();
                                  dept.setDeptno(id);
                                  dept.setDname("该ID:" + id + "没有没有对应的信息,Consumer客户端提供的降级信息,此刻服务Provider已经关闭");
                                  dept.setDb_source("no this database in MySQL");
                                  return dept;
                           }
                           @Override
                           public List<Dept> list() { return null; }
                           @Override
                           public boolean add(Dept dept) { return false; }
                    };
             }
      }
    3. 微服务的service限流降级处理机制。
      Spring Cloud Hystrix对限流降级接口统一fallback处理:
      @FeignClient(value = "MICROSERVICECLOUD-DEPT",fallbackFactory=DeptClientServiceFallbackFactory.class)
      public interface DeptClientService
      {
             @RequestMapping(value = "/dept/get/{id}", method = RequestMethod.GET)
             public Dept get(@PathVariable("id") long id);
      }
    4. 因Sentinel无代码侵入,所以不需要修改业务代码,登录Sentinel控制台。
    5. 在左侧导航栏单击簇点链路
    6. 簇点链路页面,找到想要操作的资源,单击操作栏中的降级
      降级

应用部署

  1. 创建K8s集群。
    您在创建K8s集群时,需要配置一系列集群参数,配置方法请参见表 1
    1. 登录EDAS控制台。
    2. 在左侧导航栏中选择集群 > 集群,单击右上角的创建Kubernetes集群
    3. 设置集群的基本信息。
      表 1. 集群参数配置表
      配置 说明
      集群名称 要创建的集群的名称。可以包含1~63个字符,包括数字、中文字符、英文字符和短划线(-)。
      说明 集群名称在同一个用户下必须唯一。
      地域 所创建集群将要部署到的地域。
      可用区 集群的可用区。
      专有网络 您可以在已有VPC列表中选择所需的VPC。
      • 如果您使用的VPC中当前已有NAT网关,容器服务会使用已有的NAT网关。
      • 如果VPC中没有NAT网关,系统会默认自动为您创建一个NAT网关。如果您不希望系统自动创建NAT网关,可以取消勾选页面下方的为专有网络配置 SNAT
      说明 若选择不自动创建NAT网关,您需要自行配置NAT网关实现VPC安全访问公网环境,或者手动配置SNAT,否则VPC内实例将不能正常访问公网,会导致集群创建失败。
      节点类型 计划支持两种节点类型:按量付费和包年包月,包年包月暂未开放。
      Master配置 选择实例规格和系统盘:
      • 实例规格:参见ECS云服务器 用户指南中关于实例规格族的文档。
      • 系统盘:支持SSD云盘和高效云盘。
      • Master实例数量:支持添加3个实例。
      Worker实例 您可选择新增实例或添加已有实例。
      Worker配置 Worker实例选择新增实例,可进行如下配置。
      • 实例规格:参见ECS云服务器 用户指南中关于实例规格族的文档。
      • 数量:选择Worker的数量。
      • 系统盘:支持SSD云盘和高效云盘。
      • 挂载数据盘:支持SSD云盘、高效云盘和普通云盘。
      Docker 版本Kubernetes 版本 显示当前支持的Docker版本和K8s版本,您可查看对应版本,并根据需要进行选择。
      登录密码 设置节点的登录密码。
      确认密码 确认设置的节点登录密码。
      网络插件 支持Flannel和Terway,默认启用Flannel。
      Pod网络CIDRService CIDR(可选项) 选择使用已有专有网络时可配置。
      配置 SNAT 可选,若不选择,需要自行配置NAT网关,或手动配置SNAT。
      公网SLB 会创建一个公网SLB,同时把Master节点的6443端口(对应API Server)暴露出来,用户可以在外网通过kubeconfig连接/操作集群。
      SSH登录
      • 选择开放公网SSH登录,您可以SSH访问集群。
      • 选择不开放公网SSH登录,将无法通过SSH访问集群,也无法通过kubectl连接集群。您可手动进行配置。
      日志服务 您可使用已有Project或新建一个Project。勾选使用日志服务,会在集群中自动配置日志服务插件。
      集群删除保护 防止通过控制台或API误删除集群。
      高级选项
      • 节点Pod数量:单节点可运行Pod数量的上限。
      • 集群CA:设置是否开启集群CA。
    4. 在集群设置页面的右上角,单击创建集群
    5. 当前配置确认页面,所有项目检查通过后,单击确认,启动部署。
    集群创建成功后,您可以在容器服务管理控制台的集群列表页面查看所创建的集群。
  2. 将jar包打成镜像。

    EDAS支持将应用以镜像方式部署到K8s集群中,所以需要将spring boot应用首先打包成Docker镜像,推送到镜像中心,再进入EDAS控制台完成部署。

    打包镜像的DockerFile建议参考如下内容,完成DockerFile编写,本次DockerFile如下:

    FROM centos:7
    
    #RUN yum -y install wget unzip telnet lsof net-tools bind-utils
    #RUN yum -y install java-1.8.0-openjdk-devel
    RUN rm -rf /etc/yum.repos.d/*.repo
    ADD CentOS.repo /etc/yum.repos.d/CentOS.repo
    RUN yum clean all
    
    ENV ADMIN_HOME /home/admin
    ENV LANG="en_US.UTF-8"
    ENV TERM=xterm 
    ENV JAVA_OPTS=""
    
    RUN mkdir -p /home/admin/app/
    ADD sentinel-dashboard.jar /home/admin/app/app.jar
    
    RUN echo 'java -jar $CATALINA_OPTS /home/admin/app/app.jar --server.port=8080' >> /home/admin/start.sh
    RUN chmod +x /home/admin/start.sh 
    WORKDIR $ADMIN_HOME 
    CMD ["/bin/bash", "/home/admin/start.sh"]
  3. 将镜像上传到镜像仓库。
    1. 登录容器服务台。
    2. 选择镜像 > 基本信息 > 操作指南
      基本信息
    3. 根据操作指南的步骤,上传镜像至镜像仓库。
  4. 导入K8s集群。
    1. 登录EDAS控制台。
    2. 在左侧导航栏单击资源管理 > 集群按钮。
    3. 集群页面中,单击容器服务K8s集群页签。
    4. 选择目标集群,单击右侧操作栏中的导入,打开Kubernetes集群页面。
      导入集群
    5. 导入Kubernetes集群页面中,单击导入,导入已创建的K8s集群。
      导入确认
  5. 部署应用。
    1. 在左侧导航栏中,选择应用管理 > 应用列表,进入应用列表页面。
    2. 应用列表页面,单击左上角创建应用
    3. 应用基本信息页面中设置应用的基本信息和参数,然后单击下一步
      • 命名空间:在左侧下拉列表选择地域,在右侧下拉列表选择命名空间,如果不选择命名空间,则设置为默认
      • 集群类型:在左侧下拉列表中选择集群类型为 容器服务K8s集群,右侧下拉列表内选择具体的集群。
      • K8s Namespace:K8s Namespace通过将系统内部的对象分配到不同的Namespace中,形成逻辑上分组的不同项目、小组或用户组,便于不同的分组在共享使用整个集群的资源的同时还能被分别管理。
        • default:没有其他命名空间的对象的默认命名空间。
        • kube-system:系统创建的对象的命名空间。
        • kube-public:此命名空间是自动创建的,并且可供所有用户(包括未经过身份验证的用户)读取。
      • 应用名称:输入应用名称。
      • 应用描述:填写应用的基本情况。
    4. 应用配置页面配置镜像。应用部署方式默认选择为镜像。在我的镜像区域选择您创建的镜像。
    5. 设置完成后,单击确认创建

配置控制台规则

  1. 查看簇点链路。

    Sentinel将每一个需要流控的URL或者接口称为一个资源,并使用URL地址或方法签名表示资源。Sentinel会自动发现所有潜在的资源和资源之间的调用链,并在簇点链路页面展示。 资源是设置流控规则的载体,通过簇点链路自发现,可以方便的对重要资源设置流控规则、熔断降级规则等。

    说明 客户端有访问量之后,才能在簇点链路页面看到资源监控(lazy-initializing)。
    1. 登录Sentinel控制台。
    2. 单击左侧导航栏中的簇点链路,可以看见微服务曾经被访问过的路径,同时在访问过的路径后的操作栏中可以进行流控、降级、热点、授权操作。
      簇点链路
  2. 配置流控规则。

    流量控制规则用于保护服务提供方,服务提供方指任何可以对外提供服务的系统,系统的服务能力是有限的,如果消费方请求速度过高,则采用相应的保护策略,或是直接拒绝,或是排队等待。通过流控规则页面可以查看和配置流量控制规则。

    1. 单击流控规则页签,然后在页面右上角单击新增流控规则
    2. 新建流控规则对话框中配置规则信息。
      图 1. 新建流控规则
      新建流控规则
      • 资源名:待流控的资源名称。
      • 针对来源:该规则针对的来源应用,默认来源应用设为default,代表不区分来源应用。
      • 阈值类型:应用或服务流量的QPS或线程数指标。
        • QPS(每秒钟的请求数量):当调用该API的QPS达到阈值的时候,进行限流。
        • 线程数:当调用该API的线程数达到阈值的时候,进行限流。
      • 流控模式:选择资源调用关系进行流控。资源关系有:直接、关联和链路三种。
        • 直接:API达到限流条件时,直接限流。
        • 关联:当关联的资源达到阈值时,就限流自己。
        • 链路:只记录指定链路上的流量(指定资源从入口资源进来的流量,如果达到阈值,就进行限流)
      • 流控效果:当阈值类型为QPS时,可以选择流控方式来处理被拦截的流量。
        • 快速失败:达到阈值时,立即拦截请求。
        • Warm Up:根据codeFactor(冷加载因子,默认3)的值,从阈值/codeFactor,经过预热时长,才达到设置的QPS阈值。
        • 排队等待:匀速排队,让请求以匀速的速度通过,阈值类型必须设置为QPS,否则无效。
    3. 单击新增。新的流控规则将出现在流控规则列表中。
      流控规则1
  3. 配置降级规则。

    降级规则用于保护服务消费方。在微服务架构中,业务系统通常要依赖多个服务,依赖的某个服务不可用将会影响业务系统的可用性。解决这个问题的方法是及时发现服务的不可用状态,在调用时快速失败而不是等待调动超时或者重试。Sentinel通过熔断降级来达到快速失败的目的。通过降级规则页面可以查看和配置降级规则。

    1. 单击降级规则页签,然后在页面右上角单击新建降级规则
    2. 新建降级规则对话框中配置规则信息。
      图 2. 降级规则
      降级规则
      • 资源名称:适用该规则的应用资源。
      • 降级策略
        • RT:平均响应时间(秒级统计)超出阈值且在时间窗口内的请求>=5时,触发降级;时间窗口结束后,关闭降级(Sentinel默认最大的RT为4900 ms,可以通过-Dcsp.sentinel.statistic.max.rt=xxx修改)。
        • 异常比例:QPS>=5且异常比例(秒级统计)超过阈值时,触发降级;时间窗口结束后,关闭降级。
        • 异常数:异常数(分钟统计)超过阈值时,触发降级;时间窗口结束后,关闭降级(时间窗口<60秒可能会出现问题)。
      • 时间窗口:降级触发后持续的时间。资源进入降级状态后,在配置的降级窗口时间内,请求都会快速失败。
    3. 单击新增。配置成功后,新的降级规则将出现在降级规则列表中。
      降级规则1
  4. 配置热点规则。

    为应用配置热点规则后,EDAS将分析统计热点参数(资源调用过程中的调用次数较高的参数),并根据配置的热点规则对包含热点参数的资源调用进行限流,保护系统稳定性。

    说明 Sentinel默认显示的端点并不支持热点规则,要显示热点规则,需要自己添加代码。
    @ApiOperation(value = "获取调用中间服务返回信息")
    @RequestMapping(value = "/echo-mid", method = RequestMethod.GET)
    @SentinelResource("/echo-mid") 
    public String midRest(@RequestParam("str") String str) {
           MockService.mock2();
           return restTemplate.getForObject("http://nacos-service-broker/echo-mid?str="
    + str, String.class) + "\r\n";
    }
    1. 单击热点规则页签,然后在页面右上角单击新增热点规则
    2. 新增热点规则对话框中,配置规则信息。
      图 3. 热点规则
      热点规则
      • 资源名:适用该规则的资源名称,与埋点传入的资源名保持一致。
      • 参数索引:埋点传入参数的索引位置。
      • 阈值:是作用于每个热点参数的阈值。
      • 统计窗口时长:统计窗口时间长度(单位为秒)。例如统计窗口时长为10s,QPS阈值为5代表限制10s内每个热点参数访问不超过5次。
    3. 单击新增。配置成功后,新的热点规则将出现在热点规则列表中。
      热点规则1
  5. 配置授权规则。
    1. 单击授权规则页签,然后在页面右上角单击新增授权规则
    2. 新增授权规则对话框中,配置规则信息。
      图 4. 授权规则
      授权规则
      • 资源名:适用该规则的资源名称,与埋点传入的资源名保持一致。
      • 流控应用:添加微服务。
    3. 单击新增。配置成功后,新的授权规则将出现在授权规则列表中。
      授权规则1
  6. 配置系统规则。

    系统规则从整体维度对应用入口流量进行控制,结合应用的Load、CPU使用率、总体平均RT、入口QPS和并发线程数等几个维度的监控指标,结合自适应的流控策略,让系统的入口流量和系统的负载达到一个平衡,保证系统在最大吞吐量状态下稳定运行。

    1. 单击系统规则页签,然后在页面右上角单击新增系统规则
    2. 新增系统规则对话框中,配置规则信息。
      图 5. 系统规则
      系统规则
      • 阈值类型
        • LOAD(仅对Linux/Unix-like机器生效):当系统Load1超过阈值,且系统当前的并发线程数超过系统容量时才会触发系统保护。系统容量由系统的maxQps*minRt计算得出。设定参考值一般是CPU cores * 2.5。
        • RT:当单台机器上所有入口流量的平均RT达到阈值即触发系统保护,单位是毫秒。
        • 线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。
        • 入口 QPS:当单台机器上所有入口流量的QPS达到阈值即触发系统保护。
        • CPU 使用率:当系统CPU使用率超过阈值即触发系统保护(取值范围 0.0~1.0)。
      • 流控应用:添加微服务。
    3. 单击新增。配置成功后,新的系统规则将出现在系统规则列表中。
      系统规则1