Professional Documents
Culture Documents
05-v1-服务注册:如何构建 Eureka 服务器并理解其实现原理?【 微信号:itcodeba 】【海量资源:www.yuerxuetang.com】
05-v1-服务注册:如何构建 Eureka 服务器并理解其实现原理?【 微信号:itcodeba 】【海量资源:www.yuerxuetang.com】
基于 Eureka 构建注册中心
基于 Eureka 构建服务注册中心涉及两大部分内容,首先我们将给出构建单个 Eureka 服务器的方法。
但是,Eureka 服务器不能保证高可用,因此在生产环境中,我们一般都还需要构建 Eureka 服务器集
群。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
@SpringBootApplication
@EnableEurekaServer
SpringApplication.run(EurekaServerApplication.class, args);
}
一手资源尽在:666java.com
请注意,在上面的代码中,我们在启动类上加了一个 @EnableEurekaServer 注解。在 Spring Cloud
中,包含 @EnableEurekaServer 注解的服务意味着就是一个 Eureka 服务器组件。
Eureka 服务监控页面
同时,Eureka 也为开发人员提供了一系列的配置项。这些配置项可以分成三大类,一类用于控制
Eureka 服务器端行为,以 eureka.server 开头;一类则是从客户端角度出发考虑配置需求,以
eureka.client 开头;而最后一类则关注于注册到 Eureka 的服务实例本身,以 eureka.instance 开
头。请注意,Eureka 除了充当服务器端组件之外,实际上也可以作为客户端注册到 Eureka 本身,这时
候它使用的就是客户端配置项。
Eureka 的配置项很多,我们无意一一进行展开。在日常开发过程中,使用的最多的还是客户端相关的
配置,所以这里以客户端配置为例。现在,我们尝试在 eureka-server 工程的 application.yml 文件中
添加了如下配置信息。
server:
port: 8761
eureka:
client:
registerWithEureka: false
fetchRegistry: false
一手资源尽在:666java.com
serviceUrl:
defaultZone: http:
2. 构建 Eureka 服务器集群
server:
port: 8761
eureka:
instance:
hostname: eureka1
client
serviceUrl
defaultZone: http:
对应的,application-eureka2.yml 配置文件的内容如下:
server:
一手资源尽在:666java.com
port: 8762
eureka:
instance:
hostname: eureka2
client
serviceUrl
defaultZone: http:
127.0.0.1 eureka1
127.0.0.1 eureka2
理解 Eureka 服务器实现原理
在介绍完 Eureka 服务器的构建方式之后,我们重点来讲解 Eureka 服务器的实现原理。
Eureka 核心概念
Eureka 细化架构图
在上图中,Eureka 有以下几个概念与服务治理直接相关,首当其冲的是服务注册。服务注册
(Register)是服务治理的最基本概念,内嵌了 Eureka 客户端的各个微服务通过向 Eureka 服务器提供
IP 地址、端点等各项与服务发现相关的基本信息完成服务注册操作。
Eureka 服务存储源码解析
InstanceRegistry 类层结构图
服务注册信息的存储结构示意图
void evict();
Applications getApplications();
在内部实现上,实际上对于注册中心服务器而言,服务注册、续约、取消和剔除等不同操作所执行的工
作流程基本一致,即都是对服务存储的操作,并把这一操作同步到其他 Eureka 节点。我们这里选择用
于服务注册操作的 register 方法进行展开,register 方法非常长,我们对源码进行裁剪,得出如下所示
的核销处理流程:
try {
REGISTER.increment(isReplication);
if (gMap == null) {
} else {
registrant.setActionType(ActionType.ADDED);
registrant.setLastUpdatedTimestamp();
invalidateCache(registrant.getAppName(), registrant.getVIPAddress(),
registrant.getSecureVipAddress());
Eureka 服务缓存源码解析
http://<eureka-server-ip>:8761/eureka/apps/<APPID>
Key.EntityType.Application,
appName,
keyType,
CurrentRequestVersion.get(),
EurekaAccept.fromString(eurekaAccept)
);
一手资源尽在:666java.com
String payLoad = responseCache.get(cacheKey);
if (payLoad != null) {
return Response.ok(payLoad).build();
} else {
return Response.status(Status.NOT_FOUND).build();
AtomicLong getVersionDelta();
AtomicLong getVersionDeltaWithRegions();
try {
if (useReadOnlyCache) {
if (currentPayload != null) {
payload = currentPayload;
} else {
payload = readWriteCacheMap.get(key);
readOnlyCacheMap.put(key, payload);
} else {
payload = readWriteCacheMap.get(key);
} catch (Throwable t) {
return payload;
}
一手资源尽在:666java.com
可以看到上述代码中有两个缓存,一个是 readOnlyCacheMap,一个是 readWriteCacheMap。其
中 readOnlyCacheMap 就是一个 JDK 中的 ConcurrentMap,而 readWriteCacheMap 使用的则是
Google Guava Cache 库中的 LoadingCache 类型。在创建 LoadingCache 过程中,缓存数据的来源是
调用 generatePayload 方法来生成。而在这个 generatePayload 方法中,就会调用前面介绍的
AbstractInstanceRegistry 中的 getApplications 方法获取应用信息并放到缓存中。这样我们就实现了
把注册信息与缓存信息进行关联。
@Override
try {
CurrentRequestVersion.set(key.getVersion());
if (cacheValue != currentCacheValue) {
readOnlyCacheMap.put(key, cacheValue);
}
一手资源尽在:666java.com
}
};
Eureka 高可用源码解析
@Override
leaseDuration = info.getLeaseInfo().getDurationInSecs();
if (peerEurekaNodes.isThisMyUrl(node.getServiceUrl())) {
一手资源尽在:666java.com
continue;
EurekaHttpResponse<ReplicationListResponse> submitBatchUpdates(ReplicationList
replicationList);
@Override
try {
一手资源尽在:666java.com
String urlPath = "asg/" + asgName + "/status";
response = jerseyApacheClient.resource(serviceUrl)
.path(urlPath)
.queryParam("value", newStatus.name())
.header(PeerEurekaNode.HEADER_REPLICATION, "true")
.put(ClientResponse.class);
return EurekaHttpResponse.status(response.getStatus());
} finally {
if (response != null) {
response.close();
小结与预告
今天我们讨论的是 Eureka 服务器端组件的相关内容,可以看到基于 Spring Cloud 框架,构建一个
Eureka 注册中心所需要做的事情仅仅只是添加一个注解。但在内部实现上,Eureka 服务器端需要考虑
各个微服务实例的存储和获取等核心流程,也需要考虑如何确保注册中心本身的高可用问题。我们基于
源码,对这些流程和问题底层的原理进行了详细的分析。
这里给你留一道思考题:Eureka 是如何实现自身的高可用架构的?