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