Nacos源码学习系列服务端第10篇元数据管理之Jraft一致性更新

目录

从控制台修改服务的元数据

从控制台修改实例的元数据

修改后的结果

​编辑

向JRaftProtocol注册元数据变更处理器

向JRaftProtocol提交元数据变更请求


从控制台修改服务的元数据

从控制台修改实例的元数据

修改后的结果

向JRaftProtocol注册元数据变更处理器

服务在启动的时候通过构造函数进行初始化bean

构造函数里面除了需要自动注入的属性后 还向JRaftProtocol 注册了当前对象处理器。

实例和服务的处理器bean的实例化和注册过程是一样的。

//实例元数据处理器
@Component
public class InstanceMetadataProcessor extends RequestProcessor4CP {
    //统一的元数据管理器 管理服务元数据 实例元数据 过期元数据信息
    private final NamingMetadataManager namingMetadataManager;
    //jraft 消息的序列号器
    private final Serializer serializer;
    //
    private final Type processType;
    //普通的lock 控制读写互斥操作使用再快照的加载和保存操作场景
    //快照的场景本次不细讲本次注意讲解crud
    private final ReentrantReadWriteLock lock;
    //读锁 使用再对内存中的元数据crud操作
    private final ReentrantReadWriteLock.ReadLock readLock;
    
    @SuppressWarnings("unchecked")
    public InstanceMetadataProcessor(NamingMetadataManager namingMetadataManager, 
           ProtocolManager protocolManager) {
        this.namingMetadataManager = namingMetadataManager;
        this.serializer = SerializeFactory.getDefault();

        this.processType = TypeUtils.parameterize(MetadataOperation.class, 
               InstanceMetadata.class);
        this.lock = new ReentrantReadWriteLock();
        this.readLock = lock.readLock();

        //向JRaftProtocol 协议注册 InstanceMetadataProcessor  
        //注册后负责处理JRaft框架底层分发的实例元数据变更任务
        protocolManager.getCpProtocol().
                 addRequestProcessors(Collections.singletonList(this));
    }
    
      ....
    
}

//属性字段跟InstanceMetadataProcessor 是完全一样
public class ServiceMetadataProcessor extends RequestProcessor4CP {
    
    ....
    
    //初始化属性跟InstanceMetadataProcessor 完全一致
    @SuppressWarnings("unchecked")
    public ServiceMetadataProcessor(NamingMetadataManager namingMetadataManager, 
            ProtocolManager protocolManager,
            ServiceStorage serviceStorage) {
        this.namingMetadataManager = namingMetadataManager;
        this.serviceStorage = serviceStorage;
        this.serializer = SerializeFactory.getDefault();
        this.processType = TypeUtils.parameterize(MetadataOperation.class,         
            ServiceMetadata.class);
        this.lock = new ReentrantReadWriteLock();
        this.readLock = lock.readLock();
         //向JRaftProtocol 协议注册 InstanceMetadataProcessor  
        //注册后负责处理JRaft框架底层分发的服务的元数据变更任务
         protocolManager.getCpProtocol().
                addRequestProcessors(Collections.singletonList(this));
    }
}

向JRaftProtocol提交元数据变更请求

服务启动后完成了服务和实例的元数据变更处理器的注册,接下来所有对元数据变更功能只需要向JRaftProtocol提交请求即可。JRaftProtocol 自动完成底层集群节点的一致性同步功能和调用处理器的onApply方法完成更新操作。应用程序只需要实现处理器的处理逻辑即可。

接下来我们看看前端的元数据更新请求是如何向JRaftProtocol提交处理的。

//服务实例控制器
public class InstanceController{ 
....
@CanDistro
    @PutMapping
    @Secured(action = ActionTypes.WRITE)
    public String update(HttpServletRequest request) throws Exception {
        String namespaceId = WebUtils.optional(request, CommonParams.NAMESPACE_ID, 
        Constants.DEFAULT_NAMESPACE_ID);
        String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME);
        NamingUtils.checkServiceNameFormat(serviceName);
        Instance instance = HttpRequestInstanceBuilder.newBuilder()
                .setDefaultInstanceEphemeral(
        switchDomain.isDefaultInstanceEphemeral()).setRequest(request).build();
        //调用InstanceOperatorClientImpl类的方法更新实例方法
        getInstanceOperator().updateInstance(namespaceId, serviceName, instance);
        return "ok";
    }

   ....
}

//服务控制器
public class ServiceController {
    ....

