Eureka注册中心源码解析

SpringCloud组件

Eureka注册中心

EurekaInstanceConfigBean eureka的基本配置类信息Bean
     ~~~~     ->CloudEurekaInstanceConfig Cloud的eureka所需的基本配置信息
     ~~~~           ~~~~     ->EurekaInstanceConfig eureka注册所需要的配置信息
     ~~~~     ->EnvironmentAware 环境设置
     ~~~~           ~~~~     ->Aware 标记接口,用于子类实现具体的方法,便于回调

EurekaInstanceConfig

eureka注册所需要的配置信息,其中id和appname是唯一必须的

    @ImplementedBy(CloudInstanceConfig.class)  //指定接口的默认实现类
    public interface EurekaInstanceConfig {
    }

服务发现(register)

InstanceRegistry
     ~~~~     -> PeerAwareInstanceRegistryImpl
     ~~~~           ~~~~     -> AbstractInstanceRegistry 处理来自客户端的所有请求
     ~~~~           ~~~~     -> InstanceRegistry
     ~~~~           ~~~~           ~~~~     -> LeaseManager InstanceInfo:包含注册类所有信息[租约管理] 定义register\cancel\renew\evict服务
     ~~~~           ~~~~           ~~~~     -> LookupService 一个找寻存活实例的服务[查找服务]
     ~~~~     -> PeerAwareInstanceRegistry 应用注册表接口,提供集群类信息的同步任务
     ~~~~           ~~~~     ->InstanceRegistry
     ~~~~           ~~~~           ~~~~     -> LeaseManager InstanceInfo:包含注册类所有信息[租约管理] 定义register\cancel\renew\evict服务
     ~~~~           ~~~~           ~~~~     -> LookupService 一个找寻存活实例的服务[查找服务]
     ~~~~           ~~~~     -> ApplicationContextAware 设置上下文

过程
1. ApplicationResource#addInstance()方法接收到来自客户端的注册请求
     @POST
     @Consumes({"application/json", "application/xml"})
     public Response addInstance(InstanceInfo info,
                                 @HeaderParam(PeerEurekaNode.HEADER_REPLICATION) String isReplication) {
         // 。。。
          registry.register(info, "true".equals(isReplication));
         // 。。。
     }
2. PeerAwareInstanceRegistryImpl#register(...)注册应用实例信息
```java
    /**
    复制节点信息到其他对等的eureka节点,如果是其他副本节点的信息,则不用复制
    */
    @Singleton
    public class PeerAwareInstanceRegistryImpl extends AbstractInstanceRegistry implements PeerAwareInstanceRegistry {
        @Override
        public void register(final InstanceInfo info, final boolean isReplication) {
            int leaseDuration = Lease.DEFAULT_DURATION_IN_SECS;  //心跳时间默认是90s
            //如果用户有自定义,则用自定义的时间,Eureka.instance.lease-expiration-duration-in-seconds=180 这个参数设置
            if (info.getLeaseInfo() != null && info.getLeaseInfo().getDurationInSecs() > 0) {  
                leaseDuration = info.getLeaseInfo().getDurationInSecs();
            }
            //调用父类的注册,注册到循环列表private final CircularQueue<Pair<Long, String>> recentRegisteredQueue;
            super.register(info, leaseDuration, isReplication);
            //向其他节点复制。
            //通过isReplication判断信息是来自client还是其他副本节点
            replicateToPeers(Action.Register, info.getAppName(), info.getId(), info, null, isReplication);
        }
    }
```
3. AbstractInstanceRegistry#register(...) 注册实例信息

其中有几个重要的实体类

    public class Lease<T> {
         enum Action {
        Register, Cancel, Renew
        };
        //默认心跳时间
        public static final int DEFAULT_DURATION_IN_SECS = 90;
        //注册实体类
        private T holder;
        //取消注册时间戳
        private long evictionTimestamp;
        //注册开始时间戳
        private long registrationTimestamp;
        //服务开始时间戳
        private long serviceUpTimestamp;
        //最后更新时间戳
        private volatile long lastUpdateTimestamp;
        //租约持续的时间
        private long duration;

        public Lease(T r, int durationInSecs) {
            holder = r;
            registrationTimestamp = System.currentTimeMillis();
            lastUpdateTimestamp = registrationTimestamp;
            duration = (durationInSecs * 1000);

        }
        //。。。
    }

    /**
    * 注册一个实例
    * registrant 实例具体信息
    * leaseDuration 心跳时间
    * isReplication 是否复制
    */
    public abstract class AbstractInstanceRegistry implements InstanceRegistry {
        public void register(InstanceInfo registrant, int leaseDuration, boolean isReplication) {
            read.lock();
            try {
                Map<String, Lease<InstanceInfo>> gMap = registry.get(registrant.getAppName());
                //省略...
                Lease<InstanceInfo> existingLease = gMap.get(registrant.getId());
                //省略...
                //创建租约
                Lease<InstanceInfo> lease = new Lease<InstanceInfo>(registrant, leaseDuration);
                if (existingLease != null) {
                    //设置租约提供服务开始时间
                    lease.setServiceUpTimestamp(existingLease.getServiceUpTimestamp());
                }
                //添加到租约映射
                gMap.put(registrant.getId(), lease);
                //添加到最近注册的循环队列中   private final CircularQueue<Pair<Long, String>> recentRegisteredQueue;
                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
                //如果服务开始,则设置租约启动服务的时间
                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();
            }
        }
    }
