Nacos1.4源码-服务注册

Nacos1.4使用的都是http通信,nacos2.0之后改为使用grpc通信。

涉及到的核心方法:异步队列+写时复制(copyOnWrite)

1.客户端启动流程

1.验证服务实例

NacosNamingService(核心类)

2.用post调用http请求,注册实例(客户端向服务端发起请求,注册!)

/nacos/v1/ns/instance

(调用jdkHttpClient发起请求)

客户端启动流程:Auto自动装配->EventListener->bind->this.start->register(核心注册的方法)

 2.nacos服务端

添加服务实例:InstanceController#register,代码如下:

@CanDistro
@PostMapping
@Secured(parser = NamingResourceParser.class, action = ActionTypes.WRITE)
public String register(HttpServletRequest request) throws Exception {

    final String namespaceId = WebUtils
    .optional(request, CommonParams.NAMESPACE_ID, Constants.DEFAULT_NAMESPACE_ID);
    final String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME);
    NamingUtils.checkServiceNameFormat(serviceName);

    final Instance instance = parseInstance(request);

    serviceManager.registerInstance(namespaceId, serviceName, instance);
    return "ok";
}

也就是将服务实例添加到服务端的Map中,该Map结构如下:(key-value结构)

Nacos服务注册表结构:Map<namespace, Map<group::serviceName, Service>>

服务拆分后,相同的服务类型放到一个group。比如说将订单服务拆分为支付服务、退货服务等。

接下来,服务端通过createEmptyService中的addInstance添加实例。

DistroConsistencyServiceImpl#onPut(key, value);->tasks.offer(Pair.with(datumKey, action));// 注册的实例丢到内存队列 ArrayBlockingQueue。集群的话会进行节点之间的同步。

DistroConsistencyServiceImpl阿里的分布式一致性协议的实现类Distro

 接下来,Notifier#run从队列中拿出实例-->onChange:真正通过这个线程的run方法来注册实例。调用handle方法注册实例,入口代码如下:

@Override
public void run() {
    Loggers.DISTRO.info("distro notifier started");
    
    for (; ; ) {// 死循环
        try {
            Pair<String, DataOperation> pair = tasks.take();// 拿出实例
            handle(pair);// 注册
        } catch (Throwable e) {
            Loggers.DISTRO.error("[NACOS-DISTRO] Error while handling notifying task", e);
        }
    }
}

之后会将服务实例注册到注册表中,AP架构的注册表为ephemeralInstances,代码如下:

@JsonIgnore
private Set<Instance> ephemeralInstances = new HashSet<>();

ephemeralInstances = toUpdateInstances;// 注册表 存放的实例的地方 是map中的内容

run是什么时候被执行的呢,run方法的类通过@PostConstruct注册成为一个bean,死循环会一直执行,用来检测是否有新实例出现。DistroConsistencyServiceImpl#

private volatile Notifier notifier = new Notifier();

@PostConstruct
public void init() {
    GlobalExecutor.submitDistroNotifyTask(notifier);
}

总结

准实时注册

客户端发起http请求,进行注册

服务端将其放到内存队列中,然后后台线程(单线程)的run方法将实例进行注册,放到set集合中(双层Map中的set)

异步注册:满足高并发的需求,多个实例注册)业务操作都是基于内存的,set是在内存的

 为了防止多节点读写并发冲突,nacos采用写时复制技术

CopyOnWrite:写时复制,写的时候写到备份表,写完后,将表数据合并

读的时候读的是真正的表

复制的时候,存不存在原数据过大的问题?不会的,因为复制的仅仅是ephemeralInstances(set集合),复制到list中,之后的增删改都操作list!

list首先是从cache中拿的,然后会用实际的注册表进行更新健康状态!

 涉及到的代码如下:

Cluster#updateIps():

HashMap<String, Instance> oldIpMap = new HashMap<>(toUpdateInstances.size());// 复制出来的oldMap

ephemeralInstances = toUpdateInstances;// 替换注册表

写时复制的代码如下:

public void updateIps(List<Instance> ips, boolean ephemeral) {// ips新来的实例
        
        Set<Instance> toUpdateInstances = ephemeral ? ephemeralInstances : persistentInstances;
        
        HashMap<String, Instance> oldIpMap = new HashMap<>(toUpdateInstances.size());// 复制出来的oldMap
        
        for (Instance ip : toUpdateInstances) {
            oldIpMap.put(ip.getDatumKey(), ip);// 放到oldIpMap
        }
        
        List<Instance> updatedIPs = updatedIps(ips, oldIpMap.values());// 仅仅拿到list,增删改 都在这个额副本中
        if (updatedIPs.size() > 0) {
            for (Instance ip : updatedIPs) {// 查看 新的实例是不是老实例,是不是配置变化
                Instance oldIP = oldIpMap.get(ip.getDatumKey());
                
                // do not update the ip validation status of updated ips
                // because the checker has the most precise result
                // Only when ip is not marked, don't we update the health status of IP:
                if (!ip.isMarked()) {
                    ip.setHealthy(oldIP.isHealthy());
                }
                
                if (ip.isHealthy() != oldIP.isHealthy()) {
                    // ip validation status updated
                    Loggers.EVT_LOG.info("{} {SYNC} IP-{} {}:{}@{}", getService().getName(),
                            (ip.isHealthy() ? "ENABLED" : "DISABLED"), ip.getIp(), ip.getPort(), getName());
                }
                
                if (ip.getWeight() != oldIP.getWeight()) {
                    // ip validation status updated
                    Loggers.EVT_LOG.info("{} {SYNC} {IP-UPDATED} {}->{}", getService().getName(), oldIP.toString(),
                            ip.toString());
                }
            }
        }
        
        List<Instance> newIPs = subtract(ips, oldIpMap.values());// subtract删除实例的逻辑
        if (newIPs.size() > 0) {
            Loggers.EVT_LOG
                    .info("{} {SYNC} {IP-NEW} cluster: {}, new ips size: {}, content: {}", getService().getName(),
                            getName(), newIPs.size(), newIPs.toString());
            
            for (Instance ip : newIPs) {
                HealthCheckStatus.reset(ip);
            }
        }
        
        List<Instance> deadIPs = subtract(oldIpMap.values(), ips);
        
        if (deadIPs.size() > 0) {
            Loggers.EVT_LOG
                    .info("{} {SYNC} {IP-DEAD} cluster: {}, dead ips size: {}, content: {}", getService().getName(),
                            getName(), deadIPs.size(), deadIPs.toString());
            
            for (Instance ip : deadIPs) {
                HealthCheckStatus.remv(ip);
            }
        }
        
        toUpdateInstances = new HashSet<>(ips);
        
        if (ephemeral) {
            ephemeralInstances = toUpdateInstances;// 替换注册表
        } else {
            persistentInstances = toUpdateInstances;
        }
    }

nacos-sdk-go是一个用于服务发现的开源软件包。它提供了一种简单且可靠的方式来实现服务发现功能,可以帮助开发人员更方便地构建分布式应用程序。 nacos-sdk-go基于Nacos开源项目开发,Nacos是阿里巴巴开源的一个服务发现和配置管理平台。nacos-sdk-go提供了一系列的API和函数,可以用于注册、发现和管理服务。它支持HTTP和GRPC协议,能够与不同编程语言和框架进行集成。 使用nacos-sdk-go进行服务发现非常简单。首先,我们需要在应用程序中导入nacos-sdk-go的包,并初始化一个Nacos客户端。然后,我们可以使用该客户端注册服务、获取服务列表以及注销服务。例如,我们可以使用RegisterInstance函数将一个实例注册Nacos服务注册表中。 当其他应用程序需要使用我们的服务时,它们可以使用nacos-sdk-go的DiscoverInstances函数来获取可用的服务实例列表。这样,我们的服务就可以被其他应用程序发现和使用了。 除了服务发现功能,nacos-sdk-go还提供了一些其他功能,如配置管理、动态配置刷新等。它可以帮助我们更好地管理和维护分布式应用程序的配置和服务。 总结来说,nacos-sdk-go是一个功能强大的服务发现工具,它可以帮助开发人员更方便地构建分布式应用程序。通过使用nacos-sdk-go,我们可以实现服务注册、发现和管理,并能够与其他应用程序进行无缝集成,提高应用程序的可用性和可扩展性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值