sentinel配置持久化到apollo

news2024/11/27 21:48:53

背景

sentinel-dashborad的配置默认是存储到内存中的,生产环境肯定不能这样使用,官网支持zookeeper、nacos、apollo的配置,本文就来介绍apollo的持久化

apollo

sentinel-dashboard 整合 apollo 进行规则的持久化配置,主要方式是通过 apollo 开放平台的授权方式进行写入与读取。所以需要先在apollo上开放出授权的token

sentinel-dashboard

首先将sentinel下载下来然后找到sentinel-dashboard模块,基于1.8.1版本

新建apllo需要的相关配置 ApolloProperties

@ConfigurationProperties(prefix = "apollo")
@Data
public class ApolloProperties {
    /**
     * apollo地址
     * */
    private String portalUrl;
    
    /**
     * 授权token
     * */
    private String token;
    
    /**
     * appId
     * */
    private String appId;
    
    /**
     * 环境
     * */
    private String env;
    
    /**
     * clusterName(默认为default)
     * */
    private String clusterName;
    
    /**
     * 命名空间
     * */
    private String namespace;
    
    /**
     * 操作人
     * */
    private String operator;
}

新建ApolloConfig 里面包括各种规则和apollo交互需要的编解码工具和操作apollo的api

@Configuration
@EnableConfigurationProperties(ApolloProperties.class)
public class ApolloConfig {
    
    @Autowired
    private ApolloProperties apolloProperties;;
    
    /**
     * 流控规则编码
     */
    @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 Converter<List<DegradeRuleEntity>, String> degradeRuleEntityEncoder() {
        return JSON::toJSONString;
    }
    
    /**
     * 降级规则解码
     */
    @Bean
    public Converter<String, List<DegradeRuleEntity>> degradeRuleEntityDecoder() {
        return s -> JSON.parseArray(s, DegradeRuleEntity.class);
    }
    
    /**
     * 授权规则编码
     */
    @Bean
    public Converter<List<AuthorityRuleEntity>, String> authorityRuleEntityEncoder() {
        return JSON::toJSONString;
    }
    
    /**
     * 授权规则解码
     */
    @Bean
    public Converter<String, List<AuthorityRuleEntity>> authorityRuleEntityDecoder() {
        return s -> JSON.parseArray(s, AuthorityRuleEntity.class);
    }
    
    /**
     * 系统规则编码
     */
    @Bean
    public Converter<List<SystemRuleEntity>, String> systemRuleEntityEncoder() {
        return JSON::toJSONString;
    }
    
    /**
     * 系统规则解码
     */
    @Bean
    public Converter<String, List<SystemRuleEntity>> systemRuleEntityDecoder() {
        return s -> JSON.parseArray(s, SystemRuleEntity.class);
    }
    
    /**
     * 热点规则编码
     */
    @Bean
    public Converter<List<ParamFlowRuleEntity>, String> paramFlowRuleEntityEncoder() {
        return JSON::toJSONString;
    }
    
    /**
     * 热点规则解码
     */
    @Bean
    public Converter<String, List<ParamFlowRuleEntity>> paramFlowRuleEntityDecoder() {
        return s -> JSON.parseArray(s, ParamFlowRuleEntity.class);
    }
    
    /**
     * 集群流控规则编码
     */
    @Bean
    public Converter<List<ClusterAppAssignMap>, String> clusterGroupEntityEncoder() {
        return JSON::toJSONString;
    }
    
    /**
     * 集群流控规则解码
     */
    @Bean
    public Converter<String, List<ClusterAppAssignMap>> clusterGroupEntityDecoder() {
        return s -> JSON.parseArray(s, ClusterAppAssignMap.class);
    }
    
    /**
     * API管理分组编码
     */
    @Bean
    public Converter<List<ApiDefinitionEntity>, String> apiDefinitionEntityEncoder() {
        return JSON::toJSONString;
    }
    
    /**
     * API管理分组解码
     */
    @Bean
    public Converter<String, List<ApiDefinitionEntity>> apiDefinitionEntityDecoder() {
        return s -> JSON.parseArray(s, ApiDefinitionEntity.class);
    }
    
    /**
     * 网关流控规则编码
     */
    @Bean
    public Converter<List<GatewayFlowRuleEntity>, String> gatewayFlowRuleEntityEncoder() {
        return JSON::toJSONString;
    }
    
    /**
     * 网关流控规则解码
     */
    @Bean
    public Converter<String, List<GatewayFlowRuleEntity>> gatewayFlowRuleEntityDecoder() {
        return s -> JSON.parseArray(s, GatewayFlowRuleEntity.class);
    }

