1、服务注册中心:Eureka 提供的服务端,提供服务注册与发现的功能。
2、失效剔除:对于那些非正常下线的服务实例(内存溢出、网络故障导致的),服务注册中心不能收到“服务下线”的请求,为了将这些无法提供服务的实例从服务列表中剔除,Eureka Server 在启动的时候会创建一个定时任务,默认每隔一段时间(默认 60s)将当前清单中超时(默认 90s)没有续约的服务剔除出去。
3、自我保护:Eureka Server 在运行期间,会统计心跳失败的比例在 15 分钟之内是否低于 85%,如果出现低于的情况(生产环境由于网络不稳定会导致),Eureka Server 会降当前的实例注册信息保护起来,让这些实例不过期,尽可能保护这些注册信息,但是在这保护期间内实例出现问题,那么客户端就很容易拿到实际上已经不存在的服务实例,会出现调用失败的情况,所以客户端必须有容错机制,比如可以使用请求重试、断路器等机制。在本地进行开发时可以使用 eureka.server.enable-self-preseervation=false 参数来关闭保护机制,以确保注册中心可以将不可用的实例剔除。
4、服务提供者:提供服务的应用,可以是 SpringBoot 应用也可以是其他的技术平台且遵循 Eureka 通信机制的应用。他将自己提供的服务注册到 Eureka,以供其他应用发现,(如:service 层)。
5、服务注册:服务提供者在启动的时候会通过发送 Rest 请求的方式将自己注册到 Eureka Server(服务注册中心)中,同时带上自身服务的一些元数据,Eureka Server 接收到这个Rest 请求后,将元数据存储在一个双层结构 Map 中,第一层的 key 是服务名,第二层 key是具体服务的实例名。
6、服务同步:若有两个或两个以上的 Eureka Server(服务注册中心)时,他们之间是互相注册的,当服务提供者发送注册请求到一个服务注册中心时,它会将该请求转发到集群中相连的其他注册中心,从而实现注册中心间的服务同步,这样服务提供者的服务信息可以通过任意一台服务中心获取到。
7、服务续约:在注册完服务之后,服务提供者会维护一个心跳来持续告诉 Eureka Server:“我还活着”,以防止 Eureka Server 的“剔除任务”将该服务实例从服务列表中排除出去。配置:eureka.instance.lease-renewal-in-seconds=30(续约任务的调用间隔时间,默认 30秒,也就是每隔 30 秒向服务端发送一次心跳,证明自己依然存活),eureka.instance.lease expiration-duration-in-seconds=90(服务失效时间,默认 90 秒,也就是告诉服务端,如
果 90 秒之内没有给你发送心跳就证明我“死”了,将我剔除)。
8、服务消费者:消费者应用从服务注册中心获取服务列表,从而使消费者可以知道去何处调用其所需要的服务,如:Ribbon 实现消费方式、Feign 实现消费方式。
9、获取服务:当启动服务消费者的时候,它会发送一个 Rest 请求给注册中心,获取上面注册的服务清单,Eureka Server 会维护一份只读的服务清单来返回给客户端,并且每三十秒更新一次。
10、服务调用:在服务消费者获取到服务清单后,通过服务名可以获得具体提供服务的实例名和该实例的元信息,采用 Ribbon 实现负载均衡。
11、服务下线:当服务实例进行正常的关闭操作时,它会触发一个服务下线的 Rest 请求给Eureka Server,告诉服务注册中心“我要下线了”。服务端接收到请求之后,将该服务状态设置为下线,并把下线时间传播出去。
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-dependenciesartifactId>
<version>Hoxton.SR5version>
<type>pomtype>
<scope>importscope>
dependency>
dependencies>
dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-serverartifactId>
dependency>
dependencies>
eureka:
client:
register-with-eureka: false
fetch-registry: false
service-url:
# defaultZone: http://localhost:7001/eureka
defaultZone: http://localhost:7002/eureka,http://localhost:7003/eureka
server:
enable-self-preservation: false
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerMain7001 {
public static void main(String[] args) {
SpringApplication.run(EurekaServerMain7001.class, args);
}
}
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-dependenciesartifactId>
<version>Hoxton.SR5version>
<type>pomtype>
<scope>importscope>
dependency>
dependencies>
dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
dependency>
dependencies>
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka,http://localhost:7002/eureka
instance:
prefer-ip-address: true
@SpringBootApplication
@EnableEurekaClient
public class UserServiceMain8002 {
public static void main(String[] args) {
SpringApplication.run(UserServiceMain8002.class, args);
}
}
@RestController
@Slf4j
public class UserController {
@Autowired
private IUserService iUserService;
@GetMapping("/user/sayHi/{name}")
public CommonRsp<String> sayHello (@PathVariable("name") String name) throws Exception {
log.info("Hi {}", name);
return CommonRspUtils.buildSuccessRsp(name);
}
@GetMapping("/user/{userId}")
public CommonRsp<User> getById (@PathVariable("userId") String userId) throws Exception {
User user = this.iUserService.getUserById(userId);
return CommonRspUtils.buildSuccessRsp();
}
}
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-dependenciesartifactId>
<version>Hoxton.SR5version>
<type>pomtype>
<scope>importscope>
dependency>
dependencies>
dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-ribbonartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-openfeignartifactId>
dependency>
dependencies>
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka
# defaultZone: http://localhost:7001/eureka,http://localhost:7002/eureka,http://localhost:7003/eureka
@SpringBootApplication
@EnableEurekaClient
public class UserServiceMain8001 {
public static void main(String[] args) {
SpringApplication.run(UserServiceMain8001.class, args);
}
}
// 1.使用ribbon
@Configuration
public class RestTemplateConfig {
@Bean
@LoadBalanced
public RestTemplate getRestTemplate () {
return new RestTemplate();
}
}
@RestController
public class RemoteCallerController {
@Autowired
private RestTemplate restTemplate;
private static final String USER_SERVICE_NM = "http://cloud-user-service";
@GetMapping("/user/sayHi/{name}")
public CommonRsp<User> sayHi (@PathVariable("name") String name) throws Exception {
String url = USER_SERVICE_NM + "/user/sayHi/" + name;
CommonRsp<User> result = (CommonRsp<User>) restTemplate.getForObject(url, CommonRsp.class, name);
return result;
}
}
// 2.使用feign
@FeignClient(value="cloud-user-service")
public interface IUserService {
@GetMapping("/user/sayHi/{name}")
public CommonRsp<String> sayHi(@PathVariable("name") String name) throws Exception;
}
public class RemoteCallerController {
@Autowired
private IUserService iUserService;
@GetMapping("/user/sayHi/{name}")
public CommonRsp<String> sayHi(@PathVariable("name") String name) throws Exception {
return iUserService.sayHi(name);
}
}