nacos多人发布冲突问题

1 篇文章 0 订阅
前言

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service的首字母简称,一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。

作为一个后台开发,nacos是我经常用到的一款集注册中心、配置中心于一身的平台,简单的配置启动,然后应用注册即可使用,还有简洁明了使用的UI页面,点个赞先!

贴上官网地址:
https://nacos.io/

问题及处理
问题

在使用nacos页面更改配置并发布的时候发现一个问题:

当两个人A和B都打开了某个配置的编辑页面,都进行了修改,然后点了发布,则会出现后点发布的B提交的配置生效,因为会覆盖前者A发布的版本,而此时如果没做比对或确认的话A就会没有察觉,从而导致可能的一些问题…

复现

该问题也很好复现,两个人直接按照步骤操作即可,一个人的话通过两个浏览器来模拟:

1、通过浏览器A打开nacos UI页面,找到一个配置文件,点击编辑,打开编辑页面;

2、通过浏览器B打开nacos UI页面,也找到刚刚打开的那个配置文件,点击编辑,打开编辑页面;

3、在浏览器A打开的nacos配置编辑页面对配置进行变更修改,然后点击发布;

4、在浏览器B打开的nacos配置编辑页面也对配置进行变更修改,然后点击发布;

5、再次查看nacos上这个配置文件的配置信息,会发现呈现的是浏览器B编辑发布后的结果;

处理

思路:在发布之前进行MD5比对!拿到源码,本地对逻辑进行变更,然后编译打包使用…

代码修改处如下:

1、com.alibaba.nacos.config.server.model.form.ConfigForm

增加md5参数字段

package com.alibaba.nacos.config.server.model.form;

import com.alibaba.nacos.api.exception.api.NacosApiException;
import com.alibaba.nacos.api.model.v2.ErrorCode;
import com.alibaba.nacos.common.utils.StringUtils;
import org.springframework.http.HttpStatus;

import java.io.Serializable;
import java.util.Objects;

public class ConfigForm implements Serializable {
    
    // ... 代码省略

    private String md5;
    
    public ConfigForm() {
    }
    
    public ConfigForm(String dataId, String group, String namespaceId, String content, String tag, String appName,
            String srcUser, String configTags, String desc, String use, String effect, String type, String schema,
                      String md5) {
        this.dataId = dataId;
        this.group = group;
        this.namespaceId = namespaceId;
        this.content = content;
        this.tag = tag;
        this.appName = appName;
        this.srcUser = srcUser;
        this.configTags = configTags;
        this.desc = desc;
        this.use = use;
        this.effect = effect;
        this.type = type;
        this.schema = schema;
        this.md5 = md5;
    }
    
    // ... 代码省略

    public String getMd5() {
        return md5;
    }

    public void setMd5(String md5) {
        this.md5 = md5;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        ConfigForm configForm = (ConfigForm) o;
        return dataId.equals(configForm.dataId) && group.equals(configForm.group) && Objects.equals(namespaceId, configForm.namespaceId)
                && content.equals(configForm.content) && Objects.equals(tag, configForm.tag) && Objects
                .equals(appName, configForm.appName) && Objects.equals(srcUser, configForm.srcUser) && Objects
                .equals(configTags, configForm.configTags) && Objects.equals(desc, configForm.desc) && Objects
                .equals(use, configForm.use) && Objects.equals(effect, configForm.effect) && Objects
                .equals(type, configForm.type) && Objects.equals(schema, configForm.schema)
                && Objects.equals(md5, configForm.md5);
    }
    
    @Override
    public int hashCode() {
        return Objects.hash(dataId, group, namespaceId, content, tag, appName, srcUser, configTags, desc, use, effect, type,
                schema, md5);
    }
    
    @Override
    public String toString() {
        return "ConfigVo{" +
                "dataId='" + dataId + '\'' +
                ", group='" + group + '\'' +
                ", namespaceId='" + namespaceId + '\'' +
                ", content='" + content + '\'' +
                ", tag='" + tag + '\'' +
                ", appName='" + appName + '\'' +
                ", srcUser='" + srcUser + '\'' +
                ", configTags='" + configTags + '\'' +
                ", desc='" + desc + '\'' +
                ", use='" + use + '\'' +
                ", effect='" + effect + '\'' +
                ", type='" + type + '\'' +
                ", schema='" + schema + '\'' +
                ", md5='" + md5 + '\'' +
                '}';
    }

    /**
     * Validate.
     *
     * @throws NacosApiException NacosApiException.
     */
    public void validate() throws NacosApiException {
        if (StringUtils.isBlank(dataId)) {
            throw new NacosApiException(HttpStatus.BAD_REQUEST.value(), ErrorCode.PARAMETER_MISSING,
                    "Required parameter 'dataId' type String is not present");
        } else if (StringUtils.isBlank(group)) {
            throw new NacosApiException(HttpStatus.BAD_REQUEST.value(), ErrorCode.PARAMETER_MISSING,
                    "Required parameter 'group' type String is not present");
        } else if (StringUtils.isBlank(content)) {
            throw new NacosApiException(HttpStatus.BAD_REQUEST.value(), ErrorCode.PARAMETER_MISSING,
                    "Required parameter 'content' type String is not present");
        }
    }
}