    /**
     * 操作apollo的api
     * */
    @Bean
    public ApolloOpenApiClient apolloOpenApiClient() {
        ApolloOpenApiClient client = ApolloOpenApiClient.newBuilder()
            .withPortalUrl(apolloProperties.getPortalUrl())
            .withToken(apolloProperties.getToken())
            .build();
        return client;

    }
}

新建ApolloConfigUtil 用于生成各种规则存储在apollo中的key名称

在这里插入图片描述

public final class ApolloConfigUtil
{
    /**
     * 网关-api分组id
     */
    public static final String GATEWAY_API_GROUP_DATA_ID_POSTFIX = "gw-api-group-rules";
    
    /**
     * 网关-流控规则id
     */
    public static final String GATEWAY_FLOW_DATA_ID_POSTFIX = "gw-flow-rules";
    
    /**
     * 流控规则id
     */
    public static final String FLOW_DATA_ID_POSTFIX = "flow-rules";
    /**
     * 降级规则id
     */
    public static final String DEGRADE_DATA_ID_POSTFIX = "degrade-rules";
    /**
     * 热点规则id
     */
    public static final String PARAM_FLOW_DATA_ID_POSTFIX = "param-flow-rules";
    /**
     * 系统规则id
     */
    public static final String SYSTEM_DATA_ID_POSTFIX = "system-rules";
    /**
     * 授权规则id
     */
    public static final String AUTHORITY_DATA_ID_POSTFIX = "authority-rules";
    /**
     * 集群流控id
     */
    public static final String CLUSTER_GROUP_DATA_ID_POSTFIX = "cluster-group-rules";
    
    private ApolloConfigUtil()
    {
    }
    
    public static String getGatewayFlowDataId(String appName)
    {
        return String.format("%s-%s", appName, GATEWAY_FLOW_DATA_ID_POSTFIX);
    }
    
    public static String getGatewayApiGroupDataId(String appName)
    {
        return String.format("%s-%s", appName, GATEWAY_API_GROUP_DATA_ID_POSTFIX);
    }
    
    public static String getClusterGroupDataId(String appName)
    {
        return String.format("%s-%s", appName, CLUSTER_GROUP_DATA_ID_POSTFIX);
    }
    
    public static String getFlowDataId(String appName)
    {
        return String.format("%s-%s", appName, FLOW_DATA_ID_POSTFIX);
    }
    
    public static String getDegradeDataId(String appName)
    {
        return String.format("%s-%s", appName, DEGRADE_DATA_ID_POSTFIX);
    }
    
    public static String getParamFlowDataId(String appName)
    {
        return String.format("%s-%s", appName, PARAM_FLOW_DATA_ID_POSTFIX);
    }
    
    public static String getSystemDataId(String appName)
    {
        return String.format("%s-%s", appName, SYSTEM_DATA_ID_POSTFIX);
    }
    
    public static String getAuthorityDataId(String appName)
    {
        return String.format("%s-%s", appName, AUTHORITY_DATA_ID_POSTFIX);
    }
}

流控规则持久化apollo

项目提供了DynamicRuleProviderDynamicRulePublisher两个接口,这是将整个规则的相关操作抽象了出来,一个用户查询、另一个用于新增、修改、删除。项目中test/rule模块下提供了apollo关于流控规则的示例FlowRuleApolloProviderFlowRuleApolloPublisher,也是将这两个接口进行了实现。本人直接拿这提供好的示例进行改造
FlowRuleApolloProvider

@Component("flowRuleApolloProvider")
public class FlowRuleApolloProvider implements DynamicRuleProvider<List<FlowRuleEntity>> {

    @Autowired
    private ApolloOpenApiClient apolloOpenApiClient;
    @Autowired
    private Converter<String, List<FlowRuleEntity>> converter;
    @Autowired
    private ApolloProperties apolloProperties;

    /**
     * @param appName 服务名
     * */
    @Override
    public List<FlowRuleEntity> getRules(String appName) throws Exception {
        //String appId = "appId";
        String flowDataId = ApolloConfigUtil.getFlowDataId(appName);
        OpenNamespaceDTO openNamespaceDTO = apolloOpenApiClient.getNamespace(apolloProperties.getAppId(), apolloProperties.getEnv(), apolloProperties.getClusterName(), apolloProperties.getNamespace());
        String rules = openNamespaceDTO
            .getItems()
            .stream()
            .filter(p -> p.getKey().equals(flowDataId))
            .map(OpenItemDTO::getValue)
            .findFirst()
            .orElse("");

        if (StringUtil.isEmpty(rules)) {
            return new ArrayList<>();
        }
        return converter.convert(rules);
    }
}

