β

Spring-cloud & Netflix 源码解析:Eureka client 注册过程

idouba 402 阅读

记录下eureka client如何将本地服务的注册信息发送到远端的注册服务器eureka server上。不像 上文 中讲到的get操作,服务需要自己发起读取注册信息来进行自己后续的服务调用。服务注册可以认为是Eureka client自己完成,不需要服务来费心。

实现思路其实也挺简单,在com.netflix.discovery.DiscoveryClient启动的时候,会初始化一个定时任务,定时的把本地的服务配置信息,即需要注册到远端的服务信息自动刷新到注册服务器上。

客户端
1. 在DiscoveryClient中初始化一个InstanceInfoReplicator,其实里面封装了以定时任务。

com.netflix.discovery.DiscoveryClient.initScheduledTasks()
// InstanceInfo replicator
instanceInfoReplicator = new InstanceInfoReplicator(
this,
instanceInfo,
clientConfig.getInstanceInfoReplicationIntervalSeconds(),
); // burstSize
instanceInfoReplicator.start(clientConfig.getInitialInstanceInfoReplicationIntervalSeconds());

2. 以initialDelayMs为间隔调用

com.netflix.discovery.InstanceInfoReplicator.start(int initialDelayMs)
public void start(int initialDelayMs) {
if (started.compareAndSet(false, true)) {
instanceInfo.setIsDirty(); // for initial register
scheduler.schedule(this, initialDelayMs, TimeUnit.SECONDS);
}
}

3. ScheduledExecutorService的task的具体业务定义在com.netflix.discovery.InstanceInfoReplicator.run()中,可以看到调用了了client的register方法。

public void run() {
discoveryClient.refreshInstanceInfo();
Long dirtyTimestamp = instanceInfo.isDirtyWithTime();
if (dirtyTimestamp != null) {
discoveryClient.register();
instanceInfo.unsetIsDirty(dirtyTimestamp);

Future next = scheduler.schedule(this, replicationIntervalSeconds, TimeUnit.SECONDS);
scheduledPeriodicRef.set(next);

}

4. 执行注册的业务就是定义在DiscoveryClient的register方法,可以看到这个方法不是public的,也就是设计上也不是给外面调用的。这里的调用和 上文中 一般的调用没有差别,都是对eurekaserver进行了一个rest 调用。

boolean com.netflix.discovery.DiscoveryClient。register() throws Throwable {
logger.info(PREFIX + appPathIdentifier + “: registering service…”);
EurekaHttpResponse<Void> httpResponse;
httpResponse = eurekaTransport.registrationClient.register(instanceInfo);

return httpResponse.getStatusCode() == 204;
}

2 服务端
1. 看服务端怎样接受请求,来在服务端进行注册的。可以看到服务端的也是开放一个rest接口。

@POST
@Consumes({“application/json”, “application/xml”})
public Response addInstance(InstanceInfo info,
@HeaderParam(PeerEurekaNode.HEADER_REPLICATION) String isReplication) {
logger.debug(“Registering instance {} (replication={})”, info.getId(), isReplicat
registry.register(info, “true”.equals(isReplication));
}

2.  执行注册的动作在com.netflix.eureka.registry.PeerAwareInstanceRegistryImpl.register(InstanceInfo info, boolean isReplication)中

public void register(final InstanceInfo info, final boolean isReplication) {
super.register(info, leaseDuration, isReplication);
replicateToPeers(Action.Register, info.getAppName(), info.getId(), info, null, isReplication);
}

3. 在其父类中实现一般的注册信息存储的操作,其实就是存储在一个 ConcurrentHashMap<String, Map<String, Lease<InstanceInfo>>> registry的结构中。

com.netflix.eureka.registry.AbstractInstanceRegistry.register(InstanceInfo r, int leaseDuration, boolean isReplication) {
read.lock();
Map<String, Lease<InstanceInfo>> gMap = registry.get(r.getAppName());
REGISTER.increment(isReplication);
if (gMap == null) {
final ConcurrentHashMap<String, Lease<InstanceInfo>> gNewMap =
new ConcurrentHashMap<String, Lease<InstanceInfo>>();
gMap = registry.putIfAbsent(r.getAppName(), gNewMap);
…..
}

在服务端存储的数据结构设计上还是有挺多细节的,数据老化,不同peernode上的数据复制和同步等,这些都是后面有功夫关注的。

原创文章。为了维护文章的版本一致、最新、可追溯,转载请注明: 转载自 idouba

本文链接地址: Spring-cloud & Netflix 源码解析:Eureka client 注册过程


作者:idouba
@alph 爱豆吧!

发表评论