3.Eureka注册中心
3.1 Eureka的结构和作用
上面使用RestTemplate
调用http请求时使用的是硬编码,将url写死在了模块里,这样做会带来环境变更麻烦等问题,所以引入注册中心:

上图中共涉及到以下 3 个角色:
- 服务注册中心(Register Service):它是一个 Eureka Server,用于提供服务注册和发现功能。
- 服务提供者(Provider Service):它是一个 Eureka Client,用于提供服务。它将自己提供的服务注册到服务注册中心,以供服务消费者发现。
- 服务消费者(Consumer Service):它是一个 Eureka Client,用于消费服务。它可以从服务注册中心获取服务列表,调用所需的服务。
Eureka 实现服务注册与发现的流程如下:
- 搭建一个 Eureka Server 作为服务注册中心;
- 服务提供者 Eureka Client 启动时,会把当前服务器的信息以服务名(spring.application.name)的方式注册到服务注册中心;
- 服务消费者 Eureka Client 启动时,也会向服务注册中心注册;
- 服务消费者还会获取一份可用服务列表,该列表中包含了所有注册到服务注册中心的服务信息(包括服务提供者和自身的信息);
- 在获得了可用服务列表后,服务消费者通过 HTTP 或消息中间件远程调用服务提供者提供的服务。
服务注册中心(Eureka Server)所扮演的角色十分重要,它是服务提供者和服务消费者之间的桥梁。服务提供者只有将自己的服务注册到服务注册中心才可能被服务消费者调用,而服务消费者也只有通过服务注册中心获取可用服务列表后,才能调用所需的服务。
问题1:order-service如何得知user-service实例地址?
获取地址信息的流程如下:
- user-service服务实例启动后,将自己的信息注册到eureka-server(Eureka服务端)。这个叫服务注册
- eureka-server保存服务名称到服务实例地址列表的映射关系
- order-service根据服务名称,拉取实例地址列表。这个叫服务发现或服务拉取
问题2:order-service如何从多个user-service实例中选择具体的实例?
- order-service从实例列表中利用负载均衡算法选中一个实例地址
- 向该实例地址发起远程调用
问题3:order-service如何得知某个user-service实例是否依然健康,是不是已经宕机?
- user-service会每隔一段时间(默认30秒)向eureka-server发起请求,报告自己状态,称为心跳
- 当超过一定时间没有发送心跳时,eureka-server会认为微服务实例故障,将该实例从服务列表中剔除
- order-service拉取服务时,就能将故障实例排除了
下面看一个实例:
3.2 搭建eureka-server
步骤:
1.单独创建Eureka的module,pom.xml引入网飞依赖,因为是服务端所以使用server依赖
<!--eureka服务端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
2.添加配置文件内容application.yml
server:
port: 10086 #注册中心的端口
spring:
application: #eureka服务端名称
name: eurekaserver
eureka:
client:
service-url: #eureka地址信息,为eureka集群使用
defaultZone: http://localhost:10086/eureka
3.添加主启动类和注解
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication{
public static void main(String[] args){
SpringApplication.run(EurekaServerApplication.class,args);
}
}
注册中心服务端搭建成功

3.3 搭建eureka-client
步骤同配置eureka-server,只是依赖改成eureka-client即可。
pom.xml
<!--eureka客户端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
配置文件application.yml
spring:
application: #eureka服务端名称
name: user-service
server:
port: 8081
eureka:
client:
service-url: #eureka地址信息,为eureka集群使用
defaultZone: http://127.0.0.1:10086/eureka
# eureka-client向服务中心注册时会自动获取当前主机名/ip,所以只需要提供服务的端口号
# 但也可以手动配置服务主机名或ip
instance:
hostname: your-hostname
preferIpAddress:false #true表述使用ip而非主机名
当运行主启动类时,服务就被注册到eureka-server.
服务提供者:需要注册自己的信息到Eureka Server
服务消费者:不需要注册自己的信息到Eureka Server,只需要引入eureka-client库,配置eureka-server地址能够与之通信即可.
idea在不同端口运行同一实例:
1.选择copy configuration

2.点击modify options添加参数,allow multiple instances允许运行多个实例;environment variables制定具体参数,例如指定端口号server.port=8082

3.产生新的实例

3.4 服务发现
服务发现/拉取是基于服务名称获取服务列表,然后再对服务列表做负载均衡。
之前使用RestTemplate
进行http请求时使用的是硬编码格式,显然不合适,服务拉取使用服务名代替ip和端口:
//2.请求user模块的数据
//String url= "http://localhost:8081/user/"+order.getUserId();
//使用eureka注册服务的服务名代替ip和端口号
String url = "http://user-service/user/"+order.getUserId();
User user = restTemplate.getForObject(url, User.class);
//用于使用http请求调用其他模块的接口
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
一定要加上负载均衡的注解,否则spring找不到user-service.至于为什么,看下一篇ribbon负载均衡原理. 另外LoadBalanced当有多个实例时,代码中不需要负责指定调用某个实例,由注册中心的的负载均衡策略决定.