FlowRuleApolloPublisher

@Component("flowRuleApolloPublisher")
public class FlowRuleApolloPublisher implements DynamicRulePublisher<List<FlowRuleEntity>> {

    @Autowired
    private ApolloOpenApiClient apolloOpenApiClient;
    @Autowired
    private Converter<List<FlowRuleEntity>, String> converter;
    @Autowired
    private ApolloProperties apolloProperties;

    @Override
    public void publish(String app, List<FlowRuleEntity> rules) throws Exception {
        AssertUtil.notEmpty(app, "app name cannot be empty");
        if (rules == null) {
            return;
        }

        // Increase the configuration
        //String appId = "appId";
        String flowDataId = ApolloConfigUtil.getFlowDataId(app);
        OpenItemDTO openItemDTO = new OpenItemDTO();
        openItemDTO.setKey(flowDataId);
        openItemDTO.setValue(converter.convert(rules));
        openItemDTO.setComment("Program auto-join");
        openItemDTO.setDataChangeCreatedBy(apolloProperties.getOperator());
        apolloOpenApiClient.createOrUpdateItem(apolloProperties.getAppId(), apolloProperties.getEnv(), apolloProperties.getClusterName(), apolloProperties.getNamespace(), openItemDTO);

        // Release configuration
        NamespaceReleaseDTO namespaceReleaseDTO = new NamespaceReleaseDTO();
        namespaceReleaseDTO.setEmergencyPublish(true);
        namespaceReleaseDTO.setReleaseComment("Modify or add configurations");
        namespaceReleaseDTO.setReleasedBy(apolloProperties.getOperator());
        namespaceReleaseDTO.setReleaseTitle("Modify or add configurations");
        apolloOpenApiClient.publishNamespace(apolloProperties.getAppId(), apolloProperties.getEnv(), apolloProperties.getClusterName(), apolloProperties.getNamespace(), namespaceReleaseDTO);
    }
}

下面是改造controller层,流控规则用到了两个controller,FlowControllerV1FlowControllerV2
FlowControllerV2

@RestController
@RequestMapping(value = "/v2/flow")
public class FlowControllerV2 {
    
    private final Logger logger = LoggerFactory.getLogger(FlowControllerV2.class);
    
    @Autowired
    private InMemoryRuleRepositoryAdapter<FlowRuleEntity> repository;
    
    @Autowired
    @Qualifier("flowRuleApolloProvider")
    private DynamicRuleProvider<List<FlowRuleEntity>> ruleProvider;
    @Autowired
    @Qualifier("flowRuleApolloPublisher")
    private DynamicRulePublisher<List<FlowRuleEntity>> rulePublisher;
   
    @GetMapping("/rules")
    @AuthAction(PrivilegeType.READ_RULE)
    public Result<List<FlowRuleEntity>> apiQueryMachineRules(@RequestParam String app) {
        if (StringUtil.isEmpty(app)) {
            return Result.ofFail(-1, "app can't be null or empty");
        }
        try {
            List<FlowRuleEntity> rules = ruleProvider.getRules(app);
            if (rules != null && !rules.isEmpty()) {
                for (FlowRuleEntity entity : rules) {
                    entity.setApp(app);
                    if (entity.getClusterConfig() != null && entity.getClusterConfig().getFlowId() != null) {
                        entity.setId(entity.getClusterConfig().getFlowId());
                    }
                }
            }
            rules = repository.saveAll(rules);
            return Result.ofSuccess(rules);
        } catch (Throwable throwable) {
            logger.error("Error when querying flow rules", throwable);
            return Result.ofThrowable(-1, throwable);
        }
    }
    
