Spring Cloud Alibaba基础教程:Sentinel Dashboard同步Apollo存储规则

在之前的两篇教程中我们分别介绍了如何将Sentinel的限流规则存储到Nacos和Apollo中。同时,在文末的思考中,我都指出了这两套整合方案都存在一个不足之处:不论采用什么配置中心,限流规则都只能通过Nacos界面或Apollo界面来完成修改才能得到持久化存储,而在Sentinel Dashboard中修改限流规则虽然可以生效,但是不会被持久化到配置中心。而在这两个配置中心里存储的数据是一个Json格式,当存储的规则越来越多,对该Json配置的可读性与可维护性会变的越来越差。所以,下面我们就来继续探讨这个不足之处,并给出相应的解决方案。本文以Apollo存储为例,下一篇介绍Nacos的改在示例。

问题分析

在实际操作之前,我们先通过下图了解一下之前我们所实现的限流规则持久化方案的配置数据流向图:

  • 蓝色箭头代表了限流规则由配置中心发起修改的更新路径
  • 橙色箭头代表了限流规则由Sentinel Dashboard发起修改的更新路径

从图中可以很明显的看到,Sentinel Dashboard与业务服务之间本身是可以互通获取最新限流规则的,这在没有整合配置中心来存储限流规则的时候就已经存在这样的机制。最主要的区别是:配置中心的修改都可以实时的刷新到业务服务,从而被Sentinel Dashboard读取到,但是对于这些规则的更新到达各个业务服务之后,并没有一个机制去同步到配置中心,作为配置中心的客户端也不会提供这样的逆向更新方法。

改造方案

关于如何改造,现来解读一下官方文档中关于这部分的说明:

要通过 Sentinel 控制台配置集群流控规则,需要对控制台进行改造。我们提供了相应的接口进行适配。

从 Sentinel 1.4.0 开始,我们抽取出了接口用于向远程配置中心推送规则以及拉取规则:

  • DynamicRuleProvider: 拉取规则
  • DynamicRulePublisher: 推送规则

对于集群限流的场景,由于每个集群限流规则都需要唯一的 flowId,因此我们建议所有的规则配置都通过动态规则源进行管理,并在统一的地方生成集群限流规则。

我们提供了新版的流控规则页面,可以针对应用维度推送规则,对于集群限流规则可以自动生成 flowId。用户只需实现 DynamicRuleProvider 和 DynamicRulePublisher 接口,即可实现应用维度推送(URL: /v2/flow)。

这段内容什么意思呢?简单的说就是Sentinel Dashboard通过DynamicRuleProviderDynamicRulePublisher两个接口来获取和更新应用的动态规则。默认情况下,就如上一节中Sentinel Dashboard与各业务服务之间的两个箭头,一个接口负责获取规则,一个接口负责更新规则。

所以,只需要通过这两个接口,实现对配置中心中存储规则的读写,就能实现Sentinel Dashboard中修改规则与配置中心存储同步的效果。

具体的配置数据流向图如下:

其中,绿色箭头为公共公共部分,即:不论从培中心修改,还是从Sentinel Dashboard修改都会触发的操作。这样的话,从上图的两处修改起点看,所有涉及的部分都能获取到一致的限流规则了。

代码实现

下面继续说说具体的代码实现,这里参考了Sentinel Dashboard源码中关于Apollo实现的测试用例。但是由于考虑到与Spring Cloud Alibaba的结合使用,略作修改。

第一步:修改pom.xml中的Apollo OpenAPi的依赖,将<scope>test</scope>注释掉,这样才能在主程序中使用。

<dependency>
    <groupId>com.ctrip.framework.apollo</groupId>
    <artifactId>apollo-openapi</artifactId>
    <version>1.2.0</version>
    <!--<scope>test</scope>-->
</dependency>

第二步:找到resources/app/scripts/directives/sidebar/sidebar.html中的这段代码:

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

修改为:

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

第三步:在com.alibaba.csp.sentinel.dashboard.rule包下新建一个apollo包,用来编写针对Apollo的扩展实现。

第四步:创建Apollo的配置类,定义Apollo的portal访问地址以及第三方应用访问的授权Token(通过Apollo管理员账户登录,在“开放平台授权管理”功能中创建),具体代码如下:

@Configuration
public class ApolloConfig {

    @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 ApolloOpenApiClient apolloOpenApiClient() {
        ApolloOpenApiClient client = ApolloOpenApiClient.newBuilder()
            .withPortalUrl("https://apollo.xxx.com")  // TODO 根据实际情况修改
            .withToken("open api token") // TODO 根据实际情况修改
            .build();
        return client;
    }

}

