上一篇说到Eureka客户端,这篇分析服务器端是如何与客户端交互及实现了哪些功能
这里解释一些Eureka的专有名词
instanceInfo: 服务实例信息, instanceId(唯一),app, appGroupName, ipAddr, port, leaseInfo等
Lease:租约,客户端向服务器端注册相当于签下了一纸租约,存在租期的概念,到期了要是没动静就默认不租了,把实例剔除。非常形象生动
LeaseInfo:使用了内联构造器的设计模式,来标识实例的租约信息,例如服务器端:注册时间、最后一次续约时间、被剔除时间、标记为UP的时间,客户端:续约间隔时间、租约的有效时长
LeaseManager:望文生义,这个接口负责管理实例,那么要知道如何管理服务注册、服务下线、服务续约和服务剔除,查看这个接口的实现类就能明白。
所以,查看LeaseManager的类图,看到类的继承关系,大致就明白,AbstractInstanceRegistry就是LeaseManager的基本实现类,它还同时实现了LookupService
LookupService接口的实现类还有DiscoveryClient, 主要的作用是发现活跃的服务实例,那么可否认为Eureka Server也是一个Eureka Client呢,因为和DiscoveryClient功能实现很像。事实上是可以的,Eureka Server同时也是一个Eureka Client, 这就是在配置时要注意的,如果不想注册Eureka Server为Client时,registerWithEureka属性设置为true的原因。
registerWithEureka: false #先不向Eureka Server注册自己的信息
那么基本框架大致讲到这里,接下来就详细讲解AbstractInstanceRegistry这个Eureka Server的核心类,其中registry就是注册表,结构如下
ConcurrentHashMap<String/*app name*/, Map<String/*InstanceId*/, Lease<InstanceInfo>>> registry = new ConcurrentHashMap<String, Map<String, Lease<InstanceInfo>>>();
服务注册 AbstractInstanceRegistry#register
public void register(InstanceInfo registrant, int leaseDuration, boolean isReplication) {
try {
// 获取读锁
read.lock();
// 根据appName对服务实例集群进行分类
Map<String, Lease<InstanceInfo>> gMap = registry.get(registrant.getAppName());
REGISTER.increment(isReplication);
if (gMap == null) {
final ConcurrentHashMap<String, Lease<InstanceInfo>> gNewMap = new ConcurrentHashMap<String, Lease<InstanceInfo>>();
// 如果存在键值,直接返回已存在的值,否则添加该键值对
gMap = registry.putIfAbsent(registrant.getAppName(), gNewMap);
if (gMap == null) {
gMap = gNewMap;
}
}
// 根据instanceId获取实例的租约
Lease<InstanceInfo> existingLease = gMap.get(registrant.getId());
// Retain the last dirty timestamp without overwriting it, if there is already a lease
if (existingLease != null && (existingLease.getHolder() != null)) {
Long existingLastDirtyTimestamp = existingLease.getHolder().getLastDirtyTimestamp();
Long registrationLastDirtyTimestamp = registrant.getLastDirtyTimestamp();
logger.debug("Existing lease found (existing={}, provided={}", existingLastDirtyTimestamp, registrationLastDirtyTimestamp);