    private <R> Result<R> checkEntityInternal(FlowRuleEntity entity) {
        if (entity == null) {
            return Result.ofFail(-1, "invalid body");
        }
        if (StringUtil.isBlank(entity.getApp())) {
            return Result.ofFail(-1, "app can't be null or empty");
        }
        if (StringUtil.isBlank(entity.getLimitApp())) {
            return Result.ofFail(-1, "limitApp can't be null or empty");
        }
        if (StringUtil.isBlank(entity.getResource())) {
            return Result.ofFail(-1, "resource can't be null or empty");
        }
        if (entity.getGrade() == null) {
            return Result.ofFail(-1, "grade can't be null");
        }
        if (entity.getGrade() != 0 && entity.getGrade() != 1) {
            return Result.ofFail(-1, "grade must be 0 or 1, but " + entity.getGrade() + " got");
        }
        if (entity.getCount() == null || entity.getCount() < 0) {
            return Result.ofFail(-1, "count should be at lease zero");
        }
        if (entity.getStrategy() == null) {
            return Result.ofFail(-1, "strategy can't be null");
        }
        if (entity.getStrategy() != 0 && StringUtil.isBlank(entity.getRefResource())) {
            return Result.ofFail(-1, "refResource can't be null or empty when strategy!=0");
        }
        if (entity.getControlBehavior() == null) {
            return Result.ofFail(-1, "controlBehavior can't be null");
        }
        int controlBehavior = entity.getControlBehavior();
        if (controlBehavior == 1 && entity.getWarmUpPeriodSec() == null) {
            return Result.ofFail(-1, "warmUpPeriodSec can't be null when controlBehavior==1");
        }
        if (controlBehavior == 2 && entity.getMaxQueueingTimeMs() == null) {
            return Result.ofFail(-1, "maxQueueingTimeMs can't be null when controlBehavior==2");
        }
        if (entity.isClusterMode() && entity.getClusterConfig() == null) {
            return Result.ofFail(-1, "cluster config should be valid");
        }
        return null;
    }
    
    @PostMapping("/rule")
    @AuthAction(value = AuthService.PrivilegeType.WRITE_RULE)
    public Result<FlowRuleEntity> apiAddFlowRule(@RequestBody FlowRuleEntity entity) {
        entity.setApp(app);
        Result<FlowRuleEntity> checkResult = checkEntityInternal(entity);
        if (checkResult != null) {
            return checkResult;
        }
        Date date = new Date();
        entity.setGmtCreate(date);
        entity.setGmtModified(date);
        entity.setLimitApp(entity.getLimitApp().trim());
        entity.setResource(entity.getResource().trim());
        try {
            entity = repository.save(entity);
            publishRules(entity.getApp());
        } catch (Throwable throwable) {
            logger.error("Failed to add flow rule", throwable);
            return Result.ofThrowable(-1, throwable);
        }
        return Result.ofSuccess(entity);
    }
    @PutMapping("/rule/{id}")
    @AuthAction(AuthService.PrivilegeType.WRITE_RULE)
    public Result<FlowRuleEntity> apiUpdateFlowRule(@PathVariable("id") Long id,
                                                    @RequestBody FlowRuleEntity entity) {
        entity.setApp(app);
        if (id == null || id <= 0) {
            return Result.ofFail(-1, "Invalid id");
        }
        FlowRuleEntity oldEntity = repository.findById(id);
        if (oldEntity == null) {
            return Result.ofFail(-1, "id " + id + " does not exist");
        }
        if (entity == null) {
            return Result.ofFail(-1, "invalid body");
        }
        
        entity.setApp(oldEntity.getApp());
        entity.setIp(oldEntity.getIp());
        entity.setPort(oldEntity.getPort());
        Result<FlowRuleEntity> checkResult = checkEntityInternal(entity);
        if (checkResult != null) {
            return checkResult;
        }
        
        entity.setId(id);
        Date date = new Date();
        entity.setGmtCreate(oldEntity.getGmtCreate());
        entity.setGmtModified(date);
        try {
            entity = repository.save(entity);
            if (entity == null) {
                return Result.ofFail(-1, "save entity fail");
            }
            publishRules(oldEntity.getApp());
        } catch (Throwable throwable) {
            logger.error("Failed to update flow rule", throwable);
            return Result.ofThrowable(-1, throwable);
        }
        return Result.ofSuccess(entity);
    }
    
    @DeleteMapping("/rule/{id}")
    @AuthAction(PrivilegeType.DELETE_RULE)
    public Result<Long> apiDeleteRule(@PathVariable("id") Long id) {
        if (id == null || id <= 0) {
            return Result.ofFail(-1, "Invalid id");
        }
        FlowRuleEntity oldEntity = repository.findById(id);
        if (oldEntity == null) {
            return Result.ofSuccess(null);
        }
        
        try {
            repository.delete(id);
            publishRules(oldEntity.getApp());
        } catch (Exception e) {
            return Result.ofFail(-1, e.getMessage());
        }
        return Result.ofSuccess(id);
    }
    
