Eureka源码学习之eureka server集群机制

·  阅读 104

今天来看看eureka server集群相关的东西。
在eureka server初始化的过程中是否还记得PeerEurekaNodes这个类

//eureka-server集群初始化
        PeerEurekaNodes peerEurekaNodes = getPeerEurekaNodes(
                registry,
                eurekaServerConfig,
                eurekaClient.getEurekaClientConfig(),
                serverCodecs,
                applicationInfoManager
        );
复制代码

会执行PeerEurekaNodes.start()方法,启动一个后台的线程,默认是每隔10分钟,运行一个任务,基于配置文件中的url来刷新eureka server列表。

public void start() {
        taskExecutor = Executors.newSingleThreadScheduledExecutor(
                new ThreadFactory() {
                    @Override
                    public Thread newThread(Runnable r) {
                        Thread thread = new Thread(r, "Eureka-PeerNodesUpdater");
                        thread.setDaemon(true);
                        return thread;
                    }
                }
        );
        try {
            updatePeerEurekaNodes(resolvePeerUrls());
            Runnable peersUpdateTask = new Runnable() {
                @Override
                public void run() {
                    try {
                        updatePeerEurekaNodes(resolvePeerUrls());
                    } catch (Throwable e) {
                        logger.error("Cannot update the replica Nodes", e);
                    }

                }
            };
            taskExecutor.scheduleWithFixedDelay(
                    peersUpdateTask,
                    serverConfig.getPeerEurekaNodesUpdateIntervalMs(),
                    serverConfig.getPeerEurekaNodesUpdateIntervalMs(),
                    TimeUnit.MILLISECONDS
            );
        } catch (Exception e) {
            throw new IllegalStateException(e);
        }
        for (PeerEurekaNode node : peerEurekaNodes) {
            logger.info("Replica node URL:  {}", node.getServiceUrl());
        }
    }
    
@Override
    public int getPeerEurekaNodesUpdateIntervalMs() {
        return configInstance
                .getIntProperty(namespace + "peerEurekaNodesUpdateIntervalMs",
                        (10 * 60 * 1000)).get();
    }    
复制代码

下面来看看同步注册表,同样在EurekaBootStrap中 Applications apps = eurekaClient.getApplications();
eureka server其实自己也是个eureka client,client在初始化的时候,会从相邻的eureka server中拉取注册表到本地,也作为eureka server的本地注册表

// Copy registry from neighboring eureka node
        //从相邻eureka-server节点同步注册信息
        int registryCount = registry.syncUp();
复制代码
@Override
    public int syncUp() {
        // Copy entire entry from neighboring DS node
        int count = 0;

        for (int i = 0; ((i < serverConfig.getRegistrySyncRetries()) && (count == 0)); i++) {
            if (i > 0) {
                try {
                    Thread.sleep(serverConfig.getRegistrySyncRetryWaitMs());
                } catch (InterruptedException e) {
                    logger.warn("Interrupted during registry transfer..");
                    break;
                }
            }
            Applications apps = eurekaClient.getApplications();
            for (Application app : apps.getRegisteredApplications()) {
                for (InstanceInfo instance : app.getInstances()) {
                    try {
                        if (isRegisterable(instance)) {
                            register(instance, instance.getLeaseInfo().getDurationInSecs(), true);
                            count++;
                        }
                    } catch (Throwable t) {
                        logger.error("During DS init copy", t);
                    }
                }
            }
        }
        return count;
    }

//重试5次
@Override
    public int getRegistrySyncRetries() {
        return configInstance.getIntProperty(
                namespace + "numberRegistrySyncRetries", 5).get();
    }    
复制代码

下面再来看看 注册、下线、故障 这些集群是怎么同步的?
注册:
replicateToPeers(Action.Register, info.getAppName(), info.getId(), info, null, isReplication); 这方法就是将注册同步给其他eureka server

@Override
    public void register(final InstanceInfo info, final boolean isReplication) {
        int leaseDuration = Lease.DEFAULT_DURATION_IN_SECS;
        if (info.getLeaseInfo() != null && info.getLeaseInfo().getDurationInSecs() > 0) {
            leaseDuration = info.getLeaseInfo().getDurationInSecs();
        }
        super.register(info, leaseDuration, isReplication);
        replicateToPeers(Action.Register, info.getAppName(), info.getId(), info, null, isReplication);
    }
复制代码
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();
        }
    }
复制代码

就来看看注册这块吧
1.batchingDispatcher.process()
2.AcceptorExecutor.process()中acceptorQueue.add()
3.AcceptorExecutor中的AcceptorRunner会将中acceptorQueue中的元素放入processingOrder中,AcceptorExecutor会每隔500ms将processingOrder中元素(最多250个)打包到batchWorkQueue中
4.ReplicationTaskProcessor会调用replicationClient.submitBatchUpdates(list);通过一次网络请求将batch发送到其他eureka server

public void register(final InstanceInfo info) throws Exception {
        long expiryTime = System.currentTimeMillis() + getLeaseRenewalOf(info);
        batchingDispatcher.process(
                taskId("register", info),
                new InstanceReplicationTask(targetHost, Action.Register, info, null, true) {
                    public EurekaHttpResponse<Void> execute() {
                        return replicationClient.register(info);
                    }
                },
                expiryTime
        );
    }
复制代码

总结:
采用三个队列,异步批量同步

分类:
阅读
标签:
分类:
阅读
标签: