博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
eureka分析
阅读量:4040 次
发布时间:2019-05-24

本文共 6877 字,大约阅读时间需要 22 分钟。

@EnableEurekaClient
@EnableDiscoveryClient -->EnableDiscoveryClientImportSelector
EnableDiscoveryClientImportSelector继承了SpringFactoryImportSelector

SpringFactoryImportSelector中selectImports中有下面一段话SpringFactoriesLoader进行META-INF/spring.factories中的configuration进行装载

// Find all possible auto configuration classes, filtering duplicates		List
factories = new ArrayList<>(new LinkedHashSet<>(SpringFactoriesLoader .loadFactoryNames(this.annotationClass, this.beanClassLoader)));

在autoConfiguration中的其中一个NoopDiscoveryClientAutoConfiguration

有@Bean  DiscoveryClient

@Bean	public DiscoveryClient discoveryClient() {		return new NoopDiscoveryClient(this.serviceInstance);	}

EurekaDiscoveryClient:Eureka 的 DiscoveryClient 实现类。

CompositeDiscoveryClient:用于排序可用客户端的发现客户端的顺序。

NoopDiscoveryClient:什么都不做的服务发现实现类,已经被废弃。

SimpleDiscoveryClient:简单的服务发现实现类 SimpleDiscoveryClient,具体的服务实例从 SimpleDiscoveryProperties 配置中获取。

EurekaDiscoveryClient中发现服务主要是this.eurekaClient,private final EurekaClient eurekaClient;

public List
getInstances(String serviceId) { List
infos = this.eurekaClient.getInstancesByVipAddress(serviceId, false); List
instances = new ArrayList(); Iterator var4 = infos.iterator(); while(var4.hasNext()) { InstanceInfo info = (InstanceInfo)var4.next(); instances.add(new EurekaDiscoveryClient.EurekaServiceInstance(info)); } return instances; }
eurekaClient的实现类为DiscoveryClient

DiscoveryClient的构造方法中,进行几个线程池的初始化以及加入到scheduler中

@Inject    DiscoveryClient(ApplicationInfoManager applicationInfoManager, EurekaClientConfig config, AbstractDiscoveryClientOptionalArgs args, Provider
backupRegistryProvider) { 。。。 try { this.scheduler = Executors.newScheduledThreadPool(3, (new ThreadFactoryBuilder()).setNameFormat("DiscoveryClient-%d").setDaemon(true).build()); this.heartbeatExecutor = new ThreadPoolExecutor(1, this.clientConfig.getHeartbeatExecutorThreadPoolSize(), 0L, TimeUnit.SECONDS, new SynchronousQueue(), (new ThreadFactoryBuilder()).setNameFormat("DiscoveryClient-HeartbeatExecutor-%d").setDaemon(true).build()); this.cacheRefreshExecutor = new ThreadPoolExecutor(1, this.clientConfig.getCacheRefreshExecutorThreadPoolSize(), 0L, TimeUnit.SECONDS, new SynchronousQueue(), (new ThreadFactoryBuilder()).setNameFormat("DiscoveryClient-CacheRefreshExecutor-%d").setDaemon(true).build()); this.eurekaTransport = new DiscoveryClient.EurekaTransport(null); this.scheduleServerEndpointTask(this.eurekaTransport, args); Object azToRegionMapper; if (this.clientConfig.shouldUseDnsForFetchingServiceUrls()) { azToRegionMapper = new DNSBasedAzToRegionMapper(this.clientConfig); } else { azToRegionMapper = new PropertyBasedAzToRegionMapper(this.clientConfig); } if (null != this.remoteRegionsToFetch.get()) { ((AzToRegionMapper)azToRegionMapper).setRegionsToFetch(((String)this.remoteRegionsToFetch.get()).split(",")); } this.instanceRegionChecker = new InstanceRegionChecker((AzToRegionMapper)azToRegionMapper, this.clientConfig.getRegion()); } catch (Throwable var8) { throw new RuntimeException("Failed to initialize DiscoveryClient!", var8); } if (this.clientConfig.shouldFetchRegistry() && !this.fetchRegistry(false)) { this.fetchRegistryFromBackup(); } this.initScheduledTasks(); try { Monitors.registerObject(this); } catch (Throwable var7) { logger.warn("Cannot register timers", var7); } DiscoveryManager.getInstance().setDiscoveryClient(this); DiscoveryManager.getInstance().setEurekaClientConfig(config); this.initTimestampMs = System.currentTimeMillis(); logger.info("Discovery Client initialized at timestamp {} with initial instances count: {}", this.initTimestampMs, this.getApplications().size()); } }