    public void publishRules(/*@NonNull*/ String app) throws Exception {
        List<FlowRuleEntity> rules = repository.findAllByApp(app);
        rulePublisher.publish(app, rules);
    }
}

FlowControllerV2是调用apollo的ruleProviderrulePublisher完成调用的,我把FlowControllerV1改造成直接调用的FlowControllerV2
FlowControllerV2

@RestController
@RequestMapping(value = "/v2/flow")
public class FlowControllerV2 {
    
    private final Logger logger = LoggerFactory.getLogger(FlowControllerV2.class);
    
    @Autowired
    private InMemoryRuleRepositoryAdapter<FlowRuleEntity> repository;
    
    @Autowired
    @Qualifier("flowRuleApolloProvider")
    private DynamicRuleProvider<List<FlowRuleEntity>> ruleProvider;
    @Autowired
    @Qualifier("flowRuleApolloPublisher")
    private DynamicRulePublisher<List<FlowRuleEntity>> rulePublisher;
    
    @GetMapping("/rules")
    @AuthAction(PrivilegeType.READ_RULE)
    public Result<List<FlowRuleEntity>> apiQueryMachineRules(@RequestParam String app) {
        if (StringUtil.isEmpty(app)) {
            return Result.ofFail(-1, "app can't be null or empty");
        }
        try {
            List<FlowRuleEntity> rules = ruleProvider.getRules(app);
            if (rules != null && !rules.isEmpty()) {
                for (FlowRuleEntity entity : rules) {
                    entity.setApp(app);
                    if (entity.getClusterConfig() != null && entity.getClusterConfig().getFlowId() != null) {
                        entity.setId(entity.getClusterConfig().getFlowId());
                    }
                }
            }
            rules = repository.saveAll(rules);
            return Result.ofSuccess(rules);
        } catch (Throwable throwable) {
            logger.error("Error when querying flow rules", throwable);
            return Result.ofThrowable(-1, throwable);
        }
    }
    
    private <R> Result<R> checkEntityInternal(FlowRuleEntity entity) {
        if (entity == null) {
            return Result.ofFail(-1, "invalid body");
        }
        if (StringUtil.isBlank(entity.getApp())) {
            return Result.ofFail(-1, "app can't be null or empty");
        }
        if (StringUtil.isBlank(entity.getLimitApp())) {
            return Result.ofFail(-1, "limitApp can't be null or empty");
        }
        if (StringUtil.isBlank(entity.getResource())) {
            return Result.ofFail(-1, "resource can't be null or empty");
        }
        if (entity.getGrade() == null) {
            return Result.ofFail(-1, "grade can't be null");
        }
        if (entity.getGrade() != 0 && entity.getGrade() != 1) {
            return Result.ofFail(-1, "grade must be 0 or 1, but " + entity.getGrade() + " got");
        }
        if (entity.getCount() == null || entity.getCount() < 0) {
            return Result.ofFail(-1, "count should be at lease zero");
        }
        if (entity.getStrategy() == null) {
            return Result.ofFail(-1, "strategy can't be null");
        }
        if (entity.getStrategy() != 0 && StringUtil.isBlank(entity.getRefResource())) {
            return Result.ofFail(-1, "refResource can't be null or empty when strategy!=0");
        }
        if (entity.getControlBehavior() == null) {
            return Result.ofFail(-1, "controlBehavior can't be null");
        }
        int controlBehavior = entity.getControlBehavior();
        if (controlBehavior == 1 && entity.getWarmUpPeriodSec() == null) {
            return Result.ofFail(-1, "warmUpPeriodSec can't be null when controlBehavior==1");
        }
        if (controlBehavior == 2 && entity.getMaxQueueingTimeMs() == null) {
            return Result.ofFail(-1, "maxQueueingTimeMs can't be null when controlBehavior==2");
        }
        if (entity.isClusterMode() && entity.getClusterConfig() == null) {
            return Result.ofFail(-1, "cluster config should be valid");
        }
        return null;
    }
    
