Sentinel 持久化热点规则出现的问题:objectMapper不能将规则json转换成ParamFlowRule

vsnjm48y  于 2022-10-19  发布在  其他
关注(0)|答案(8)|浏览(395)

Issue Description

Type: bug report

新增一个热点规则时,传来的json数据不能转换成com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule

收到的json(即图中的ruleStr):

{"app":"sentinel","gmtModified":1598930162707,"port":8723,"ip":"192.168.0.190","rule":{"burstCount":0,"clusterConfig":{"fallbackToLocalWhenFail":true,"sampleCount":10,"thresholdType":0,"windowIntervalMs":1000},"clusterMode":false,"controlBehavior":0,"count":1.0,"durationInSec":1,"grade":1,"limitApp":"default","maxQueueingTimeMs":0,"paramFlowItemList":[],"paramIdx":0,"resource":"a"},"id":18,"gmtCreate":1598930162707}

readValue执行后得到的Object:

控制台是模仿源码中的nacos流控规则改造的

publisher:

controller

个人觉得原因是ParamFlowRule 和 ParamFlowRuleEntity 结构不一致导致的。希望可以得到解决的方法

mjqavswn

mjqavswn1#

想到两种方式供参考下:
1.修改 ParamFlowRuleEntity ,不继承 AbstractRuleEntity<ParamFlowRule> 而是跟 FlowRuleEntity 一样实现 RuleEntity ,把 ParamFlowRule 里的属性进来,保持Entity为统一的格式。
2.对于 ParamFlowRuleEntity , AuthorityRuleEntity 这两类规则实体,实现单独的 Converter ,取 AbstractRuleEntity 里的rule做转换。

PR #1453 里是用的第1种方式,它可以复用统一的 Converter

关联issue: #1257

l7wslrjt

l7wslrjt2#

我这里解决了,可参考 https://github.com/Gasonzhong/sentinel-zookeeper-dashboard
用新的entity和实现单独的Converter

q3qa4bjr

q3qa4bjr3#

+1 ,我是自己在服务里新加了一个 ParamFlowRuleEntity 解决的,但是感觉不够同一,最好把这个类放到core 包里,这样可以直接访问到就行了

oprakyz7

oprakyz74#

原因是:改造dashboard,提交到nacos配置中心的数据是ParamFlowRuleEntity类型,微服务拉取配置要解析的是ParamFlowRule类型,会导致规则解析丢失数据,造成热点规则不生效。
我用了两种方式解决了这个问题:
第一种:自定义一个解析热点规则配置的解析器FlowParamJsonConverter,继承JsonConverter,重写convert方法。然后利用后置处理器替换beanName为"param-flow-rules-sentinel-nacos-datasource"的converter属性,注入FlowParamJsonConverter。
第二种:改造Sentinel Dashboard控制台,发布配置时将ParamFlowRuleEntity转成ParamFlowRule类型,再发布到Nacos配置中心。从配置中心拉取配置后将ParamFlowRule转成ParamFlowRuleEntity。

x7rlezfr

x7rlezfr5#

原因是:改造dashboard,提交到nacos配置中心的数据是ParamFlowRuleEntity类型,微服务拉取配置要解析的是ParamFlowRule类型,会导致规则解析丢失数据,造成热点规则不生效。
我用了两种方式解决了这个问题:
第一种:自定义一个解析热点规则配置的解析器FlowParamJsonConverter,继承JsonConverter,重写convert方法。然后利用后置处理器替换beanName为"param-flow-rules-sentinel-nacos-datasource"的converter属性,注入FlowParamJsonConverter。
第二种:改造Sentinel Dashboard控制台,发布配置时将ParamFlowRuleEntity转成ParamFlowRule类型,再发布到Nacos配置中心。从配置中心拉取配置后将ParamFlowRule转成ParamFlowRuleEntity。

使用了第二种方法,但是热点规则还是失效

l7wslrjt

l7wslrjt6#

感觉主要的问题在于ParamFlowRule不包含app, ip 跟 port字段,所以序列化后会丢失这些信息,而dashboard后台又是需要这些信息的。

我自己搭建的dashboard反正去掉了ip跟port的单台机器限流配置,所以我是这样改的(只改dashboard代码,客户端不动)。。供参考。

  1. convert加一层转化
@Bean
    public Converter<List<ParamFlowRuleEntity>, String> paramFlowRuleEntityEncoder() {
        return source -> {
            if (source == null || source.isEmpty()) {
                return EMPTY_LIST_JSON_STRING;
            }
            List<ParamFlowRule> paramFlowRules = source.stream().map(AbstractRuleEntity::toRule).collect(Collectors.toList());
            return JSON.toJSONString(paramFlowRules);
        };
    }

    @Bean
    public Converter<String, List<ParamFlowRuleEntity>> paramFlowRuleEntityDecoder() {
        return source -> {
            if (StringUtil.isBlank(source) || StringUtil.equals(source, StringUtil.EMPTY)) {
                return Collections.emptyList();
            }

            List<ParamFlowRule> paramFlowRules = JSON.parseArray(source, ParamFlowRule.class);
            return paramFlowRules.stream().map(ParamFlowRuleEntity::fromParamFlowRule).collect(Collectors.toList());
        };
    }
  1. 这样转化会丢失关键的app信息,但ip跟port对我来说不是必须的,所以在DynamicRuleProvider再包一层加上app信息就行
@Override
    public List<ParamFlowRuleEntity> getRules(String appName) throws Exception {
        String rules = configService.getConfig(appName + NacosConfigConstants.PARAM_FLOW_DATA_ID_POSTFIX,
                NacosConfigConstants.GROUP_ID, 3000);
        if (StringUtil.isEmpty(rules)) {
            return new ArrayList<>();
        }
        List<ParamFlowRuleEntity> paramFlowRuleEntityList = converter.convert(rules);
        for (ParamFlowRuleEntity paramFlowRuleEntity : paramFlowRuleEntityList) {
            paramFlowRuleEntity.setApp(appName);
        }
        return paramFlowRuleEntityList;
    }

如果需要用到ip跟port的其实可以改下ParamFlowRuleEntity,使其成员变量向ParamFlowRule靠,然后加一些互转的方法。也就是前面cdfive提到的方法1。

rjjhvcjd

rjjhvcjd7#

这是来自QQ邮箱的假期自动回复邮件。   您好,我最近正在休假中,无法亲自回复您的邮件。我将在假期结束后,尽快给您回复。

xfyts7mz

xfyts7mz8#

把AuthorityRuleEntity类里面的get方法的 @JsonIgnore和@JSONField(serialize = false)注解去掉怎么样?
`public class AuthorityRuleEntity extends AbstractRuleEntity {

public AuthorityRuleEntity() {
}

public AuthorityRuleEntity(AuthorityRule authorityRule) {
    AssertUtil.notNull(authorityRule, "Authority rule should not be null");
    this.rule = authorityRule;
}

public static AuthorityRuleEntity fromAuthorityRule(String app, String ip, Integer port, AuthorityRule rule) {
    AuthorityRuleEntity entity = new AuthorityRuleEntity(rule);
    entity.setApp(app);
    entity.setIp(ip);
    entity.setPort(port);
    return entity;
}

@JsonIgnore
@JSONField(serialize = false)
public String getLimitApp() {
    return rule.getLimitApp();
}

@JsonIgnore
@JSONField(serialize = false)
public String getResource() {
    return rule.getResource();
}

@JsonIgnore
@JSONField(serialize = false)
public int getStrategy() {
    return rule.getStrategy();
}

}`

相关问题