Spring Cloud Alibaba基础教程:SentinelDashboard中修改规则同步到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。用户只需实现 DynamicRuleProviderDynamicRulePublisher 接口,即可实现应用维度推送(URL:/v2/flow)。

这段内容是什么意思呢?简单的说就是 Sentinel Dashboard 通过 DynamicRuleProviderDynamicRulePublisher 两个接口来获取和更新应用的动态规则。

所以,只需要通过这两个接口,实现对配置中心中存储规则的读写,就能实现 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、Namespace都采用了默认值:defaultapplication,这个读者有特殊需求可以做对应的修改。

第六步:实现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.setDataChangeCreateBy(“apollo”);namespaceReleaseDTO.setReleaseBy(“apollo”);**这两句需要注意一下,必须设置存在并且有去权限的用户,不然会更新失败。

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

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

注:本文摘自 程序猿DD-翟永超老师,我是亲自打字了解学习。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Spring Boot + Spring Cloud Alibaba Seata 配置 TCC 模式,需要进行以下步骤: 1. 引入 Seata TCC 的依赖: ```xml <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-seata</artifactId> <version>2.0.3.RELEASE</version> </dependency> ``` 2. 配置 Seata TCC 的相关参数: ```yaml spring: application: name: demo-service # 应用名称 seata: service: group: my_test_tx_group # 事务分组名称 vgroup-mapping.my_test_tx_group: default # 分组所在的虚拟组 enable-degrade: false # 是否开启降级模式,默认为 false use-jdk-proxy: false # 是否使用 JDK 代理,默认为 false config: type: nacos # 配置心类型,可以是 file、nacos、apollo、zk nacos: namespace: seata # 命名空间 server-addr: localhost:8848 # Nacos 服务地址 group: SEATA_GROUP # 配置组 username: nacos # 用户名 password: nacos # 密码 file: name: file.conf # 配置文件名 registry: type: nacos # 注册心类型,可以是 file、nacos、eureka、consul、zk nacos: server-addr: localhost:8848 # Nacos 服务地址 namespace: seata # 命名空间 group: SEATA_GROUP # 注册组 username: nacos # 用户名 password: nacos # 密码 tx-service-group: my_test_tx_group # 事务分组名称 ``` 3. 在需要使用 TCC 模式的方法上使用 @Tcc 注解: ```java @Service public class DemoServiceImpl implements DemoService { @Autowired private AccountService accountService; @Autowired private StorageService storageService; /** * TCC 模式下的分布式事务实现 */ @Override @GlobalTransactional(timeoutMills = 300000, name = "demo-service-tx") public void tccTransaction(String userId, String commodityCode, Integer count) { // 第一步:减少库存 storageService.decrease(commodityCode, count); // 第二步:扣除账户余额 accountService.decrease(userId, count); // 第三步:确认(提交) // do nothing // 第四步:取消(回滚) // do nothing } } ``` 4. 在 Seata 控制台配置相应的 TCC 事务分组。 以上就是在 Spring Boot + Spring Cloud Alibaba Seata 配置 TCC 模式的步骤。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

菜鸟特工007

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值