    @PostMapping("/rule")
    @AuthAction(value = AuthService.PrivilegeType.WRITE_RULE)
    public Result<FlowRuleEntity> apiAddFlowRule(@RequestBody FlowRuleEntity entity) {
        entity.setApp(app);
        Result<FlowRuleEntity> checkResult = checkEntityInternal(entity);
        if (checkResult != null) {
            return checkResult;
        }
        Date date = new Date();
        entity.setGmtCreate(date);
        entity.setGmtModified(date);
        entity.setLimitApp(entity.getLimitApp().trim());
        entity.setResource(entity.getResource().trim());
        try {
            entity = repository.save(entity);
            publishRules(entity.getApp());
        } catch (Throwable throwable) {
            logger.error("Failed to add flow rule", throwable);
            return Result.ofThrowable(-1, throwable);
        }
        return Result.ofSuccess(entity);
    }
    @PutMapping("/rule/{id}")
    @AuthAction(AuthService.PrivilegeType.WRITE_RULE)
    public Result<FlowRuleEntity> apiUpdateFlowRule(@PathVariable("id") Long id,
                                                    @RequestBody FlowRuleEntity entity) {
        entity.setApp(app);
        if (id == null || id <= 0) {
            return Result.ofFail(-1, "Invalid id");
        }
        FlowRuleEntity oldEntity = repository.findById(id);
        if (oldEntity == null) {
            return Result.ofFail(-1, "id " + id + " does not exist");
        }
        if (entity == null) {
            return Result.ofFail(-1, "invalid body");
        }
        
        entity.setApp(oldEntity.getApp());
        entity.setIp(oldEntity.getIp());
        entity.setPort(oldEntity.getPort());
        Result<FlowRuleEntity> checkResult = checkEntityInternal(entity);
        if (checkResult != null) {
            return checkResult;
        }
        
        entity.setId(id);
        Date date = new Date();
        entity.setGmtCreate(oldEntity.getGmtCreate());
        entity.setGmtModified(date);
        try {
            entity = repository.save(entity);
            if (entity == null) {
                return Result.ofFail(-1, "save entity fail");
            }
            publishRules(oldEntity.getApp());
        } catch (Throwable throwable) {
            logger.error("Failed to update flow rule", throwable);
            return Result.ofThrowable(-1, throwable);
        }
        return Result.ofSuccess(entity);
    }
    
    @DeleteMapping("/rule/{id}")
    @AuthAction(PrivilegeType.DELETE_RULE)
    public Result<Long> apiDeleteRule(@PathVariable("id") Long id) {
        if (id == null || id <= 0) {
            return Result.ofFail(-1, "Invalid id");
        }
        FlowRuleEntity oldEntity = repository.findById(id);
        if (oldEntity == null) {
            return Result.ofSuccess(null);
        }
        
        try {
            repository.delete(id);
            publishRules(oldEntity.getApp());
        } catch (Exception e) {
            return Result.ofFail(-1, e.getMessage());
        }
        return Result.ofSuccess(id);
    }
    
    public void publishRules(/*@NonNull*/ String app) throws Exception {
        List<FlowRuleEntity> rules = repository.findAllByApp(app);
        rulePublisher.publish(app, rules);
    }
}

配置文件application.properties

#spring settings
server.servlet.encoding.force=true
server.servlet.encoding.charset=UTF-8
server.servlet.encoding.enabled=true

server.port=8082
csp.sentinel.dashboard.server=localhost:8082
project.name=sentinel-dashboard

#cookie name setting
server.servlet.session.cookie.name=sentinel_dashboard_cookie

#logging settings
logging.level.org.springframework.web=INFO
logging.file.name=${user.home}/logs/csp/sentinel-dashboard.log
logging.pattern.file= %d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n
#logging.pattern.console= %d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n

#auth settings
auth.filter.exclude-urls=/,/auth/login,/auth/logout,/registry/machine,/version
auth.filter.exclude-url-suffixes=htm,html,js,css,map,ico,ttf,woff,png
# If auth.enabled=false, Sentinel console disable login
auth.username=sentinel
auth.password=sentinel

# Inject the dashboard version. It's required to enable
# filtering in pom.xml for this resource file.
sentinel.dashboard.version=@project.version@

apollo.portalUrl = #apollo地址
apollo.token= #token
apollo.appId= appId
apollo.env= #环境
apollo.clusterName= #集群名字,默认default
apollo.namespace= #命令空间
apollo.operator= #操作人,默认apollo

结构

在这里插入图片描述

服务项目

添加依赖

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

application.yml

#服务端口
server:
  port: 8080
# 应用名称
spring:
  application:
    name: test-service
  # nacos
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    sentinel:
      transport:
        port: 8720
        dashboard: localhost:8082
      datasource:
        degrade:
          apollo:
            flowRulesKey: ${spring.application.name}-${spring.cloud.sentinel.datasource.degrade.apollo.rule-ruleType}-rules
            namespace-name: ${sentinel.datasource.rules.apollo.namespace-name}
            ruleType: degrade
        flow:
          apollo:
            flowRulesKey: ${spring.application.name}-${spring.cloud.sentinel.datasource.flow.apollo.ruleType}-rules
            namespace-name: ${sentinel.datasource.rules.apollo.namespace-name}
            ruleType: flow
      eager: true
