zoukankan      html  css  js  c++  java
  • sentinel 持久化

    1. 概述

    在前面的关于Sentinel的使用中,可以发现,Sentinel-dashboard配置的规则,在我们的微服务以及控制台重启的时候就清空了,因为他是基于内存的.

    所以我们有必要将规则配置进行持久化, Sentinel 为我们提供了多种方式,多种选择:

    image-20210408135947884

    官方文档:https://github.com/alibaba/Sentinel/wiki/在生产环境中使用-Sentinel

    而最推荐的方式为Push模式,

    我们可以将规则配置到注册中心中,例如ZooKeeper, Nacos, Apollo等等,当我们的客户端去连接时,将配置信息实时推送到各个客户端,概念图如下:

    image-20210408140336138

    下面以Nacos 为例

    2. 以Nacos演示

    首先我们观察一下,没有注册Nacos的情况

    手动注册规则,并进行访问:

    
    @RestController
    @RequestMapping("test")
    @Slf4j
    public class TestController {
    
        @Autowired
        private TestService testService;
    
        /**
         * 加载此类后执行
         */
        @PostConstruct
        public void init() {
            List<FlowRule> rules = new ArrayList<>();
            //新建一个规则
            FlowRule rule = new FlowRule();
            //保护的资源
            rule.setResource("HelloWorld");
            //设置为QPS的规则类型
            rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
            //值为2,则表示每秒只能访问此资源两次
            rule.setCount(2);
            rules.add(rule);
            //加载此资源
            FlowRuleManager.loadRules(rules);
        }
    
        @GetMapping("testB")
        @SentinelResource(value = "HelloWorld",blockHandler = "handler" ,blockHandlerClass = CustomerBlockHandler.class)
        public void testA() {
            System.out.println("业务代码执行完毕!");
        }
    }
    
    

    打印如下

    业务代码执行完毕!
    业务代码执行完毕!
    方法被流控
    方法被流控
    方法被流控
    方法被流控
    业务代码执行完毕!
    业务代码执行完毕!
    方法被流控
    方法被流控
    

    控制台流控规则显示如下

    image-20210408112155405

    说明此时本地注册的流控规则生效

    使用Nacos配置:

    添加依赖(pom):

            <dependency>
                <groupId>com.alibaba.csp</groupId>
                <artifactId>sentinel-datasource-nacos</artifactId>
            </dependency>
    

    添加访问数据源配置(yaml):

    server:
      port: 8401
    spring:
      application:
        name: cloudalibaba-sentinel-service
      cloud:
        sentinel:
          transport: 
            dashboard: 127.0.0.1:8080
            port: 8719  
          datasource:
            dsl: # 名称随意
              nacos:
                server-addr: 192.168.100.108:8848 # nacos地址
                dataId: cloudalibaba-sentinel-service #nacos配置的dataId
                groupId: DEFAULT_GROUP # nacos配置的groupId
                data_type: json # 配置文件类型
                rule-type: flow #规则类型
    management:
      endpoints:
        web:
          exposure:
            include: "*"
            
    

    此时我们再访问testB 接口,发现此方法已经无法被流控,并且 控制台也没有显示此流控规则了, 说明 我们从Nacos中拉取规则时, 将覆盖本地规则,此时 Nacos 我们还没有配置,则 此时流控为空

    业务代码执行完毕!
    业务代码执行完毕!
    业务代码执行完毕!
    业务代码执行完毕!
    业务代码执行完毕!
    业务代码执行完毕!
    业务代码执行完毕!
    业务代码执行完毕!
    业务代码执行完毕!
    业务代码执行完毕!
    业务代码执行完毕!
    

    image-20210408112328895

    在Nacos中添加流控配置:

    配置如下,其中 DataId ,GroupId, 配置类型 ,要和客户端中配置的一致,此流控规则为 QPS 为1

    image-20210408141659632

    [
        {
            "resource":"/retaLimit/byUrl", // 资源名
            "limitApp":"default", //来源应用
            "grade":1, //阈值类型,0 表示线程数,1表示QPS
            "count":1, // 单机阈值
            "strategy":0, // 流控模式, 0表示直接,1表示关联, 2表示链路
            "controlBehavior":0, //流控效果, 0表示快速失败,1表示 Warm Up, 2表示排队等待
            "clusterMode":false //是否集群
        }
    ]
    

    此时客户端不用重启, 将自动将新增的流控规则推送到此客户端中:

    image-20210408142410982

    快速访问流控接口:

    @GetMapping("testD")
        @SentinelResource(value = "/retaLimit/byUrl",blockHandler = "handler" ,blockHandlerClass = CustomerBlockHandler.class)
        public void testD() {
            System.out.println("业务代码执行完毕!");
        }
    

    打印信息如下:

    业务代码执行完毕!
    业务代码执行完毕!
    业务代码执行完毕!
    方法被流控
    方法被流控
    方法被流控
    方法被流控
    业务代码执行完毕!
    方法被流控
    方法被流控
    
    

    说明成功将流控规则从Nacos中拉取下来,并此时重启客户端后,流控规则仍然存在,实现持久化.

    3. 改造Sentinel-dashboard

    在上面的演示中, 我们发现此时的dashboard,仅仅只是变成查看 客户端 从Nacos中拉取下来的配置,并没有连接到Nacos中, 所以当我们从dashboard中添加规则时,并没有将规则持久化到Nacos中, 当我们重启客户端后,dashboard 新增的规则仍然消失,

    但是如果我们每次新增规则,都要以这样新增 JSON的方式,又比较麻烦,所以我们可以将dashboard进行改造,使之新增规则时,同样将规则持久化到Nacos中

    首先,需要将dashboard 的源码下载下来: https://github.com/alibaba/Sentinel/tree/master/sentinel-dashboard (源码下载较慢的话,可以私信或评论发你),并打开(本人下载的是1.8)

    查看源码中,在controller包中,有几个特殊的Controller, 对应着页面中的各个规则的CRUD, 以FlowControllerV1 为例:

    image-20210408185522479

    查看此类,有一个非常重要的字段:

    @Autowired
    private SentinelApiClient sentinelApiClient;
    

    每个Controller 就是通过这个对象, 与Sentinel客户端进行Http交互, 将从页面上增加,删除的操作,通过调用对应的API 来操作对应的客户端;

    例如保存规则的方法中:

    private CompletableFuture<Void> publishRules(String app, String ip, Integer port) {
            List<FlowRuleEntity> rules = repository.findAllByMachine(MachineInfo.of(app, ip, port));
            return sentinelApiClient.setFlowRuleOfMachineAsync(app, ip, port, rules);
        }
    

    调用了此对象的setFlowRuleOfMachineAsync 方法,一直点进去看,会发现最终发送了一个Http请求,

    executeCommand(new HttpGet(urlBuilder.toString()));
    

    那么其他方法,其他各种规则配置类都是一样, 这样一来, dashboard 将直接与客户端请求HTTP请求, 下面我们进行改造,使之 读取规则从Nacos中读取,保存也往Nacos中保存,.

    开始改造:

    在此源码中,其实已经为我们准备了关于此方面的示例,在test包中,

    image-20210408221341777

    已经有了关于关联Nacos的示例, 其中 FlowRuleNacosProvider 类和FlowRuleNacosPublisher 类分别继承了DynamicRuleProvider接口 和 DynamicRulePublisher 接口, 实现了拉取 和推送的方法, 而这两个类则可以替换FlowControllerV1 类中sentinelApiClient字段, 将这四个类拷贝到 主包中,创建Nacos文件夹:

    image-20210408222032375

    注册类时修Bean的id:

    @Component("myFlowRuleNacosProvider")
    public class FlowRuleNacosProvider implements DynamicRuleProvider<List<FlowRuleEntity>> {
    
        @Autowired
        private ConfigService configService;
        @Autowired
        private Converter<String, List<FlowRuleEntity>> converter;
    
        @Override
        public List<FlowRuleEntity> getRules(String appName) throws Exception {
            String rules = configService.getConfig(appName + NacosConfigUtil.FLOW_DATA_ID_POSTFIX,
                NacosConfigUtil.GROUP_ID, 3000);
            if (StringUtil.isEmpty(rules)) {
                return new ArrayList<>();
            }
            return converter.convert(rules);
        }
    }
    
    @Component("myFlowRuleNacosPublisher")
    public class FlowRuleNacosPublisher implements DynamicRulePublisher<List<FlowRuleEntity>> {
    
        @Autowired
        private ConfigService configService;
        @Autowired
        private Converter<List<FlowRuleEntity>, String> converter;
    
        @Override
        public void publish(String app, List<FlowRuleEntity> rules) throws Exception {
            AssertUtil.notEmpty(app, "app name cannot be empty");
            if (rules == null) {
                return;
            }
            configService.publishConfig(app + NacosConfigUtil.FLOW_DATA_ID_POSTFIX,
                NacosConfigUtil.GROUP_ID, converter.convert(rules));
        }
    }
    

    并修改NacosConfig 类, 将Nacos的地址改成自己的地址

    @Configuration
    public class NacosConfig {
    
        @Bean
        public Converter<List<FlowRuleEntity>, String> flowRuleEntityEncoder() {
            return JSON::toJSONString;
        }
    
        @Bean
        public Converter<String, List<FlowRuleEntity>> flowRuleEntityDecoder() {
            return s -> JSON.parseArray(s, FlowRuleEntity.class);
        }
    
        @Bean
        public ConfigService nacosConfigService() throws Exception {
            return ConfigFactory.createConfigService("192.168.100.108");
        }
    }
    

    并将依赖中,关于nacos持久化的包,test标签注释:

    <dependency>
                <groupId>com.alibaba.csp</groupId>
                <artifactId>sentinel-datasource-nacos</artifactId>
                <!--<scope>test</scope>-->
    </dependency>
    

    此时,我们只需将所有controller包中的sentinelApiClient ,换成 对应的 Nacos对象即可,例如上面的保存流控规则:

    @RestController
    @RequestMapping(value = "/v1/flow")
    public class FlowControllerV1 {
    
        private final Logger logger = LoggerFactory.getLogger(FlowControllerV2.class);
    
        @Autowired
        private InMemoryRuleRepositoryAdapter<FlowRuleEntity> repository;
    
        @Autowired
        @Qualifier("myFlowRuleNacosProvider")
        private DynamicRuleProvider<List<FlowRuleEntity>> ruleProvider;
        @Autowired
        @Qualifier("myFlowRuleNacosPublisher")
        private DynamicRulePublisher<List<FlowRuleEntity>> rulePublisher;
    
        private void publishRules(/*@NonNull*/ String app) throws Exception {
            List<FlowRuleEntity> rules = repository.findAllByApp(app);
            rulePublisher.publish(app, rules);
        }
    }
    
    

    此时,当我们再保存流控规则时,将调用rulePublisherpublish 方法, 对Nacos进行保存,

    但是不建议修改原生的版本,官方也给我们提供了示例,即v2 包中FlowControllerV2类,此时的接口为 "/v2/flow"

    @RestController
    @RequestMapping(value = "/v2/flow")
    public class FlowControllerV2 
    

    建议将所有的controller拷贝一份v2版本, 下面就着官方的示例,看如何将页面上的 菜单也切换到v2的版本上

    同样,对于前端, 也提供了Demo, 在resources/app/scripts/directives/sidebar/sidebar.html 中,修改流控规则的路由,

    <li ui-sref-active="active" ng-if="!entry.isGateway">
                <a ui-sref="dashboard.flowV1({app: entry.app})">
                  <i class="glyphicon glyphicon-filter"></i>&nbsp;&nbsp;流控规则</a>
              </li>
    

    修改为

    <a ui-sref="dashboard.flow({app: entry.app})">
    

    路由规则配置在app.js中:

    image-20210408223942858

    那么此时,当点击流控规则按钮时,将跳转到 flow_v2.html中, 而这个html也是提供好的,调用的接口都是 "v2":

    如图:当我们再次点击流控规则时,无论是保存还是获取,都将调用v2的版本,其他页面也以此类推

    image-20210408224116345

    同时,对于客户端,也需要添加指定对应的 dataId 和 GroupId

          datasource:
            dsl:
              nacos:
                server-addr: 192.168.100.109:8848
                dataId: cloudalibaba-sentinel-service
                groupId: DEFAULT_GROUP
                data_type: json
                rule-type: flow
            flow: # 和 改造后的对应
                nacos:
                    server-addr: 192.168.100.109:8848
                    dataId: ${spring.application.name}-flow-rules
                    groupId: SENTINEL_GROUP
                    data_type: json
                    rule-type: flow
    

    上面的介绍中,仅仅只是以流控规则为例, 即FlowControllerV1, 同时,对于Nacos, 也就只创建了FlowRuleNacosProviderFlowRuleNacosPublisher 类, 对于其他 的例如降级规则,系统规则等,都需创建 对应的Nacos替换类, 用于替换相应controller的

    sentinelApiClient 字段, 同时前端页面也是一样.

    还有更简单的方式,是直接使用阿里云提供的服务,具体使用,请自行百度或者查看官网:

    https://github.com/alibaba/Sentinel/wiki/AHAS-Sentinel-控制台

  • 相关阅读:
    人生,别认输,因为没人希望你赢
    一张图看懂开源许可协议,开源许可证GPL、BSD、MIT、Mozilla、Apache和LGPL的区别
    Android Studio 出现 Gradle's dependency cache may be corrupt 解决方案
    清华梦的粉碎——转自王垠
    label smooth
    <现代C++实战30讲>笔记 01 | 堆、栈、RAII:C++里该如何管理资源?
    h5转pb的两个坑
    opencv库的像素x,y,width,height,col,row的对应关系
    detect 导图
    keras多gpu训练
  • 原文地址:https://www.cnblogs.com/xjwhaha/p/14635279.html
Copyright © 2011-2022 走看看