在微服务架构中,有着许许多多的微服务,微服务之间需要彼此进行远程调用,需要知道彼此的地址,通过人工的方式去管理这些地址是不现实的。于是就有了服务注册中心,每一个微服务都将自己的地址告诉注册中心,在需要进行远程调用的时候,也通过注册中心去找到需要调用的服务地址。
注册中心可以说是服务的通讯录,它记录了服务和服务地址的映射关系。
Eureka是一个基于REST的服务,用于定位服务,以实现云端中间层服务发现和故障转移。服务注册与发现对于微服务架构来说是非常重要的,有了服务发现与注册,只需要使用服务的标识符,就可以访问到服务,而不需要修改服务调用的配置文件了。
Eureka采用了C-S的设计架构,包含两个组件:Eureka Server 和 Eureka Client。
Eureka Server 作为服务注册功能的服务器,它是服务注册中心。
Eureka Client 是一个Java客户端,用于简化Eureka Server的交互。
各个节点启动后,会在Eureka Server中进行注册,在 Eureka Server中的服务注册表中将会存储所有可用服务节点的信息。服务节点的信息可以在界面中直观的看到。
在微服务的调用关系中,服务分为两个角色,服务的提供者和消费者。
服务提供者:一次业务中,被其它微服务调用的服务。(提供接口给其它微服务)
服务消费者:一次业务中,调用其它微服务的服务。(调用其它微服务提供的接口)
服务提供者和服务消费者的角色是相对的。一个服务可以同时为消费者和提供者。
服务的提供者需要在 Eureka Server 注册。使用 Eureka Client 与 Eureka Server 进行交互。并且定时的发送心跳以确保EurekaServer注册中心指导这个服务是正常的。如果Eureka Server 在多个心跳周期内没有接收到某个节点的心跳,EurekaServer将会从服务注册表中把这个服务节点移除(默认90秒)。
服务的消费者根据服务提供者的服务名去到注册中心去获取服务提供者的ip和端口号,然后进行远程调用。
创建项目,引入 spring-cloud-starter-netflix-eureka-server 依赖。
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-serverartifactId>
dependency>
在启动类上添加 @EnableEurekaServer 注解。
@EnableEurekaServer
@SpringBootApplication
public class EurekaApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaApplication.class, args);
}
}
在配置文件中进行如下配置
server:
port: 1000
spring:
application:
name: eurekaServer # eureka的服务名称
eureka:
client:
register-with-eureka: false #是否将自己注册到注册中心去 默认是为true
fetch-registry: false #是从注册中心获取自己的信息, 默认是true
service-url:
defaultZone: http://localhost:1000/eureka/ #定义服务中心的地址
Eureka 注册中心配置就完成了。启动项目,访问服务中心的地址。
服务提供者需要将自身的信息注入到注册中心。
在pom文件中引入依赖
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
dependency>
配置文件中进行配置
spring:
application:
name: provider
server:
port: 8888
#eureka 的服务注册中心服务的提供者
eureka:
instance:
prefer-ip-address: true # 注册服务的时候使用服务的ip地址
client:
service-url:
defaultZone: http://localhost:1000/eureka/ #将服务注册到服务中心去
启动项目,就会自动将服务提供者的信息注入到 Eureka 注册中心去。
服务的消费者需要从注册中心中定时的拉去注册中心的注册的服务信息。方便进行远程的服务调用。
服务的消费者同样需要配置Eureka的客户端依赖。
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
dependency>
在配置文件中进行配置。
server:
port: 8001
spring:
application:
name: consumer
eureka:
client:
#是否将自己注册到注册中心,默认为 true
register-with-eureka: false
#表示 Eureka Client 间隔多久去服务器拉取注册信息,默认为 30 秒
registry-fetch-interval-seconds: 10
#设置服务注册中心地址
service-url:
defaultZone: http://localhost:1000/eureka/
通过以上的配置,在消费者中,就可以根据服务提供者的服务名,去进行远程调用。
调用示例
@Autowired
private RestTemplate restTemplate;
public Order queryOrderById(Long orderId) {
// 1.查询订单
Order order = orderMapper.findById(orderId);
// 2.利用RestTemplate发起http请求,查询用户
// 2.1.url路径
String url = "http://provider/user/" + order.getUserId();
// 2.2.发送http请求,实现远程调用
User user = restTemplate.getForObject(url, User.class);
// 3.封装user到Order
order.setUser(user);
// 4.返回
return order;
}
所有的服务都要通过服务注册中心来进行信息交换,一旦服务注册中心掉线,会影响到整个系统的稳定性。所以在生产环境中,Eureka 一般都以集群的形式出现的。
Eureka集群,实际上就是启动多个Eureka实例, 多个Eureka实例之间互相注册,互相同步数据,共同组成一个Eureka集群。
在 Eureka Server 集群中,Eureka Server 之间进行数据同步,不同的 EurekaServer 之间不区分主从节点,所有节点都是平等的。
在项目中配置两个服务注册中心,两个注册中心互相注册。然后将服务提供者,注册到两个注册中心,再将服务消费者设置从两个注册中心拉去服务信息,完成集群的搭建。
搭建Eureka集群,如果 eureka.client.service-url.defaultZone = http://192.168.0.81:8761/eureka/ 属性中要使用别名而不是IP地址时,需要修改服务器的hosts文件(C:\Windows\System32\drivers\etc\hosts)
127.0.0.1 eureka-server1.com
127.0.0.1 eureka-server2.com
注册中心1 配置文件
需要向注册中心2中进行注册。
server:
port: 1001
spring:
application:
#该名称在集群模式下应该保持一致
name: eureka-server
eureka:
instance:
#服务注册中心实例的主机名
hostname: eureka-server1.com
#是否使用 ip 地址注册
prefer-ip-address: true
#该实例注册到服务中心的唯一ID
instance-id: ${spring.cloud.client.ip-address}:${server.port}
client:
#设置服务注册中心地址,指向另一个注册中心(除自己之外所有,多个使用逗号隔开)
service-url:
defaultZone: http://localhost:1002/eureka/
注册中心2 配置文件
需要向注册中心1中进行注册
server:
port: 1002
spring:
application:
#该名称在集群模式下应该保持一致
name: eureka-server
eureka:
instance:
#服务注册中心实例的主机名
hostname: eureka-server2.com
#是否使用 ip 地址注册
prefer-ip-address: true
#该实例注册到服务中心的唯一ID
instance-id: ${spring.cloud.client.ip-address}:${server.port}
client:
#设置服务注册中心地址,指向另一个注册中心(除自己之外所有,多个使用逗号隔开)
service-url:
defaultZone: http://localhost:1001/eureka/
修改服务的提供者和服务的消费者,配置多个注册中心。
服务提供者配置文件
spring:
application:
name: provider
server:
port: 8888
#eureka 的服务注册中心服务的提供者
eureka:
instance:
prefer-ip-address: true # 注册服务的时候使用服务的ip地址
client:
service-url:
#将服务注册到服务中心去
defaultZone: http://eureka-server1.com:1001/eureka/,http://eureka-server2.com:1002/eureka/
服务消费者配置文件
server:
port: 8001
spring:
application:
name: consumer
eureka:
client:
#是否将自己注册到注册中心,默认为 true
register-with-eureka: false
#表示 Eureka Client 间隔多久去服务器拉取注册信息,默认为 30 秒
registry-fetch-interval-seconds: 10
#设置服务注册中心地址
service-url:
defaultZone: http://eureka-server1.com:1001/eureka/,http://eureka-server2.com:1002/eureka/
默认情况下,如果 Eureka Server 在一定时间内没有接收到某个微服务实例的心跳,Eureka Server将 会注销该实例(默认90秒)。
但是当网络分区故障发生时,微服务与Eureka Server之间无法正常通信,就可能把健康状态的微服务错误注销。Eureka 的自我保护模式就是为了避免这种情况的。
Eureka Server 在运行期间会去统计心跳失败比例在 15 分钟之内是否低于 85%,如果低于 85%(短时间丢失过多的客户端,则可能出现网络故障,进入自我保护模式),Eureka Server 会将这些实例保护起来,让这些实例不会过期,同时提示一个警告,这种算法叫做 Eureka Server 的自我保护模式,这种自我保护模式默认开启。
自我保护模式关闭
eureka:
server:
#true:开启自我保护模式,false:关闭自我保护模式,默认开启
enable-self-preservation: false
当人为的关闭一个服务时,并且不想触发 Eureka 自我保护机制,想要注册中心剔除这个下线的服务。这种关闭方式叫做优雅停服。
优雅停服需要在想要关闭的服务提供中进行配置。
配置依赖
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
修改配置文件
#度量指标监控与健康检查
management:
endpoints:
web:
exposure:
#开启 shutdown 端点访问
include: shutdown
endpoint:
#开启 shutdown 实现优雅停服
shutdown:
enabled: true
访问 http://服务地址:服务端口/actuator/shutdown 即可实现优雅停服。