app:
  id: #appId
apollo:
  meta: #地址
  bootstrap:
    enabled: true
    namespaces:  #命令空间
    eagerLoad:
      enabled: true
sentinel:
  datasource:
    rules:
      apollo:
        namespace-name: #命令空间      
feign:
  sentinel:
    enabled: true
management:
  endpoints:
    web:
      exposure:
        include: '*'
    health:
      show-details: always
  security:
    enabled: false

其他规则和流控规则改造相同,这里就不再介绍了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/528889.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Kettle获取接口数据到表

kettle从接口服务获取数据 主要用到kettle输入菜单下的控件&#xff1a;生成记录、JSON input 查询菜单下的控件&#xff1a;HTTP client 输出菜单下的控件&#xff1a;表输出、插入/更新 生成记录&#xff1a;设置一个变量&#xff0c;用这个变量来保存要去访问接口的URL地址…

数据结构学习之队列

前言&#xff1a;在我们学习了栈之后&#xff0c;明白了它的结构的特殊性即LAST IN FIRST OUT(后进先出)&#xff0c;与之相对应的也有一个特殊的结构队列&#xff08;queue&#xff09;--FIRST IN FIRST OUT(先进先出)&#xff0c;他们都是面对特殊情况下的数据的结构&#xf…

支持导入 Postman ,用这个插件就可以了

首先安装 导入 Postcat 插件&#xff0c;之后就可以愉快的导入 Postman 格式的文件了。 右上角——选择导入——选择Postman 格式——拖入文件 导入即可&#xff01;再也不用担心 Postcat 格式的 api 文件能把自己难住了&#xff01; 如果你日常会用到 api 管理工具的话&#x…

5G和物联网将如何重塑汽车行业?物联网将给汽车行业带来哪些变革?

“ 物联网(Internet of Things)的诞生给无数行业带来了变革&#xff0c;其中就包括汽车行业。物联网对于汽车发展的重要性是毋庸置疑的。从网联汽车到智能交通系统&#xff0c;物联网正在为汽车行业开辟下一个汽车时代。汽联网(Internet of Vehicles)正在成型。” 我们今天看到…

k8s部署mysql并使用nfs持久化数据

k8s部署mysql并使用nfs持久化数据 一、配置nfs服务器1.1 修改配置文件1.2. 载入配置1.3. 检查服务配置 二、创建K8S资源文件2.1 mysql-deployment.yml2.2 mysql-svc.yml 一、配置nfs服务器 参考文章: pod使用示例https://cloud.tencent.com/developer/article/1914388nfs配置…

管好【SD-WEBUI】中大量的模型:名称+预览图+备注+分组(Part.2)

文章目录 &#xff08;零&#xff09;前言&#xff08;一&#xff09;模型预览图&#xff08;1.1&#xff09;预览图姿态&#xff08;证件照&#xff09;&#xff08;1.2&#xff09;预览图姿态&#xff08;半身动作&#xff09; &#xff08;二&#xff09;LoRA模型名称&#…

机器人关节电机PWM

脉冲宽度调制(Pulse width modulation,PWM)技术。一种模拟控制方式 机器人关节电机的控制通常使用PWM(脉冲宽度调制)技术。PWM是一种用于控制电子设备的技术,通过控制高电平和低电平之间的时间比例,实现对电子设备的控制。在机器人关节电机中,PWM信号可以控制电机的…

C++ | 高效使用vector

C | 高效使用vector 文章目录 C | 高效使用vector1.善用Reserve2.移动构造和赋值3.释放vector如果vector内存的是指针&#xff0c;需要先释放每个指针所指内存&#xff0c;再释放vectorReference 1.善用Reserve 当需要向vector中添加元素但目前的空间已经放满时&#xff0c;ve…

200G AOC有源光缆在数据中心的应用

随着大数据时代对高速、高带宽的需求日益增长&#xff0c;人们迫切需要一种新型产品作为高性能计算和数据中心的主要传输介质。因此&#xff0c;光通信传输速率的发展也提高了。面对短距离数据中心在光互连产品中的高速、高密度、低成本、低功耗要求&#xff0c;AOC有源光缆提供…

shell脚本----awk命令

