Eureka
分布式微服务架构中,服务注册中心用于存储服务提供者地址信息、服务发布相关的属性信息,消费者 通过主动查询和被动通知的方式获取服务提供者的地址信息,消费者只需要知道当前系统发布了那些服务,而不需要知道服务具体存在于什么位置。
服务端:eureka注册中心,需要创建工程,引入服务端jar
客户端:服务提供者和消费者对于,eureka来说都是客户端,提供者和消费者向eureka注册自己的信息,消费者调用提供者的时候会通过eureka获得服务提供者的信息。客户端需要引入eureka client相关的jar,然后进行相关配置,和eureka server建立联系
微服务启动后,会周期性地向Eureka Server发送心跳(默认周期为30秒)以续约自己的信息
Eureka Server在一定时间内没有接收到某个微服务节点的心跳,Eureka Server将会注销该微服务节点(默认90秒)
每个Eureka Server同时也是Eureka Client,多个Eureka Server之间通过复制的方式完成服务注册列表的同步
Eureka Client会缓存Eureka Server中的信息。即使所有的Eureka Server节点都宕掉,服务消 费者依然可以使用缓存中的信息找到服务提供者
搭建集群Eureka-Server
创建parent工程,引入依赖(父工程)
<dependencyManagement>
<dependencies>
<!--spring cloud依赖管理,引入了Spring Cloud的版本-->
<!--用dependencyManagement管理其他dependency的版本-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Greenwich.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
在父工程下创建子模块eureka-server
在子模块中引入Eureka server的依赖
<dependencies>
<!--Eureka server依赖-->
<dependency>
<!--版本号在父工程已经控制了-->
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
在父工程的pom文件中手动引入jaxb的jar,因为Jdk9之后默认没有加载该模块, EurekaServer使用到,所以需要手动导入,否则EurekaServer服务无法启动
在parent pom加入
<!--eureka server 需要引入Jaxb,开始-->
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-core</artifactId>
<version>2.2.11</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.2.11</version>
</dependency>
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.2.10-b140310.1920</version>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
<!--引入Jaxb,结束-->
在子工程eureka-server中创建src/main/resources/application.yml
#eureka server服务端口
server:
port: 8761
spring:
application:
name: cloud-eureka-server # 应用名称,应用名称会在Eureka中作为服务名称
# eureka 客户端配置(和Server交互),Eureka Server 其实也是一个Client
eureka:
instance:
hostname: CloudEurekaServerA # 当前eureka实例的主机名
client:
service-url:
# 配置客户端所交互的Eureka Server的地址(Eureka Server集群中每一个Server其实相对于其它Server来说都是Client)
# 集群模式下,defaultZone应该指向其它Eureka Server,如果有更多其它Server实例,逗号拼接即可
defaultZone: http://CloudEurekaServerB:8762/eureka
register-with-eureka: true # 集群模式下可以改成true
fetch-registry: true # 集群模式下可以改成true
dashboard:
enabled: true
创建启动类
@SpringBootApplication
// 声明当前项目为Eureka服务
@EnableEurekaServer
public class EurekaServerApplicationA {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplicationA.class,args);
}
}
创建在父工程下创建另外一个子模块EurekaServerApplicationB
修改application.yml配置
#eureka server服务端口
server:
port: 8762
spring:
application:
name: cloud-eureka-server # 应用名称,应用名称会在Eureka中作为服务名称
# eureka 客户端配置(和Server交互),Eureka Server 其实也是一个Client
eureka:
instance:
hostname: CloudEurekaServerB # 当前eureka实例的主机名
client:
service-url: # 配置客户端所交互的Eureka Server的地址
defaultZone: http://CloudEurekaServerA:8761/eureka
register-with-eureka: true
fetch-registry: true
本地环境搭建修改hosts文件加入
127.0.0.1 CloudEurekaServerA
127.0.0.1 CloudEurekaServerB
启动两个server,浏览器进入http://localhost:8761/
eureka服务端的作用
服务下线
当服务正常关闭操作时,会发送服务下线的REST请求给EurekaServer。
服务中心接受到请求后,将该服务置为下线状态
失效剔除
Eureka Server会定时(间隔值是eureka.server.eviction-interval-timer-in-ms,默认60s)进行检查, 如果发现实例在在一定时间(此值由客户端设置的eureka.instance.lease-expiration-duration-in- seconds定义,默认值为90s)内没有收到心跳,则会注销此实例。
自我保护
服务提供者 —> 注册中心
定期的续约(服务提供者和注册中心通信),假如服务提供者和注册中心之间的网络有点问题,不代表 服务提供者不可用,不代表服务消费者无法访问服务提供者
如果在15分钟内超过85%的客户端节点都没有正常的心跳,那么Eureka就认为客户端与注册中心出现了 网络故障,Eureka Server自动进入自我保护机制。
当处于自我保护模式时
1)不会剔除任何服务实例(可能是服务提供者和EurekaServer之间网络问题),保证了大多数服务依然可用
2)Eureka Server仍然能够接受新服务的注册和查询请求,但是不会被同步到其它节点上,保证当前节点依然可用,当网络稳定时,当前Eureka Server新的注册信息会被同步到其它节点中。
3)在Eureka Server工程中通过eureka.server.enable-self-preservation配置可用关停自我保护,默认值是打开
eureka:
server:
enable-self-preservation: false # 关闭自我保护模式(缺省为打开)
服务提供者Eureka-Client
父工程引入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-commons</artifactId>
</dependency>
在父工程下创建子模块service-resume并加入客户端依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
配置application.yml
spring:
application:
name: service-resume
eureka:
client:
service-url:
# 注册到集群,就把多个Eurekaserver地址使用逗号连接起来即可;注册到单实例(非集群模式),那就写一个就ok
defaultZone: http://CloudEurekaServerA:8761/eureka,http://CloudEurekaServerB:8762/eureka
instance:
prefer-ip-address: true #服务实例中显示ip,而不是显示主机名(兼容老的eureka版本)
#自定义实例显示格式,加上版本号,便于多版本管理,注意是ip-address,早期版本是ipAddress
instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}:@project.version@
创建启动类
@SpringBootApplication
//@EnableEurekaClient // 开启Eureka Client(Eureka独有)
@EnableDiscoveryClient // 开启注册中心客户端 (通用型注解,比如注册到Eureka、Nacos等)
// 说明:从SpringCloud的Edgware版本开始,不加注解也ok
public static void main(String[] args) {
SpringApplication.run(ServiceResumeApplication.class,args);
}
}
使用服务提供者
@Autowired
private DiscoveryClient discoveryClient;
@GetMapping("/checkState/{userId}")
public Integer findResumeOpenState(@PathVariable Long userId) {
// TODO 从Eureka Server中获取我们关注的那个服务的实例信息以及接口信息
// 1、从 Eureka Server中获取service-resume服务的实例信息(使用客户端对象做这件事)
List<ServiceInstance> instances = discoveryClient.getInstances("service-resume");
// 2、如果有多个实例,选择一个使用(负载均衡的过程)
ServiceInstance serviceInstance = instances.get(0);
// 3、从元数据信息获取host port
String host = serviceInstance.getHost();
int port = serviceInstance.getPort();
String url = "http://" + host + ":" + port + "/resume/openstate/" + userId;
System.out.println("===============>>>从EurekaServer集群获取服务实例拼接的url:" + url);
// 调用远程服务—> 简历微服务接口 RestTemplate -> JdbcTempate
// httpclient封装好多内容进行远程调用
Integer forObject = restTemplate.getForObject(url, Integer.class);
return forObject;
}
向服务加入自定义数据
eureka:
instance:
# 自定义Eureka元数据
metadata-map:
cluster: cl1
region: rn1
使用元数据
List<ServiceInstance> instances = discoveryClient.getInstances("service-resume");
ServiceInstance serviceInstance = instances.get(0);
//获得元数据
Map<String, String> metadata = serviceInstance.getMetadata();
eureka客户端的作用
服务提供者(也是Eureka客户端)要向EurekaServer注册服务,并完成服务续约等工作
服务注册(服务提供者):
1)当我们导入了eureka-client依赖坐标,配置Eureka服务注册中心地址
2)服务在启动时会向注册中心发起注册请求,携带服务元数据信息
3)Eureka注册中心会把服务的信息保存在Map中。
服务续约(提供者):
服务每隔30秒会向注册中心续约(心跳)一次(也称为报活),如果没有续约,租约在90秒后到期,然后 服务会被失效。每隔30秒的续约操作我们称之为心跳检测
#向Eureka服务中心集群注册服务
eureka:
instance:
# 租约续约间隔时间,默认30秒
lease-renewal-interval-in-seconds: 30
# 租约到期,服务时效时间,默认值90秒,服务超过90秒没有发生心跳,EurekaServer会将服务从列表移除
lease-expiration-duration-in-seconds: 90
获取服务列表(消费者):
每隔30秒服务会从注册中心中拉取一份服务列表,这个时间可以通过配置修改。
1)服务消费者启动时,从 EurekaServer服务列表获取只读备份,缓存到本地
2)每隔30秒,会重新获取并更新数据
3)每隔30秒的时间可以通过配置eureka.client.registry-fetch-interval-seconds修改
#向Eureka服务中心集群注册服务
eureka:
client:
# 每隔多久拉取一次服务列表
registry-fetch-interval-seconds: 30