侧边栏壁纸
博主头像
MULY博主等级

大直若屈,大巧若拙,大辩若讷

  • 累计撰写 11 篇文章
  • 累计创建 19 个标签
  • 累计收到 1 条评论

生产环境Sentinel改造实践(二):规则管理推送改造

MULY
2022-04-07 / 0 评论 / 0 点赞 / 72 阅读 / 10,023 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2022-04-07,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

前文介绍了Sentinel相关的核心概念,本文开始动手对规则管理推送进行改造。

这里挑选流控规则模式改造为示例

Sentinel Dashboard 改造

  1. com.alibaba.csp.sentinel.dashboard.rule.nacos新建NacosConfig.java

    package com.alibaba.csp.sentinel.dashboard.rule.nacos;
    
    import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
    import com.alibaba.csp.sentinel.datasource.Converter;
    import com.alibaba.fastjson.JSON;
    import com.alibaba.nacos.api.PropertyKeyConst;
    import com.alibaba.nacos.api.config.ConfigFactory;
    import com.alibaba.nacos.api.config.ConfigService;
    import lombok.Getter;
    import lombok.Setter;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    import java.util.List;
    import java.util.Properties;
    
    /**
     * @wiki https://github.com/eacdy/Sentinel-Dashboard-Nacos
     * add by tam
     */
    @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 {
            NacosProperties nacosProperties = nacosProperties();
            Properties properties = new Properties();
            properties.put(PropertyKeyConst.SERVER_ADDR, nacosProperties.getServerAddr());
            if (!nacosProperties.getNamespace().isEmpty()) {
                properties.put(PropertyKeyConst.NAMESPACE, nacosProperties.getNamespace());
            }
            return ConfigFactory.createConfigService(properties);
        }
    
        @Bean
        @ConfigurationProperties(prefix = "spring.cloud.sentinel.datasource.nacos")
        public NacosProperties nacosProperties() {
            return new NacosProperties();
        }
    
    
        @Getter
        @Setter
        public static class NacosProperties {
            private String serverAddr;
            private String namespace;
            private String groupId;
        }
    }
    

    这里主要接收三个参数 serverAddr: nacos服务器地址,namespace:nacos命名空间,groupId:nacos分组

    application.properties里新增配置

    spring.cloud.sentinel.datasource.nacos.server-addr=172.16.1.20:8848
    spring.cloud.sentinel.datasource.nacos.groupId=DEFAULT_GROUP
    spring.cloud.sentinel.datasource.nacos.namespace=wuyan_local
    
  2. 同级目录下新增NacosConfigUtil.java

    package com.alibaba.csp.sentinel.dashboard.rule.nacos;
    
    import com.alibaba.csp.sentinel.dashboard.util.JSONUtils;
    import com.alibaba.nacos.api.config.ConfigService;
    import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.RuleEntity;
    import com.alibaba.fastjson.JSON;
    import com.alibaba.csp.sentinel.slots.block.Rule;
    import com.alibaba.csp.sentinel.util.AssertUtil;
    import com.alibaba.csp.sentinel.util.StringUtil;
    import com.alibaba.nacos.api.exception.NacosException;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.stream.Collectors;
    
    /**
     * @wiki https://github.com/eacdy/Sentinel-Dashboard-Nacos
     * add by tam
     */
    @Component
    public class NacosConfigUtil {
        @Autowired
        private NacosConfig.NacosProperties nacosProperties;
    
        public static final String FLOW_DATA_ID_POSTFIX = "-flow-rules";
        public static final String DEGRADE_DATA_ID_POSTFIX = "-degrade-rules";
        public static final String SYSTEM_DATA_ID_POSTFIX = "-system-rules";
        public static final String PARAM_FLOW_DATA_ID_POSTFIX = "-param-flow-rules";
        public static final String AUTHORITY_DATA_ID_POSTFIX = "-authority-rules";
        public static final String GATEWAY_FLOW_DATA_ID_POSTFIX = "-gateway-flow-rules";
        public static final String GATEWAY_API_DATA_ID_POSTFIX = "-gateway-api-rules";
        public static final String DASHBOARD_POSTFIX = "-dashboard";
        public static final String CLUSTER_MAP_DATA_ID_POSTFIX = "-cluster-map";
    
        /**
         * cc for `cluster-client`
         */
        public static final String CLIENT_CONFIG_DATA_ID_POSTFIX = "-cc-config";
        /**
         * cs for `cluster-server`
         */
        public static final String SERVER_TRANSPORT_CONFIG_DATA_ID_POSTFIX = "-cs-transport-config";
        public static final String SERVER_FLOW_CONFIG_DATA_ID_POSTFIX = "-cs-flow-config";
        public static final String SERVER_NAMESPACE_SET_DATA_ID_POSTFIX = "-cs-namespace-set";
    
        /**
         * 将规则序列化成JSON文本,存储到Nacos server中
         *
         * @param configService nacos config service
         * @param app           应用名称
         * @param postfix       规则后缀 eg.NacosConfigUtil.FLOW_DATA_ID_POSTFIX
         * @param rules         规则对象
         * @throws NacosException 异常
         */
        public <T> void setRuleStringToNacos(ConfigService configService, String app, String postfix, List<T> rules) throws NacosException {
            AssertUtil.notEmpty(app, "app name cannot be empty");
            if (rules == null) {
                return;
            }
    
            List<Rule> ruleForApp = rules.stream()
                    .map(rule -> {
                        RuleEntity rule1 = (RuleEntity) rule;
                        //System.out.println(rule1.getClass());
                        Rule rule2 = rule1.toRule();
                        //System.out.println(rule2.getClass());
                        return rule2;
                    })
                    .collect(Collectors.toList());
    
            // 存储,给微服务使用
            String dataId = genDataId(app, postfix);
            configService.publishConfig(
                    dataId,
                    nacosProperties.getGroupId(),
                    JSON.toJSONString(ruleForApp)
            );
    
            // 存储,给控制台使用
            configService.publishConfig(
                    dataId + DASHBOARD_POSTFIX,
                    nacosProperties.getGroupId(),
                    JSONUtils.toJSONString(rules)
            );
        }
    
        /**
         * 从Nacos server中查询响应规则,并将其反序列化成对应Rule实体
         *
         * @param configService nacos config service
         * @param appName       应用名称
         * @param postfix       规则后缀 eg.NacosConfigUtil.FLOW_DATA_ID_POSTFIX
         * @param clazz         类
         * @param <T>           泛型
         * @return 规则对象列表
         * @throws NacosException 异常
         */
        public <T> List<T> getRuleEntitiesFromNacos(ConfigService configService, String appName, String postfix, Class<T> clazz) throws NacosException {
            String rules = configService.getConfig(
                    genDataId(appName, postfix) + DASHBOARD_POSTFIX,
                    //genDataId(appName, postfix),
                    nacosProperties.getGroupId(),
                    3000
            );
            if (StringUtil.isEmpty(rules)) {
                return new ArrayList<>();
            }
            return JSONUtils.parseObject(clazz, rules);
        }
    
        private static String genDataId(String appName, String postfix) {
            return appName + postfix;
        }
    

    注意这里的dataId完整的为 【appId(即客户端spring.application.name配置应用名)+ -flow-rules

    这个很重要,客户端在集成nacos的sentinel配置时这个要对应

  3. com.alibaba.csp.sentinel.dashboard.rule.nacos.flow目录下新建FlowRuleNacosProvider.java

    package com.alibaba.csp.sentinel.dashboard.rule.nacos.flow;
    
    import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
    import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider;
    import com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosConfigUtil;
    import com.alibaba.nacos.api.config.ConfigService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    import java.util.List;
    
    /**
     * @author Eric Zhao
     * @since 1.4.0
     * add by tam
     */
    @Component("flowRuleNacosProvider")
    public class FlowRuleNacosProvider implements DynamicRuleProvider<List<FlowRuleEntity>> {
    
        @Autowired
        private ConfigService configService;
    
        @Autowired
        private NacosConfigUtil nacosConfigUtil;
    
        @Override
        public List<FlowRuleEntity> getRules(String appName) throws Exception {
            return nacosConfigUtil.getRuleEntitiesFromNacos(
                    this.configService,
                    appName,
                    NacosConfigUtil.FLOW_DATA_ID_POSTFIX,
                    FlowRuleEntity.class
            );
        }
    }
    

    这个类主要从Nacos拉取规则信息

  4. com.alibaba.csp.sentinel.dashboard.rule.nacos.flow目录下新建FlowRuleNacosPublisher.java

    package com.alibaba.csp.sentinel.dashboard.rule.nacos.flow;
    
    import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
    import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher;
    import com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosConfigUtil;
    import com.alibaba.nacos.api.config.ConfigService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    import java.util.List;
    
    /**
     * @author Eric Zhao
     * @since 1.4.0
     * add by tam
     */
    @Component("flowRuleNacosPublisher")
    public class FlowRuleNacosPublisher implements DynamicRulePublisher<List<FlowRuleEntity>> {
    
        @Autowired
        private ConfigService configService;
    
        @Autowired
        private NacosConfigUtil nacosConfigUtil;
    
        @Override
        public void publish(String app, List<FlowRuleEntity> rules) throws Exception {
            nacosConfigUtil.setRuleStringToNacos(
                    this.configService,
                    app,
                    NacosConfigUtil.FLOW_DATA_ID_POSTFIX,
                    rules
            );
        }
    }
    
  5. 修改com.alibaba.csp.sentinel.dashboard.controller.v2.FlowControllerV2

    	@Autowired
        @Qualifier("flowRuleNacosProvider")
        private DynamicRuleProvider<List<FlowRuleEntity>> ruleProvider;
        @Autowired
        @Qualifier("flowRuleNacosPublisher")
        private DynamicRulePublisher<List<FlowRuleEntity>> rulePublisher;
    

    主要增加 @Qualifier("flowRuleNacosProvider")@Qualifier("flowRuleNacosPublisher")

Sentinel接入客户端

项目如果是SpringCloud项目在pom文件里引入

		<dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>

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

bootstrap.properties新增如下配置

server.port=8002
spring.application.name=qetesh-openapi
spring.cloud.nacos.discovery.server-addr=172.16.1.20:8848
spring.cloud.nacos.discovery.namespace=wuyan_local

spring.cloud.sentinel.transport.dashboard=localhost:8888
spring.cloud.sentinel.eager=true
spring.cloud.sentinel.datasource.ds1.nacos.server-addr=127.0.0.1:8848
spring.cloud.sentinel.datasource.ds1.nacos.dataId=${spring.application.name}-flow-rules
spring.cloud.sentinel.datasource.ds1.nacos.namespace=wuyan_local
spring.cloud.sentinel.datasource.ds1.nacos.groupId=DEFAULT_GROUP
spring.cloud.sentinel.datasource.ds1.nacos.rule-type=flow

注意三个参数 serverAddrnamespacegroupId 和Dashboard的保持一致

并且spring.cloud.sentinel.datasource.ds1.nacos.rule-type 值为flow(流控)

在启动类增加如下代码

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
@EnableDiscoveryClient
public class QeteshOpenapiApplication {

    public static void main(String[] args) {
        SpringApplication.run(QeteshOpenapiApplication.class, args);
    }

    @RestController
    static class TestController {

        @SentinelResource("ken2")
        @GetMapping("/hello")
        public String hello() {
            return "itweek.top";
        }

    }

}

启动项目访问接口,在DashBoard里就能看到相关的配置

image-20220407155608640

在流控规则里新增如下配置,

image-20220407155804931

image-20220407155634279

这时在nacos也会有相应的配置

image-20220407155729389

多次访问接口会出现 即代表流控规则限流成功

image-20220407155652592

0

评论区