文章目录 一、awk工作原理二、awk相关命令三、awk的使用按行输出文本:按字段输出文本&#xff1a;通过管道、双引号调用 Shell 命令&#xff1a; 一、awk工作原理 逐行读取文本&#xff0c;默认以空格或tab键为分隔符进行分隔&#xff0c;将分隔所得的各个字段保存到内建变量中…

Flink Kafka-Source

文章目录 Kafka Source1. 使用方法2. Topic / Partition 订阅3. 消息解析4. 起始消费位点5. 有界 / 无界模式6. 其他属性7. 动态分区检查8. 事件时间和水印9. 空闲10. 消费位点提交11. 监控12. 安全 Apache Kafka 连接器 Flink 提供了 Apache Kafka 连接器使用精确一次&#xf…

由浅入深理解java集合(四)——集合 Queue

Queue用于模拟队列这种数据结构&#xff0c;队列通常是指“先进先出”&#xff08;FIFO&#xff09;的容器。新元素插入&#xff08;offer&#xff09;到队列的尾部&#xff0c;访问元素&#xff08;poll&#xff09;操作会返回队列头部的元素。通常&#xff0c;队列不允许随机…

【C++初阶】类与对象(中)之构造函数与析构函数

&#x1f466;个人主页&#xff1a;Weraphael ✍&#x1f3fb;作者简介&#xff1a;目前学习C和算法 ✈️专栏&#xff1a;C航路 &#x1f40b; 希望大家多多支持&#xff0c;咱一起进步&#xff01;&#x1f601; 如果文章对你有帮助的话 欢迎 评论&#x1f4ac; 点赞&#x1…

C++继承详解——基类派生类对象赋值转换、菱形虚拟继承

hello&#xff0c;这里是bangbang&#xff0c;今天来讲下继承。 面向对象三大特性&#xff1a;封装、继承、多态。 目录 1. 继承的概念及定义 1.1 继承的概念 1.2 继承定义 1.2.1 定义格式 1.2.2 继承关系和访问限定符 1.2.3 继承基类成员访问方式的变化 2. 基类和派生类对…

Java面试知识点(全)-设计模式二

Java面试知识点(全) 导航&#xff1a; https://nanxiang.blog.csdn.net/article/details/130640392 注&#xff1a;随时更新 13.模板模式 定义一个操作中算法的骨架&#xff0c;而将一些步骤延迟到子类中&#xff0c;模板方法使得子类可以不改变算法的结构即可重定义该算法的…

7. 深入理解MVCC与BufferPool缓存机制

MySQL性能调优 1. MVCC多版本并发控制机制1.1 undo日志版本链与read view机制详解 2. Innodb引擎SQL执行的BufferPool缓存机制 本文是按照自己的理解进行笔记总结&#xff0c;如有不正确的地方&#xff0c;还望大佬多多指点纠正&#xff0c;勿喷。 本节课内容&#xff1a; 1、…

PowerShell install 一键部署VMware_Workstation

VMware Workstation 前言 VMware Workstation Pro 是业界标准的桌面 Hypervisor&#xff0c;用于在 Linux 或 Windows PC 上运行虚拟机 download VMware_Workstation VMware_Workstation WindowsVMware_Workstation linux文档downloaddownload参考 前提条件 开启wmi,配置…

2023接口自动化测试框架9项必备功能(建议收藏)

当你准备使用一个接口测试框架或者自造轮子的时候&#xff0c;或许你需要先了解下一个接口自动化测试框架必须具备什么功能。 一、校验 这个很好了解&#xff0c;如果没有校验&#xff0c;单纯的执行接口的话&#xff0c;那就谈不上测试了。所以支持对返回值校验是一个必须的…

【集合详解】——python基础——如桃花来

目录索引 集合的特点&#xff1a;创建集合&#xff1a;集合常见操作&#xff1a;增加数据&#xff1a;*add():**update():* 删除数据&#xff1a;*remove():**discard():**pop():* 查找数据&#xff1a;*in:**not in:* 集合的特点&#xff1a; 没有重复元素,即使重复&#xff0…

【ONE·C++ || set和map(三):基于红黑树的封装框架】

总言 主要介绍map、set的封装框架。 文章目录 总言1、基本框架说明2、map、set封装Ⅰ&#xff1a;用于比较的仿函数3、map、set封装Ⅱ&#xff1a;迭代器实现3.1、基本说明3.2、begin()、end()、operator*、operator&、operator、operator!3.2.1、begin()、end()3.2.2、op…