4. PeerAwareInstanceRegistryImpl#replicateToPeers(...)

将节点信息复制到其他副本

     private void replicateToPeers(Action action, String appName, String id,
                                  InstanceInfo info /* optional */,
                                  InstanceStatus newStatus /* optional */, boolean isReplication) {
        //计时开始                               
        Stopwatch tracer = action.getTimer().start();
        try {
            if (isReplication) {
                numberOfReplicationsLastMin.increment();
            }
            // If it is a replication already, do not replicate again as this will create a poison replication
            if (peerEurekaNodes == Collections.EMPTY_LIST || isReplication) {
                return;
            }
            //查询是否有其他副本节点存在
            for (final PeerEurekaNode node : peerEurekaNodes.getPeerEurekaNodes()) {
                // If the url represents this host, do not replicate to yourself.
                //如果遍历到自己的节点,略过
                if (peerEurekaNodes.isThisMyUrl(node.getServiceUrl())) {
                    continue;
                }
                //如果去其他副本节点,则复制信息到其他节点
                replicateInstanceActionsToPeers(action, appName, id, info, newStatus, node);
            }
        } finally {
            tracer.stop();
        }
    }

获取所有副本的过程
(1). DefaultEurekaServerContext#initialize()

    @Singleton
    public class DefaultEurekaServerContext implements EurekaServerContext {
        @PostConstruct
        @Override
        public void initialize() {
            logger.info("Initializing ...");
            //获取nodes存储在DefaultEurekaServerContext中
            peerEurekaNodes.start(); 
            try {
                //在PeerAwareInstanceRegistryImpl中初始化Nodes和其他的
                registry.init(peerEurekaNodes);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            logger.info("Initialized");
        }
    }

(2). PeerEurekaNodes#start()

    public void start() {
        //。。。
        updatePeerEurekaNodes(resolvePeerUrls());
        //。。。
    }

(3). PeerEurekaNodes#resolvePeerUrls()
获取和解析配置里面的副本Node地址

    protected List<String> resolvePeerUrls() {
        //获取本地eureka配置文件
        InstanceInfo myInfo = applicationInfoManager.getInfo();
        //获取
        String zone = InstanceInfo.getZone(clientConfig.getAvailabilityZones(clientConfig.getRegion()), myInfo);
        List<String> replicaUrls = EndpointUtils
                .getDiscoveryServiceUrls(clientConfig, zone, new EndpointUtils.InstanceInfoBasedUrlRandomizer(myInfo));

        int idx = 0;
        while (idx < replicaUrls.size()) {
            if (isThisMyUrl(replicaUrls.get(idx))) {
                replicaUrls.remove(idx);
            } else {
                idx++;
            }
        }
        return replicaUrls;
    }

(4). EndpointUtils#getDiscoveryServiceUrls(...)
解析副本地址,判断是直接获取配置文件,还是根据nds来解析,参数eureka.client.use-dns-for-fetching-service-urls=false配置,默认false

    public static List<String> getDiscoveryServiceUrls(EurekaClientConfig clientConfig, String zone, ServiceUrlRandomizer randomizer) {
        boolean shouldUseDns = clientConfig.shouldUseDnsForFetchingServiceUrls();
        if (shouldUseDns) {
            return getServiceUrlsFromDNS(clientConfig, zone, clientConfig.shouldPreferSameZoneEureka(), randomizer);
        }
        return getServiceUrlsFromConfig(clientConfig, zone, clientConfig.shouldPreferSameZoneEureka());
    }
5. PeerAwareInstanceRegistryImpl.replicateInstanceActionsToPeers(...)
    private void replicateInstanceActionsToPeers(Action action, String appName,
                                                 String id, InstanceInfo info, InstanceStatus newStatus,
                                                 PeerEurekaNode node) {
        try {
            InstanceInfo infoFromRegistry;
            CurrentRequestVersion.set(Version.V2);
            switch (action) {
                //取消
                case Cancel:
                    node.cancel(appName, id);
                    break;
                //心跳检测
                case Heartbeat:
                    InstanceStatus overriddenStatus = overriddenInstanceStatusMap.get(id);
                    infoFromRegistry = getInstanceByAppAndId(appName, id, false);
                    node.heartbeat(appName, id, infoFromRegistry, overriddenStatus, false);
                    break;
                //心跳检测
                case Register:
                    node.register(info);
                    break;
                //状态更新
                case StatusUpdate:
                    infoFromRegistry = getInstanceByAppAndId(appName, id, false);
                    node.statusUpdate(appName, id, newStatus, infoFromRegistry);
                    break;
                //状态删除
                case DeleteStatusOverride:
                    infoFromRegistry = getInstanceByAppAndId(appName, id, false);
                    node.deleteStatusOverride(appName, id, infoFromRegistry);
                    break;
            }
        } catch (Throwable t) {
            logger.error("Cannot replicate information to {} for action {}", node.getServiceUrl(), action.name(), t);
        } finally {
            CurrentRequestVersion.remove();
        }
    }

服务下线(cancel)

服务租约(renew)

服务剔除(evict)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值