在initScheduledTasks方法中this.instanceInfoReplicator.start(this.clientConfig.getInitialInstanceInfoReplicationIntervalSeconds());

查看InstanceInfoReplicator中的run方法,可以看到注册方法this.discoveryClient.register();

public void run() {        boolean var6 = false;        ScheduledFuture next;        label53: {            try {                var6 = true;                this.discoveryClient.refreshInstanceInfo();                Long dirtyTimestamp = this.instanceInfo.isDirtyWithTime();                if (dirtyTimestamp != null) {                    this.discoveryClient.register();                    this.instanceInfo.unsetIsDirty(dirtyTimestamp);                    var6 = false;                } else {                    var6 = false;                }                break label53;            } catch (Throwable var7) {                logger.warn("There was a problem with the instance info replicator", var7);                var6 = false;            } finally {                if (var6) {                    ScheduledFuture next = this.scheduler.schedule(this, (long)this.replicationIntervalSeconds, TimeUnit.SECONDS);                    this.scheduledPeriodicRef.set(next);                }            }            next = this.scheduler.schedule(this, (long)this.replicationIntervalSeconds, TimeUnit.SECONDS);            this.scheduledPeriodicRef.set(next);            return;        }        next = this.scheduler.schedule(this, (long)this.replicationIntervalSeconds, TimeUnit.SECONDS);        this.scheduledPeriodicRef.set(next);    }

再看注册方法,使用 http rest请求进行注册

 

client的心跳,续约

this.heartbeatExecutor = new ThreadPoolExecutor(1, this.clientConfig.getHeartbeatExecutorThreadPoolSize(), 0L, TimeUnit.SECONDS, new SynchronousQueue(), (new ThreadFactoryBuilder()).setNameFormat("DiscoveryClient-HeartbeatExecutor-%d").setDaemon(true).build());

在initScheduledTasks()方法中有启动定时任务

this.scheduler.schedule(new TimedSupervisorTask("heartbeat", this.scheduler, this.heartbeatExecutor, renewalIntervalInSecs, TimeUnit.SECONDS, expBackOffBound, new DiscoveryClient.HeartbeatThread(null)), (long)renewalIntervalInSecs, TimeUnit.SECONDS);

查看线程DiscoveryClient.HeartbeatThread中的run方法,可以看到renew()方法,进行续约

参考:

 

下面是eureka的server端:

server有服务剔除(client没有心跳交互后,会尝试3次,90秒),下线服务

client会定时30秒从server端拉取注册信息,并缓存到本地,30秒重新拉取后会覆盖

server端的自我保护机制,server统计心跳15分钟内,失败是否大于85%,如果大于则进入自我保护机制,不再剔除client,同时接收注册跟查询,但是不再跟其他的节点同步注册信息,等待网路稳定后再同步。

server集群,不分主次,相互之间通过 Replicate 来同步数据,只需要配置一下同步节点的URL

application-eureka-server1.properties、application-eureka-server2.properties配置文件设置了不同的端口(server.port),重点是参数eureka.client.serviceUrl.defaultZone,分别配置对方的地址作为Eureka Client进行相互注册。

Eureka 提供了 Region 和 Zone 两个概念来进行分区,同一分区内进行优先调用。

参考地址:

转载地址:http://lxadi.baihongyu.com/

你可能感兴趣的文章
arm linux 生成火焰图
查看>>
linux和windows内存布局验证
查看>>
linux insmod error -1 required key invalid
查看>>
linux kconfig配置
查看>>
linux不同模块completion通信
查看>>
linux printf获得时间戳
查看>>
C语言位扩展
查看>>
linux dump_backtrace
查看>>
linux irqdebug
查看>>
git 常用命令
查看>>
linux位操作API
查看>>
uboot.lds文件分析
查看>>
uboot start.s文件分析
查看>>
没有路由器的情况下,开发板,虚拟机Ubuntu,win10主机,三者也可以ping通
查看>>
本地服务方式搭建etcd集群
查看>>
安装k8s Master高可用集群
查看>>
忽略图片透明区域的事件(Flex)
查看>>
忽略图片透明区域的事件(Flex)
查看>>
AS3 Flex基础知识100条
查看>>
Flex动态获取flash资源库文件
查看>>