Spring Cloud 微服务注册中心(Eureka)
Eureka,服务注册和发现,它提供了一个服务注册中心、服务发现的客户端,还有一个方便的查看所有注册服务的界面。
所有的服务使用Eureka的服务发现客户端来将自己注册到Eureka的服务器上。
一 基础架构
图1:角色解释:
- Eureka Server:提供服务注册和发现
- Service Provider:服务提供方,将自身服务注册到Eureka。服务注册、服务续约、服务下线。
- Service Consumer:服务消费方,从Eureka获取注册服务列表,从而能够消费服务。
Eureka支持Region
和Zone
的概念,其中一个Region可以包含多个Zone。Eureka在启动时需要指定一个Zone名,即当前Eureka属于哪个zone, 如果不指定则属于defaultZone
。Eureka Client也需要指定Zone, Client(当与Ribbon配置使用时)在向Server获取注册列表时会优先向自己Zone的Eureka发请求,如果自己Zone中的Eureka全挂了才会尝试向其它Zone。当获取到远程服务列表后,Client也会优先向同一个Zone的服务发起远程调用。Region和Zone可以对应于现实中的大区和机房。
二 实战
2.1 Eureka单机示例
2.1.1 服务端
pom.xml
: maven 依赖
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Camden.SR2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
EurekaApplication.java
: 启动函数
@SpringBootApplication
@EnableEurekaServer
public class EurekaApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaApplication.class,args);
}
}
application.properties
: 配置文件
server.port=9001
eureka.instance.hostname=localhost
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
eureka.instance.preferIpAddress=true
eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka/
eureka.server.enableSelfPreservation=false
2.1.2 客户端
pom.properites
: maven依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
UserApplication.java
: 启动函数
@SpringBootApplication
@EnableDiscoveryClient
public class UserApplication {
public static void main(String[] args) {
SpringApplication.run(UserApplication.class,args);
}
}
application.properties
: 配置文件
spring.application.name=user-service
spring.cloud.config.profile=dev
spring.profiles.active=dev
eureka.client.serviceUrl.defaultZone=http://localhost:9001/eureka/
先后启动服务端和客户端,访问 http://localhost:9001/,可以在eureka界面看到,服务user-service注册成功如图。
2.2 高可用集群
注册中心单机,如果挂了,将导致整个服务不可用。生产环境不可能只有一个实例。 下图为官网给出的高可用集群架构图。
集群配置很简单,比如上图有3个节点us-east-1c,us-east-1d,us-east-1e。配置集群只需要把分别把自己作为客户端,其他两个节点当作服务端即可。 在2.1.1 的基础上,添加application-peer1.properties
和application-peer2.properties
:
server.port=9011
eureka.instance.hostname=peer1
eureka.client.serviceUrl.defaultZone=http://peer2:9111/eureka/
server.port=9111
eureka.instance.hostname=peer2
eureka.client.serviceUrl.defaultZone=http://peer1:9011/eureka/
修改hosts
:
127.0.0.1 peer1
127.0.0.1 peer2
分别通过spring.profiles.active=peer1
和spring.profiles.active=peer2
启动。
注意:如果使用localhost
,将出现unavailable-replicas
的情况。
三 原理分析
两个重要类:客户端:DiscoveryClient
,服务端:ApplicationResourcs
。 DiscoveryClient在Eureka-client(jar包)里。 提共一下功能:
- Registering:注册
- Renewal:续约
- Cancellation:取消
- Querying:查询已注册的服务列表
3.1 注册续约
客户端 DiscoveryClient通过initScheduledTasks()初始化定时任务。
-
shouldRegisterWithEureka:注册判断
-
renewalIntervalInSecs : 续约间隔(即心跳间隔,默认30s)等其他客户端和实例配置信息
-
心跳定时任务;注册
instanceInfoReplicator.run()
-
register()方法中发起http请求注册,传入
instanceInfo
实体。httpResponse = eurekaTransport.registrationClient.register(instanceInfo);
涉及配置:
# 续租间隔 eureka.instance.lease-renewal-interval-in-seconds=30 # 服务失效时间。默认是90秒 eureka.instance.lease-expiration-duration-in-seconds=90
其实注册和续约是一个逻辑。
服务端
-
ApplicationResource类接收Http服务请求,调用PeerAwareInstanceRegistryImpl的register方法
-
PeerAwareInstanceRegistryImpl完成服务注册后,调用replicateToPeers向其它Eureka Server节点(Peer)做状态同步(异步操作) 注册的服务列表保存在一个嵌套的hash map中:
-
第一层hash map的key是app name,也就是应用名字
-
第二层hash map的key是instance name,也就是实例名字 USER-SERVICE就是app name,192.168.1.106:user-service:9002就是instance name。
下图为renew服务端实现:
3.2 获取服务列表
客户端 和注册在DiscoveryClient
的方法initScheduledTasks()中定义。
- shouldFetchRegistry:
- 设置配置。
- 定时任务CacheRefreshThread()
涉及配置:
# 是否获取服务列表
eureka.client.fetch-registry=true
# 更新间隔
eureka.client.registry-fetch-interval-seconds=30
3.3 peer 节点通讯
Eureka Server在启动后会调用EurekaClientConfig.getEurekaServerServiceUrls
来获取所有的Peer节点,并且会定期更新。定期更新频率可以通过eureka.server.peerEurekaNodesUpdateIntervalMs
配置。 这个方法的默认实现是从配置文件读取,所以如果Eureka Server节点相对固定的话,可以通过在配置文件中配置来实现。 如果希望能更灵活的控制Eureka Server节点,比如动态扩容/缩容,那么可以override getEurekaServerServiceUrls
方法,比如从数据库读取Eureka Server列表。下图为一个服务节点的初始化过程。
参考文档: [1].http://nobodyiam.com/2016/06/25/dive-into-eureka/
源码部分参考此文档