eureka源码解析——服务注册流程


一、服务注册源码

1.1 服务注册入口ApplicationResource#addInstance

eureka中使用的web框架是jersey,和springMVC差不多,这里重点就是调用注册表注册服务

在这里插入图片描述

1.1.1 PeerAwareInstanceRegistryImpl#register

这里重点有两个步骤

  1. 更新本地注册表,把待注册的实例添加到本地注册表中。
  2. 同步给集群间其他节点。

在这里插入图片描述

1.1.1.1 AbstractInstanceRegistry#register

这里代码比较长重要有以下这几个步骤

  1. 更新注册表信息,这里注册表就是一个map(key是appName,value是Lease(InstanceInfo)),这个lease其实就是租约的相关信息,其中会包含实例信息,ip,port和最后一次续约的时间戳,租期等,这里如果判断之前在注册表中就存在的话,看有没有变更过,通过变更时间来判断,如果没有,则继续使用原有的instance信息。如果是第一次注册肯定注册表里没有实例信息,那么就会将expectedNumberOfClientsSendingRenew+1,这个表示需要续约的客户端数量,然后就是调用updateRenewsPerMinThreshold更新下一接受续约的最少的阈值(跟自我保护有关,后续会讲),然后生成租约信息放入注册表中。
  2. 塞入最近改变队列中,更新最后更新时间,这里最近改变队列
  3. 失效本地缓存(服务发现的时候会先去本地的一级二级缓存中获取,没有的话才会才回去注册表中查找)
    在这里插入图片描述
    public void register(InstanceInfo registrant, int leaseDuration, boolean isReplication) {
        // 获取读锁
        read.lock();
        try {
            // 先从注册表中 获取对应 appName 的 map 集合
            Map<String, Lease<InstanceInfo>> gMap = registry.get(registrant.getAppName());
            REGISTER.increment(isReplication);
            // 不存在就创建,并且塞入 appName 的 map 集合
            if (gMap == null) {
                final ConcurrentHashMap<String, Lease<InstanceInfo>> gNewMap =
                        new ConcurrentHashMap<String, Lease<InstanceInfo>>();
                // 存在就不会 put ,并将存在的那个返回来,不能存在的话进行 put ,返回 null
                // 试想该地使用 putIfAbsent 的作用 : double check, 虽然使用了concurrentHashMap
                // 保证了元素的增删改查没有问题,但是还是不能保证 gNewMap 只存在一个
                gMap = registry.putIfAbsent(registrant.getAppName(), gNewMap);
                if (gMap == null) {
                    gMap = gNewMap;
                }
            }
            // 获取该实例 id 对应的租约信息
            Lease<InstanceInfo> existingLease = gMap.get(registrant.getId());
            // Retain the last dirty timestamp without overwriting it, if there is already a lease
            // 如果是存在
            if (existingLease != null && (existingLease.getHolder() != null)) {
                Long existingLastDirtyTimestamp = existingLease.getHolder().getLastDirtyTimestamp();
                Long registrationLastDirtyTimestamp = registrant.getLastDirtyTimestamp();
                logger.debug("Existing lease found (existing={}, provided={}", existingLastDirtyTimestamp, registrationLastDirtyTimestamp);

                // this is a > instead of a >= because if the timestamps are equal, we still take the remote transmitted
                // InstanceInfo instead of the server local copy.
                if (existingLastDirtyTimestamp > registrationLastDirtyTimestamp) {
                    logger.warn("There is an existing lease and the existing lease's dirty timestamp {} is greater" +
                            " than the one that is being registered {}", existingLastDirtyTimestamp, registrationLastDirtyTimestamp);
                    logger.warn("Using the existing instanceInfo instead of the new instanceInfo as the registrant");
                    registrant = existingLease.getHolder();
                }
                // 如不存在的话
            } else {
                // The lease does not exist and hence it is a new registration
                synchronized (lock) {
                    // 这个是与自我保护机制有关的
                    if (this.expectedNumberOfClientsSendingRenews > 0) {
                        // Since the client wants to register it, increase the number of clients sending renews
                        // 每有一个新的客户端注册进来,就会 +1 ,标识回来要发送心跳的客户端 +1
                        this.expectedNumberOfClientsSendingRenews = this.expectedNumberOfClientsSendingRenews + 1;
                        // 更新下自己能容忍的最少心跳数量
                        updateRenewsPerMinThreshold();
                    }
                }
                logger.debug("No previous lease information found; it is new registration");
            }
            Lease<InstanceInfo> lease = new Lease<>(registrant, leaseDuration);
            if (existingLease != null) {
                // 服务启动时间ServiceUp
                lease.setServiceUpTimestamp(existingLease.getServiceUpTimestamp());
            }
            // 塞到注册表中
            gMap.put(registrant.getId(), lease);
            // 放到registed 队列中
            recentRegisteredQueue.add(new Pair<Long, String>(
                    System.currentTimeMillis(),
                    registrant.getAppName() + "(" + registrant.getId() + ")"));
            // This is where the initial state transfer of overridden status happens
            if (!InstanceStatus.UNKNOWN.equals(registrant.getOverriddenStatus())) {
                logger.debug("Found overridden status {} for instance {}. Checking to see if needs to be add to the "
                        + "overrides", registrant.getOverriddenStatus(), registrant.getId());
                if (!overriddenInstanceStatusMap.containsKey(registrant.getId())) {
                    logger.info("Not found overridden id {} and hence adding it", registrant.getId());
                    overriddenInstanceStatusMap.put(registrant.getId(), registrant.getOverriddenStatus());
                }
            }
            // 从本地缓存中获取该实例状态
            InstanceStatus overriddenStatusFromMap = overriddenInstanceStatusMap.get(registrant.getId());
            if (overriddenStatusFromMap != null) {
                // 存在的话设置进去
                logger.info("Storing overridden status {} from map", overriddenStatusFromMap);
                registrant.setOverriddenStatus(overriddenStatusFromMap);
            }

            // Set the status based on the overridden status rules
            InstanceStatus overriddenInstanceStatus =
                    getOverriddenInstanceStatus(registrant, existingLease, isReplication);
            registrant.setStatusWithoutDirty(overriddenInstanceStatus);

            // If the lease is registered with UP status, set lease service up timestamp
            // 实例状态是 up 的话,设置下服务的启动时间
            if (InstanceStatus.UP.equals(registrant.getStatus())) {
                lease.serviceUp();
            }
            registrant.setActionType(ActionType.ADDED);
            // 塞入最近改变队列中
            recentlyChangedQueue.add(new RecentlyChangedItem(lease));
            // 更新最后更新时间
            registrant.setLastUpdatedTimestamp();
            // 本地缓存失效
            invalidateCache(registrant.getAppName(), registrant.getVIPAddress(), registrant.getSecureVipAddress());
            logger.info("Registered instance {}/{} with status {} (replication={})",
                    registrant.getAppName(), registrant.getId(), registrant.getStatus(), isReplication);
        } finally {
            read.unlock();
        }
    }