第五步:实现Apollo的配置拉取实现。

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

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

    @Value("${env:DEV}")
    private String env;

    @Override
    public List<FlowRuleEntity> getRules(String appName) throws Exception {
        // flowDataId对应
        String flowDataId = "sentinel.flowRules";
        OpenNamespaceDTO openNamespaceDTO = apolloOpenApiClient.getNamespace(appName, env, "default", "application");
        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);
    }
}
  • getRules方法中的appName参数是Sentinel中的服务名称,这里直接通过这个名字获取Apollo配置是由于Apollo中的项目AppId与之一致,如果存在不一致的情况,则需要自己做转换。
  • 这里注入了一个env属性,主要由于我们在使用Apollo的时候,通过启动参数来控制不同环境。所以这样就能在不同环境区分不同的限流配置了。
  • 这里的flowDataId对应各个微服务应用中定义的spring.cloud.sentinel.datasource.ds.apollo.flowRulesKey配置,即:Apollo中使用了什么key来存储限流配置。
  • 其他如Cluster、Namepsace都采用了默认值:default和application,这个读者有特殊需求可以做对应的修改。

第六步:实现Apollo的配置推送实现。

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

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

    @Value("${env:DEV}")
    private String env;

    @Override
    public void publish(String app, List<FlowRuleEntity> rules) throws Exception {
        String flowDataId = "sentinel.flowRules";

        AssertUtil.notEmpty(app, "app name cannot be empty");
        if (rules == null) {
            return;
        }

        OpenItemDTO openItemDTO = new OpenItemDTO();
        openItemDTO.setKey(flowDataId);
        openItemDTO.setValue(converter.convert(rules));
        openItemDTO.setComment("modify by sentinel-dashboard");
        openItemDTO.setDataChangeCreatedBy("apollo");
        apolloOpenApiClient.createOrUpdateItem(app, env, "default", "application", openItemDTO);

        // Release configuration
        NamespaceReleaseDTO namespaceReleaseDTO = new NamespaceReleaseDTO();
        namespaceReleaseDTO.setEmergencyPublish(true);
        namespaceReleaseDTO.setReleaseComment("release by sentinel-dashboard");
        namespaceReleaseDTO.setReleasedBy("apollo");
        namespaceReleaseDTO.setReleaseTitle("release by sentinel-dashboard");
        apolloOpenApiClient.publishNamespace(app, env, "default", "application", namespaceReleaseDTO);
    }
}
  • 这里的大部分内容,如:env、flowDataId、app说明与上一步中的实现一致
  • openItemDTO.setDataChangeCreatedBy("apollo");namespaceReleaseDTO.setReleasedBy("apollo");这两句需要注意一下,必须设置存在并且有权限的用户,不然会更新失败。

第七步:修改com.alibaba.csp.sentinel.dashboard.controller.v2.FlowControllerV2DynamicRuleProviderDynamicRulePublisher注入的Bean,改为上面我们编写的针对Apollo的实现:

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

代码示例

本文介绍内容的客户端代码,示例读者可以通过查看下面仓库中的alibaba-sentinel-dashboard-apollo项目:

如果您对这些感兴趣,欢迎star、follow、收藏、转发给予支持!

原文地址:https://www.cnblogs.com/didispace/p/10823776.html

时间: 2024-08-28 07:00:46

Spring Cloud Alibaba基础教程:Sentinel Dashboard同步Apollo存储规则的相关文章

Spring Cloud Alibaba基础教程:使用Nacos实现服务注册与发现

自Spring Cloud Alibaba发布第一个Release以来,就备受国内开发者的高度关注.虽然Spring Cloud Alibaba还没能纳入Spring Cloud的主版本管理中,但是凭借阿里中间件团队的背景,还是得到不少团队的支持:同时,由于Spring Cloud Alibaba中的几项主要功能都直指Netflix OSS中的重要组件,而后者最近频繁宣布各组件不在更新新特性,这使得Spring Cloud Alibaba关注度不断飙升,不少开发者或团队也开始小范围试水.笔者对此

Spring Cloud Alibaba基础教程:支持的几种服务消费方式(RestTemplate、WebClient、Feign)