2、com.alibaba.nacos.config.server.controller.ConfigController#publishConfig

添加md5入参,前端有传,直接接收

@PostMapping
    @TpsControl(pointName = "ConfigPublish")
    @Secured(action = ActionTypes.WRITE, signType = SignType.CONFIG)
    public Boolean publishConfig(HttpServletRequest request, HttpServletResponse response,
            @RequestParam(value = "dataId") String dataId,
            @RequestParam(value = "group") String group,
            @RequestParam(value = "tenant", required = false, defaultValue = StringUtils.EMPTY) String tenant,
            @RequestParam(value = "content") String content, @RequestParam(value = "tag", required = false) String tag,
            @RequestParam(value = "appName", required = false) String appName,
            @RequestParam(value = "src_user", required = false) String srcUser,
            @RequestParam(value = "config_tags", required = false) String configTags,
            @RequestParam(value = "desc", required = false) String desc,
            @RequestParam(value = "use", required = false) String use,
            @RequestParam(value = "effect", required = false) String effect,
            @RequestParam(value = "type", required = false) String type,
            @RequestParam(value = "schema", required = false) String schema,
            @RequestParam(value = "md5", required = false) String md5) throws NacosException {
        
        // ... 代码省略
        configForm.setMd5(md5);

        // ... 代码省略
       
        return configOperationService.publishConfig(configForm, configRequestInfo, encryptedDataKey);
    }

3、com.alibaba.nacos.config.server.service.ConfigOperationService#publishConfig

添加校验逻辑

public Boolean publishConfig(ConfigForm configForm, ConfigRequestInfo configRequestInfo, String encryptedDataKey)
            throws NacosException {
        
        // ... 代码省略

        ConfigInfo oldConfigInfo = configInfoPersistService.findConfigInfo(configInfo.getDataId(), configInfo.getGroup(),
                configInfo.getTenant());
        String oldConfigInfoMd5 = oldConfigInfo.getMd5();
        String curMd5 = configForm.getMd5();
        if (!StringUtils.equals(curMd5, oldConfigInfoMd5)) {
            // 传进来的上一版本md5和数据库里现在的md5不相等,表示在此之前其他用户已更新,不能直接覆盖
            throw new NacosApiException(HttpStatus.METHOD_NOT_ALLOWED.value(), ErrorCode.RESOURCE_CONFLICT, "已有其他用户更新了此配置,请先更新再修改发布!");
        }
        
        // ... 代码省略
        
        return true;
    }

4、编译打包

mvn -Prelease-nacos -Dmaven.test.skip=true clean install -U  

5、拿到打包后的新包使用即可

新包路径:项目代码路径/distribution/target

复测

再次测试结果符合预期!

结语

到此这个问题就可以如愿解决了,欢迎留言交流!

如果您看到了这里,欢迎和我沟通交流!
             一个95后码农

个人博客:fy-blog

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Nacos中,多人可以通过配置标签和描述来实现配置的分类和管理。配置标签可以帮助用户更好、更灵活地对配置进行分类,并支持多人或跨团队协作管理配置。此外,Nacos还提供了配置订阅者即监听者查询能力,通过监听者查询功能,用户可以查看当前订阅配置的监听者,并获取客户端当前配置的MD5校验值,以便于检查配置变更是否已推送到客户端。这些功能可以帮助多人对配置进行管控。 此外,Nacos还提供了命名空间管理功能,可以帮助用户对不同的配置进行隔离和管理。通过命名空间管理,可以将配置按照不同的命名空间进行划分,以便于不同团队或用户对配置进行独立管理。 如果需要在多人使用Nacos时进行管控,可以考虑以下几点: 1. 使用配置标签进行分类和管理,可以根据需求创建不同的标签,并将配置按照标签进行分类,方便多人协作管理。 2. 添加配置描述,可以在配置中添加描述信息,帮助其他人理解配置的用途和变更内容。 3. 使用命名空间进行配置的隔离和管理,可以根据不同的团队或用户创建不同的命名空间,将配置进行划分,实现独立管理。 4. 定期检查配置变更是否已推送到客户端,可以通过监听者查询功能查看订阅者情况,并使用MD5校验值来确认配置变更是否生效。 通过以上方法,多人可以更好地对Nacos中的配置进行管控和协作管理。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [Nacos(一)Linux部署Nacos单机环境(兼容Nacos1.x与2.x)](https://blog.csdn.net/zhuocailing3390/article/details/123056124)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值