1.1.1.2 AbstractInstanceRegistry#getDeltaRetentionTask

上面我们把租约信息放到最近改变队列中,然后我们看在什么时候从队列中获取值的,在这个方法中会去遍历队列中的值,这里其实就是在队列中保留三分钟,三分钟过后就从队列中删掉,会有一个定时任务定时调用这个方法,这个后续增量获取的时候会说,大家现在只需要知道这个队列中会保存三分钟内改变信息。


    protected AbstractInstanceRegistry(EurekaServerConfig serverConfig, EurekaClientConfig clientConfig, ServerCodecs serverCodecs) {
        this.serverConfig = serverConfig;
        this.clientConfig = clientConfig;
        this.serverCodecs = serverCodecs;
        this.recentCanceledQueue = new CircularQueue<Pair<Long, String>>(1000);
        this.recentRegisteredQueue = new CircularQueue<Pair<Long, String>>(1000);

        this.renewsLastMin = new MeasuredRate(1000 * 60 * 1);

        this.deltaRetentionTimer.schedule(getDeltaRetentionTask(),
                serverConfig.getDeltaRetentionTimerIntervalInMs(),
                serverConfig.getDeltaRetentionTimerIntervalInMs());
    }
    
   private TimerTask getDeltaRetentionTask() {
        return new TimerTask() {

            @Override
            public void run() {
                Iterator<RecentlyChangedItem> it = recentlyChangedQueue.iterator();
                while (it.hasNext()) {
                    if (it.next().getLastUpdateTime() <
                            System.currentTimeMillis() - serverConfig.getRetentionTimeInMSInDeltaQueue()) {
                        it.remove();
                    } else {
                        break;
                    }
                }
            }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值