通过<Spring Cloud Alibaba基础教程:使用Nacos实现服务注册与发现>一文的学习,我们已经学会如何使用Nacos来实现服务的注册与发现,同时也介绍如何通过LoadBalancerClient接口来获取某个服务的具体实例,并根据实例信息来发起服务接口消费请求.但是这样的做法需要我们手工的去编写服务选取.链接拼接等繁琐的工作,对于开发人员来说非常的不友好.所以接下来,我们再来看看除此之外,还支持哪些其他的服务消费方式. 使用RestTemplate 在之前的例子中,已经使用过R

Spring Cloud Alibaba基础教程:Nacos配置的加载规则详解

前情回顾: <Spring Cloud Alibaba基础教程:使用Nacos实现服务注册与发现> <Spring Cloud Alibaba基础教程:支持的几种服务消费方式(RestTemplate.WebClient.Feign)> <Spring Cloud Alibaba基础教程:使用Nacos作为配置中心> 上一篇,我们学习了如何在Nacos中创建配置,以及如何使用Spring Cloud Alibaba的Nacos客户端模块来加载配置.在入门例子中,我们只配

Spring Cloud Alibaba基础教程:Nacos配置的多文件加载与共享配置

前情回顾: <Spring Cloud Alibaba基础教程:使用Nacos实现服务注册与发现> <Spring Cloud Alibaba基础教程:支持的几种服务消费方式> <Spring Cloud Alibaba基础教程:使用Nacos作为配置中心> <Spring Cloud Alibaba基础教程:Nacos配置的加载规则详解> <Spring Cloud Alibaba基础教程:Nacos配置的多环境管理> 对于Nacos作为配置中

Spring Cloud Alibaba基础教程:Nacos的数据持久化

前情回顾: <Spring Cloud Alibaba基础教程:使用Nacos实现服务注册与发现> <Spring Cloud Alibaba基础教程:支持的几种服务消费方式> <Spring Cloud Alibaba基础教程:使用Nacos作为配置中心> <Spring Cloud Alibaba基础教程:Nacos配置的加载规则详解> <Spring Cloud Alibaba基础教程:Nacos配置的多环境管理> <Spring C

Spring Cloud Alibaba基础教程:Sentinel使用Apollo存储规则

上一篇我们介绍了如何通过Nacos的配置功能来存储限流规则.Apollo是国内用户非常多的配置中心,所以,今天我们继续说说Spring Cloud Alibaba Sentinel中如何将流控规则存储在Apollo中. 使用Apollo存储限流规则 Sentinel自身就支持了多种不同的数据源来持久化规则配置,目前包括以下几种方式: 文件配置 Nacos配置 ZooKeeper配置 Apollo配置 本文我们就来一起动手尝试一下,如何使用Apollo来存储限流规则. 准备工作 下面我们将同时使用

Spring Cloud Alibaba与Spring Boot/Cloud之间不得不说的版本关系

这篇博文是临时增加出来的内容,主要是由于最近连载<Spring Cloud Alibaba基础教程>系列的时候,碰到读者咨询的大量问题中存在一个比较普遍的问题:版本的选择.其实这类问题,在之前写Spring Cloud基础教程的时候,就已经发过一篇<聊聊Spring Cloud版本的那些事儿>,来说明Spring Boot和Spring Cloud版本之间的关系. Spring Cloud Alibaba现阶段版本的特殊性 现在的Spring Cloud Alibaba由于没有纳入

Spring Cloud Alibaba | Sentinel:分布式系统的流量防卫兵基础实战

Spring Cloud Alibaba | Sentinel:分布式系统的流量防卫兵基础实战 Springboot: 2.1.8.RELEASE SpringCloud: Greenwich.SR2 1. Sentinel控制台概述 在介绍入门实战之前,先来介绍一下Sentinel.Sentinel控制台提供一个轻量级的开源控制台,它提供机器发现以及健康情况管理.监控(单机和集群),规则管理和推送的功能. Sentinel控制台主要功能: 查看机器列表以及健康情况:收集 Sentinel 客户

Spring Cloud Alibaba | Sentinel: 服务限流基础篇

目录 Spring Cloud Alibaba | Sentinel: 服务限流基础篇 1. 简介 2. 定义资源 2.1 主流框架的默认适配 2.2 抛出异常的方式定义资源 2.3 返回布尔值方式定义资源 2.4 注解方式定义资源 2.5 异步调用支持 3. 规则的种类 3.1 流量控制规则 (FlowRule) 3.2 熔断降级规则 (DegradeRule) 3.3 系统保护规则 (SystemRule) 3.4 访问控制规则 (AuthorityRule) Spring Cloud Al