zoukankan      html  css  js  c++  java
  • 四、eureka服务端同步注册操作

    所有文章

    https://www.cnblogs.com/lay2017/p/11908715.html

    正文

    eureka服务端注册服务一文中,我们提到register方法做了两件事

    1)注册服务实例信息到当前节点

    2)复制服务实例信息到其它节点

    本文关注第二点,复制服务实例信息到其它节点。为此,我们先简单看一下register方法的代码

    打开PeerAwareInstanceRegistryImpl类的register方法

    public void register(final InstanceInfo info, final boolean isReplication) {
        // ...
        super.register(info, leaseDuration, isReplication);
        // 复制到其它节点
        replicateToPeers(Action.Register, info.getAppName(), info.getId(), info, null, isReplication);
    }

    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();
            }
            // 如果本次register操作本身就是复制,就不再复制到其它节点了
            if (peerEurekaNodes == Collections.EMPTY_LIST || isReplication) {
                return;
            }
    
            // 遍历左右节点
            for (final PeerEurekaNode node : peerEurekaNodes.getPeerEurekaNodes()) {
                // 如果是当前节点,直接跳过
                if (peerEurekaNodes.isThisMyUrl(node.getServiceUrl())) {
                    continue;
                }
                // 复制操作触发
                replicateInstanceActionsToPeers(action, appName, id, info, newStatus, node);
            }
        } finally {
            tracer.stop();
        }
    }

    这里其实就是向所有其它节点发送注册请求

    跟进replicateInstanceActionsToPeers,可以看到除了register还有一些其它操作一样是需要同步到其它节点的。这里我们只关注register操作

    private void replicateInstanceActionsToPeers(Action action, String appName,
                                                 String id, InstanceInfo info, InstanceStatus newStatus,
                                                 PeerEurekaNode node) {
        try {
            InstanceInfo infoFromRegistry = null;
            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) {
            // ... 
        }
    }

    跟进register方法,复制实例信息被构造成了一个任务丢给了batchingDispatcher去异步执行,如果失败将会重试。

    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
        );
    }

    InstanceReplicationTask的主要逻辑就是调用了replicationClient的register方法,跟进它

    这里以Jersey的实现为例

    public EurekaHttpResponse<Void> register(InstanceInfo info) {
        String urlPath = "apps/" + info.getAppName();
        ClientResponse response = null;
        try {
            Builder resourceBuilder = jerseyClient.resource(serviceUrl).path(urlPath).getRequestBuilder();
            addExtraHeaders(resourceBuilder);
            response = resourceBuilder
                    .header("Accept-Encoding", "gzip")
                    .type(MediaType.APPLICATION_JSON_TYPE)
                    .accept(MediaType.APPLICATION_JSON)
                    .post(ClientResponse.class, info);
            return anEurekaHttpResponse(response.getStatus()).headers(headersOf(response)).build();
        } finally {
            // ...
        }
    }

    可以看到,其实就是发送了http请求到其它eureka Server端

    总结

    eureka Server会将register、cancel、heartbeat等操作从一个节点同步发送到其它节点,从而实现了复制的功能。eureka和zookeeper不一样,它是遵循ap的,所以采用了最终一致性,并没有像zookeeper一样选择强一致。eureka Server之间的维持最终一致性的细节点还是很多的,比如失败重试、超时、心跳、实例的版本号、同一个节点的锁控制等等。有兴趣的话可以详细了解它。

  • 相关阅读:
    oracle内存粒度
    知乎--软件架构设计 性能系列
    VAMEI 图解的博客
    泰晓科技
    高性能高并发系统的稳定性保障
    如何提高Linux下块设备IO的整体性能?
    Unix操作系统LD_PRELOAD简介
    浅析keepalived vip漂移原理与VRRP协议
    SQL:将查询结果插入到另一个表的三种情况
    C# Graphics中有关绘图质量的几个Mode
  • 原文地址:https://www.cnblogs.com/lay2017/p/11919370.html
Copyright © 2011-2022 走看看