zoukankan      html  css  js  c++  java
  • Spring Cloud微服务安全实战_6-7_sentinel限流实战

    上一篇说了微服务上的限流,用的是guava的RateLimit做的简单的限流,本篇说用阿里的sentinel   做微服务的限流。

    sentinel  是阿里2018年开源的一个开源项目,具体中文文档:https://github.com/alibaba/Sentinel/wiki/%E4%BB%8B%E7%BB%8D 。

    简单来说 Sentinel就是干三件事: 限流、熔断、降级,来保证服务高可用,不会崩掉(你本身不会崩掉,也不会因为依赖的其他服务崩掉把你带死)

      

    一、简单的限流使用场景

    流控

      实验项目

        

      1,引依赖(微服务上)

       找到最新版的maven依赖,加到nb-order-api服务  

    <!--阿里巴巴sentinel-->
    <dependency>
       <groupId>com.alibaba.csp</groupId>
       <artifactId>sentinel-core</artifactId>
       <version>1.7.1</version>
    </dependency>

      2,定义资源

        最常见的就是你要保护的方法,或者一段逻辑。

        手动编码方式,下面代码中红色部分就是定义资源try-catch中间就是要保护的逻辑

     * 创建订单
         * @param info
         * @param
         * @return
         */
        //注解生效需在启动类配置@EnableGlobalMethodSecurity(prePostEnabled = true)
        //@PreAuthorize("#oauth2.hasScope('write')")
        @PreAuthorize("hasRole('ROLE_ADMIN')")
        @PostMapping
        public OrderInfo create(@RequestBody OrderInfo info,@AuthenticationPrincipal String username){
    
            try(Entry entry = SphU.entry("createOrder")){ //资源名称-createOrder
                // 被保护的逻辑
                log.info("获取到username = {}",username);
            }catch (BlockException ex){
                // 处理被流控的逻辑
                log.info("blocked!");
            }
            //查询价格
            //PriceInfo price = restTemplate.getForObject("http://localhost:9080/prices/"+info.getProductId(),PriceInfo.class);
            //log.info("price is "+price.getPrice());
            return info;
        }

      3,定义规则

        针对某个定义的资源(上面的createOrder),定义一个规则,规则有很多种:流控规则、熔断规则、降级规则,都可以对定义的资源定义规则,这里做一个流控规则的演示。

        新建sentinel的配置类

    package com.nb.security;
    
    import com.alibaba.csp.sentinel.slots.block.RuleConstant;
    import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
    import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
    import org.springframework.context.ApplicationListener;
    import org.springframework.context.event.ContextRefreshedEvent;
    import org.springframework.stereotype.Component;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * sentinel规则,硬编码方式
     */
    @Component
    public class SentinelConfig implements ApplicationListener<ContextRefreshedEvent> {
    
        @Override
        public void onApplicationEvent(ContextRefreshedEvent event) {
            //系统启动好以后执行
            List<FlowRule> rules = new ArrayList<>();
            FlowRule rule = new FlowRule();
            rule.setResource("createOrder");//资源名称
            rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
            rule.setCount(1);//设置QPS=1,每秒1个请求
            rules.add(rule);
            FlowRuleManager.loadRules(rules);
        }
    }

       实验:启动订单服务,用postman直接请求创建订单服务 http://localhost:9060/orders ,先跳过网关以方便做实验

      

       查看打印日志可以看出,每秒只能有一个请求通过,其他的则走了catch限流逻辑,这里就可以自定义处理。

      

     3,sentinel日志

      实验运行之后,会生成一些日志文件,在windows上的目录是:C:Usersdevlogscsp

      

       sentinel-record.log.2020-03-16.0 , 可以看出sentinel定义的规则

    2020-03-16 09:02:21.729 INFO [FlowRuleManager] Flow rules loaded: {}
    2020-03-16 09:02:21.732 INFO App name resolved: com.nb.security.NbOrderApiApplication
    2020-03-16 09:02:21.734 INFO [SentinelConfig] Application type resolved: 0
    2020-03-16 09:02:21.736 INFO [MetricWriter] Creating new MetricWriter, singleFileSize=52428800, totalFileCount=6
    2020-03-16 09:02:21.738 INFO [DynamicSentinelProperty] Config will be updated to: [FlowRule{resource=createOrder, limitApp=default, grade=1, count=1.0, strategy=0, refResource=null, controlBehavior=0, warmUpPeriodSec=10, maxQueueingTimeMs=500, clusterMode=false, clusterConfig=null, controller=null}]
    2020-03-16 09:02:21.741 INFO [FlowRuleManager] Flow rules received: {createOrder=[FlowRule{resource=createOrder, limitApp=default, grade=1, count=1.0, strategy=0, refResource=null, controlBehavior=0, warmUpPeriodSec=10, maxQueueingTimeMs=500, clusterMode=false, clusterConfig=null, controller=com.alibaba.csp.sentinel.slots.block.flow.controller.DefaultController@2e2b9f53}]}
    2020-03-16 09:03:24.012 INFO [InitExecutor] Found init func: com.alibaba.csp.sentinel.metric.extension.MetricCallbackInit
    2020-03-16 09:03:24.017 INFO [InitExecutor] Executing com.alibaba.csp.sentinel.metric.extension.MetricCallbackInit with order 2147483647
    2020-03-16 09:03:24.019 INFO Add child <sentinel_default_context> to node <machine-root>
    2020-03-16 09:03:24.023 INFO [SlotChainProvider] Global slot chain builder resolved: com.alibaba.csp.sentinel.slots.DefaultSlotChainBuilder
    2020-03-16 09:03:24.030 INFO Add child <createOrder> to node <sentinel_default_context>
    2020-03-16 09:03:24.032 INFO [AuthorityRuleManager] Load authority rules: {}
    2020-03-16 09:03:24.037 INFO [SystemRuleManager] Current system check status: false, highestSystemLoad: 1.797693e+308, highestCpuUsage: 1.797693e+308, maxRt: 9223372036854775807, maxThread: 9223372036854775807, maxQps: 1.797693e+308
    2020-03-16 09:03:24.039 INFO [DegradeRuleManager] Degrade rules loaded: {}
    2020-03-16 09:03:24.042 INFO [MetricExtensionProvider] MetricExtension resolved, size=0
    2020-03-16 09:03:25.743 INFO [MetricWriter] New metric file created: C:Usersdevlogscspcom-nb-security-NbOrderApiApplication-metrics.log.2020-03-16
    2020-03-16 09:03:25.744 INFO [MetricWriter] New metric index file created: C:Usersdevlogscspcom-nb-security-NbOrderApiApplication-metrics.log.2020-03-16.idx

       com-nb-security-NbOrderApiApplication-metrics.log.2020-03-16 可以看出流量变化情况

    |--timestamp-|------date time----|--resource-|p |block|s |e|rt

    1584320604000|2020-03-16 09:03:24|createOrder|1|0|1|0|14|0|0|0
    1584320610000|2020-03-16 09:03:30|createOrder|1|0|1|0|0|0|0|0
    1584320611000|2020-03-16 09:03:31|createOrder|1|0|1|0|0|0|0|0
    1584320713000|2020-03-16 09:05:13|createOrder|1|0|1|0|1|0|0|0
    1584320716000|2020-03-16 09:05:16|createOrder|1|1|1|0|1|0|0|0
    1584320718000|2020-03-16 09:05:18|createOrder|1|0|1|0|0|0|0|0
    1584320719000|2020-03-16 09:05:19|createOrder|1|0|1|0|1|0|0|0
    1584320722000|2020-03-16 09:05:22|createOrder|1|1|1|0|0|0|0|0
    1584320723000|2020-03-16 09:05:23|createOrder|1|0|1|0|0|0|0|0
    1584320724000|2020-03-16 09:05:24|createOrder|1|0|1|0|0|0|0|0

             其中 p 代表通过的请求, block 代表被阻止的请求, s 代表成功执行完成的请求个数, e 代表用户自定义的异常, rt 代表平均响应时长。

       

      4,启动 Sentinel 控制台

        官方文档 https://github.com/alibaba/Sentinel/wiki/%E6%8E%A7%E5%88%B6%E5%8F%B0#2-%E5%90%AF%E5%8A%A8%E6%8E%A7%E5%88%B6%E5%8F%B0

         下载 Dashboard jar包 :https://github.com/alibaba/Sentinel/releases ,是一个springboot项目。

          

         启动jar包: 其中 -Dserver.port=8888 用于指定 Sentinel 控制台端口为 8888

    java -Dserver.port=8888 -Dcsp.sentinel.dashboard.server=localhost:8888 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.7.1.jar

        

         默认用户名 密码都是sentinel ,如需修改请参照官方文档

        

         首页 ,默认是他自己

                    

         

        5,客户端接入控制台 

           官方文档 https://github.com/alibaba/Sentinel/wiki/%E6%8E%A7%E5%88%B6%E5%8F%B0#2-%E5%90%AF%E5%8A%A8%E6%8E%A7%E5%88%B6%E5%8F%B0

          有两种方式,一种是通过制定JVM参数的形式,这种springboot不友好这里就不说了。

          如果是springboot项目就应该这么做,通过Spring Cloud Alibaba Sentinel配置https://github.com/alibaba/spring-cloud-alibaba/wiki/Sentinel

          引依赖(不需要上面说的 sentinel-transport-simple-http的依赖了          

            <!-- https://github.com/alibaba/spring-cloud-alibaba/wiki/Sentinel-->
            <dependency>
             <groupId>org.springframework.cloud</groupId>
             <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
             <version>0.9.0.RELEASE</version>
            </dependency>

            使用注解定义资源 

            

              配置控制台信息   application.yml

    spring:
      cloud:
        sentinel:
          transport:
            port: 8719
            dashboard: localhost:8888

              这里的 spring.cloud.sentinel.transport.port 端口配置会在应用对应的机器上启动一个 Http Server,该 Server 会与 Sentinel 控制台做交互。比如 Sentinel 控制台添加了一个限流规则,会把规则数据 push 给这个 Http Server 接收,Http Server 再将规则注册到 Sentinel 中

        启动order-api,http://localhost:8888 就可以访问sentinel控制台了 

    二,熔断降级 

      为什么要有熔断降级? 

      服务雪崩举例:

     

      

      比如A是订单服务,它会调用商品服务B,调用价格服务C,调用用户服务D。

      服务一切正常的时候是没问题的,假设用户服务D因为网络抖动或者压力变大,导致响应时间变慢,原来是10毫秒,现在变成了100、1000毫秒。

      这时候A服务调D服务的时候,当前线程就会卡住了,线程就会等待D服务的响应。等待的时候继续有请求进来调用A服务,A服务就会开新的线程去调D服务,D服务没响应,就会在这等着。这样请求A服务的继续进来,请求就一直的等着,到了一定阈值后,就没办法新建线程了,所有线程都占满了,此时A服务也失去响应了。此时有依赖A服务的服务也不行了,引起连锁反应。根本的问题是D服务不行了,这样导致跟D有依赖关系的所有的服务都出问题。这就是服务雪崩。

      熔断:

        这时候就需要用熔断的方式,保证某一个服务出问题,不会把直接或者间接依赖它的所有的服务都带死。

                   

        原理就是在所有的服务前面加一个熔断器,熔断器平常处于关闭的状态,熔断器一旦发现后面服务(服务D)有问题不可用了,就打开熔断器。此时服务A再调用服务D的时候,到熔断器这就直接返回了。

        请求不会到达服务D,服务A这就不会因为服务D响应变慢而有线程堆积,等待,这样就解决了服务雪崩的问题。

        

        熔断器机制示意

            

          1,当一个请求过来

              如果熔断器是关闭的,请求就放给后面的业务父服务。

              如果业务服务出问题(抛异常、网络抖动、压力大响应时间变长、服务超时),在熔断器这都会做一个统计,比如从熔断器放过去10个请求,5个超时,3个报错,熔断器都会进行统计。

              可以在自己配置熔断器什么情况从关闭状态变为打开状态。如果触发了熔断器打开状态,请求到熔断器这就直接返回回去了。

          2,如果是因为网络抖动 或者 瞬时压力变大导致的熔断器打开,等网络恢复或者后面压力变小了,其实是又可以正常提供服务的,就需要有个机制让熔断器知道后面的服务恢复正常了,重新让熔断器回到关闭状态。

            机制就是:熔断器这会有一个定时任务,在一定的时间周期内,到了时间周期,就将熔断器转为【半打开状态】,会放一个请求给后面的业务服务,如果业务服务可以成功处理,就从半打开状态变为关闭状态。

                  如果放过去的这一个请求仍然是失败状态,熔断器就回到打开状态。过一个时间周期,再做一次这么的循环,一旦有一个请求成功了,就转为关闭状态。

        降级:

          熔断器打开的时候,指定一个更简化的业务逻辑处理。

          比如,后面的服务是一个推荐的服务,正常的推荐是根据用户的用户画像,算出推荐的商品,但是这个服务需要实时计算的,如果压力大变慢了,熔断器处于打开状态后,可以指定一个预先设计好的简化的逻辑,一个商品列表,静态的。当熔断器打开的时候就直接返回这个列表,用户还可以看到一个商品列表,但是就不是根据用户推荐给他的,服务降级了。

      在sentinel指定熔断降级规则

      1,通过编码方式

        

        

         调用创建订单,跨省

        

         熔断异常信息

          

         降级

          

           

       一般通过控制台指定各种规则,那就可以去掉 SentinelConfig配置了。

    代码 :https://github.com/lhy1234/springcloud-security/tree/chapt-6-6-sentinel-ratelimit

  • 相关阅读:
    Centos7 KVM启用嵌套虚拟化
    CentOS 桥接网卡配置
    centos iso镜像自动挂载
    git status没有颜色提示
    virt-install 安装系统和启动虚机
    Python 源代码代码打包成 whl 文件
    存储池与存储卷,使用virt-install创建虚拟机
    ftp 搭建 centos 源
    git 生成并添加 SSH key
    linked-list-cycle leetcode C++
  • 原文地址:https://www.cnblogs.com/lihaoyang/p/12501789.html
Copyright © 2011-2022 走看看