    public String update(HttpServletRequest request) throws Exception {
        String namespaceId = WebUtils.optional(request, CommonParams.NAMESPACE_ID, 
                Constants.DEFAULT_NAMESPACE_ID);
        String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME);
        ServiceMetadata serviceMetadata = new ServiceMetadata();
        serviceMetadata.setProtectThreshold(
            NumberUtils.toFloat(WebUtils.required(request, "protectThreshold")));
                   serviceMetadata.setExtendData(
                UtilsAndCommons.parseMetadata(
              WebUtils.optional(request, "metadata", StringUtils.EMPTY)));
        serviceMetadata.setSelector(parseSelector(WebUtils.optional(request,
              "selector", StringUtils.EMPTY)));
        com.alibaba.nacos.naming.core.v2.pojo.Service service = 
            com.alibaba.nacos.naming.core.v2.pojo.Service
                .newService(namespaceId, NamingUtils.getGroupName(serviceName),
                        NamingUtils.getServiceName(serviceName));
        //调用InstanceOperatorClientImpl类的方法的
        getServiceOperator().update(service, serviceMetadata);
        return "ok";
    }
     ....
}

public class InstanceOperatorClientImpl implements InstanceOperator {

 @Override
    public void updateInstance(String namespaceId, String serviceName, Instance instance) 
         throws NacosException {
        //更加命名空间 服务吗 临时节点标志新建服务对象
        Service service = getService(namespaceId, serviceName, instance.isEphemeral());
        //服务管理器如果不存在该服务就报错 
        if (!ServiceManager.getInstance().containSingleton(service)) {
            throw new NacosException(NacosException.INVALID_PARAM,
                    "service not found, namespace: " + namespaceId + ", service: " + 
                    service);
        }
        //生成metadataId    
        String metadataId = InstancePublishInfo
                .genMetadataId(instance.getIp(), instance.getPort(), 
                instance.getClusterName());
         //调用NamingMetadataOperateService的updateInstanceMetadata 方法
         metadataOperateService.updateInstanceMetadata(service, metadataId, 
                   buildMetadata(instance));
    }

}

//metadataId的生成逻辑 ip:port:cluster
public class InstancePublishInfo {
    public static String genMetadataId(String ip, int port, String cluster) {
        return ip + InternetAddressUtil.IP_PORT_SPLITER + port + 
             InternetAddressUtil.IP_PORT_SPLITER + cluster;
    }
}

我们看到InstanceOperatorClientImpl 的updateInstance方法只是简单了做一个服务的校验和metadataidde生成逻辑就交给NamingMetadataOperateService的updateInstanceMetadata方法处理了。

public class NamingMetadataOperateService {
    /**
     * Update instance metadata.
     *
     * @param service          service of metadata
     * @param metadataId       instance metadataId Id
     * @param instanceMetadata metadata
     */
    public void updateInstanceMetadata(Service service, String metadataId,             
               InstanceMetadata) {
        //构建MetadataOperation对象
        MetadataOperation<InstanceMetadata> operation = buildMetadataOperation(service);
        operation.setTag(metadataId);
        operation.setMetadata(instanceMetadata);

        //构建WriteRequest请求WriteRequest 是定义constency.proto文件中
        WriteRequest operationLog = 
        WriteRequest.newBuilder().setGroup(Constants.INSTANCE_METADATA)               
               .setOperation(DataOperation.CHANGE.name()).
        setData(ByteString.copyFrom(serializer.serialize(operation))).build();
        submitMetadataOperation(operationLog);
    }


 private void submitMetadataOperation(WriteRequest operationLog) {
           ...
            //向JRaftProtocol提交请求
            Response response = cpProtocol.write(operationLog);
            ...
    }

 //根据service 构建 MetadataOperation 对象
 private <T> MetadataOperation<T> buildMetadataOperation(Service service) {
        MetadataOperation<T> result = new MetadataOperation<>();
        result.setNamespace(service.getNamespace());
        result.setGroup(service.getGroup());
        result.setServiceName(service.getName());
        return result;
    }
}

public class MetadataOperation<T> implements Serializable {
    
    private static final long serialVersionUID = -111405695252896706L;
    
    private String namespace;
    
    private String group;
    
    private String serviceName;
    

    private String tag;
    
    private T metadata;

}

//constency.proto文件
//WriteRequest 结构体
message WriteRequest {
  string group = 1;
  string key = 2;
  bytes data = 3;
  string type = 4;
  string operation = 5;
  map<string, string> extendInfo = 6;
}

实际上updateInstanceMetadata这个方法并没有立即更新内存中的元数据而是构建一个包含metadata的OperationMetadata对象 , 使用protol协议构建WriteRequest请求对象提交给JRaftProtocol分发和处理。

上面我们详细解析了实例的元数据变更请求的处理过程,服务的元数据变更请求处理过程原理是一样的。这里不赘述。

下一章节我们讲讲元数据处理器收到JRaftProtocol分发的任务后是如何更新本地的元数据的。敬请期待!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值