SpringCloud系列:
虽然说官方已经发布Eureka不在维护的通知,但是还是需要对我们用过的Eureka进行深入了解的,因为这些玩意都是大同小异的。
下面先利用白话文分析Eureka服务端的实现原理:
eureka服务端:
EurekaServerAutoConfiguration自动配置类,注册各种bean,包括PeerAwareInstanceRegistry用于服务注册(实际就是父类AbstractInstanceRegistry提供的ConcurrentHashMap存放服务注册列表:registry)、以及jersey。eureka是利用jersey提供接口给客户端访问注册服务和获取服务列表的,jerseyApplication将注册DefaultResourceConfig的bean交由spring容器,这里扫描获取所有@Path注解的类(这是jersey的注解相当springmvc的@RequestMapping)放入DefaultResourceConfig交由spring容器即可。这样就启动了jersey的访问。这里我们直接从服务注册接口和服务查询接口开始对eureka的剖析。ApplicationResource提供注册接口addInstance,ApplicationsResource提供服务列表获取getContainers;
ApplicationResource.addInstance:接收服务注册请求,将InstanceInfo服务信息调用PeerAwareInstanceRegistry.register将其信息组装后放入名叫registry(实际就是父类AbstractInstanceRegistry提供的ConcurrentHashMap存放服务注册列表:registry))的一个ConcurrentHashMap中,这样就完成了服务注册操作。
ApplicationsResource.getContainers:接收服务列表获取访问,调用ResponseCacheImpl.getGZIP其实际就是通过readWriteCacheMap(LoadingCache)中获取到信息,而这这个readWriteCacheMap信息是在实例化ResponseCacheImpl时进行初始化数据的,初始化是真正调用到的是ResponseCacheImpl.generatePayload进行readWriteCacheMap赋值,而这里就是从AbstractInstanceRegistry的registry.entrySet()获取所有服务信息将其进行处理返回。
服务端通过客户端发送的心跳进行服务的续约(续约时间固定),当超过续约时间未收到客户端心跳则会进行剔除操作,当然服务端下线时也会主动触发请求服务端进行服务剔除,服务续约请求:InstanceResource.renewLease()进行服务时间的刷新;
主动触发剔除请求:InstanceResource.cancelLease()调用的是AbstractInstanceRegistry.internalCancel()进行服务删除;
定时查看对比各服务的续约时间是否超期,是则发起剔除操作:AbstractInstanceRegistry.evict()查询服务是否过期,过期的调用AbstractInstanceRegistry.internalCancel()进行服务删除
eureka服务端核心大致的实现如上面所说, 下面进行源码的探究:
EurekaServerAutoConfiguration自动配置类
我们在demo中使用启动eureka服务端是启动类会加上@EnableEurekaServer:
该注解import一个类EurekaServerMarkerConfiguration:
该类实际上什么都没有,就是注册了个空的Marker。
我们回到EurekaServerAutoConfiguration自动配置类中你会发现,这个Marker是启动自动配置类的条件标识:
接着我们来看看这个自动配置类做了些什么操作,其他多余的我就不列了,就绕着前面的白话文里提到的PeerAwareInstanceRegistry和jersey;
服务注册核心PeerAwareInstanceRegistry类:
JerseyApplication:
这里正如前面所说的扫描出所有@Path和@Provider的类放入DefaultResourceConfig,这里关于jersey知识我就不这里描述了,不懂的可以自行百度。
这里我们注册的比较重要的几个jersey接口,其中有ApplicationResource,ApplicationsResource,InstanceResource。
ApplicationResource该类提供了服务注册接口:
我们先来分析这个服务注册的过程
首先从接口中我们拿到客户端提交过来的信息InstanceInfo,该接口其他的各种细节操作我们不需要关注他,拿到info后调用
registry.register(info, "true".equals(isReplication));
也就是调用AbstractInstanceRegistry.register:
到这里我们可以看到其实际上就是操作一个叫做registry的ConcurrentHashMap【ConcurrentHashMap
{
"客户端服务": { // 服务名
"实例的唯一ID": { // 实例标识符
"lease": { // 持有实例信息
"instanceInfo": { // 实例信息
"appName": "客户端服务",
"instanceId": "实例的唯一ID",
"ipAddr": "IP地址",
"port": "调用端口"
}
}
}
}
}
服务的注册大概就是这样子,接着就是服务列表的获取接口
ApplicationsResource,提供了所有注册过的服务列表获取:
其中重点我们可以看下
通过调用ResponseCacheImpl.getGZIP来获取
而这个又接着getValue:
实际上这个值得获取来自于readWriteCacheMap,然而这个readWriteCacheMap的数据又是从哪而来的呢?
ResponseCacheImpl在被构造时会进行readWriteCacheMap的数据初始化操作:
这里调用generatePayload:
前面我们传入的得是ALL_APPS,我们来看看这块数据的获取,调用的是AbstractInstanceRegistry.getApplicationsFromMultipleRegions最终获取的部分核心内容如下:
这里的registry不正是我们前面注册时存放进去的服务信息嘛,然后接着获取所有进行遍历构造出Applications对象然后进行返回。也就是说前面readWriteCacheMap获取到的就是Applications信息。到这里服务的获取我们也就明白了。
接着就是InstanceResource,该接口提供的是服务的续约请求已经服务的剔除请求:
服务续约请求接口:renewLease
这里通过服务名和id最终调用的是AbstractInstanceRegistry.renew:
从服务列表registry里面获取对应lease,然后调用对应的renew()方法进行时间的更新:
这样就完成了服务的续约操作,也就是将服务的更新时间延长一定时间。
接着就是进行服务的剔除接口操作
通过服务名及i最终调用的是AbstractInstanceRegistry.cancal :
接着调用internalCancel:
获取到对应的instanceInfo然后将其从registry进行remove掉,然后获取的lease调用cancel()给了个过期时间:
以上是客户端主动请求剔除操作,还有一个专门的定时任务进行服务的轮询对比过期时间的剔除操作,同样的逻辑,这里就不在赘述了
总结
eureka服务服务端通过jersey对外提供服务注册和服务获取以及服务续约和剔除等接口,服务信息被注册放入到一个名为registry的ConcurrentHashMap里。
以上就是本章eureka服务端源码分析的所有内容,如有什么不对的地方望指出。感谢你的收看,下章将进行eureka客户端源码的探究,如有兴趣记得关注哦。