一、Eureka简介
Eureka是Netflix开发的服务发现框架,本身是一个基于REST的服务,主要用于定位运行在AWS域中的中间层服务,以达到负载均衡和中间层服务故障转移的目的。SpringCloud将它集成在其子项目spring-cloud-netflix中,以实现SpringCloud的服务发现功能。
-
Eureka组件
Eureka包含两个组件:Eureka Server和Eureka Client。1.1 Eureka Server
Eureka Server提供服务注册服务,各个节点启动后,会在Eureka Server中进行注册,这样Eureka Server中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观的看到。
Eureka Server本身也是一个服务,默认情况下会自动注册到Eureka注册中心。
如果搭建单机版的Eureka Server注册中心,则需要配置取消Eureka Server的自动注册逻辑。毕竟当前服务注册到当前服务代表的注册中心中是一个说不通的逻辑。
Eureka Server通过Register、Get、Renew等接口提供服务的注册、发现和心跳检测等服务。
<!-- eurake-server -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
1.2 Eureka Client
Eureka Client是一个java客户端,用于简化与Eureka Server的交互,客户端同时也具备一个内置的、使用轮询(round-robin)负载算法的负载均衡器。在应用启动后,将会向Eureka Server发送心跳,默认周期为30秒,如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳,Eureka Server将会从服务注册表中把这个服务节点移除(默认90秒)。
Eureka Client分为两个角色,分别是:Application Service(Service Provider)和Application Client(Service Consumer)
<!-- Eureka-client -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
- Eureka和Zookeeper的不同
ZooKeeper注册中心集群搭建后,集群中各节点呈现主从关系,集群中只有主节点对外提供服务的注册和发现功能,从节点相当于备份节点,只有主节点宕机时,从节点会选举出一个新的主节点,继续提供服务的注册和发现功能。
Eureka Server注册中心集群中每个节点都是平等的,集群中的所有节点同时对外提供服务的发现和注册等功能。同时集群中每个Eureka Server节点又是一个微服务,也就是说,每个节点都可以在集群中的其他节点上注册当前服务。又因为每个节点都是注册中心,所以节点之间又可以相互注册当前节点中已注册的服务,并发现其他节点中已注册的服务。
二、Eureka使用
- 搭建Eureka Server
依赖:
<!-- eurake-server -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
配置文件:
server:
port: 7001
eureka:
instance:
hostname: eureka7001.com # eureka服务端实例名称
client:
register-with-eureka: false #false表示不向注册中心注册自己
fetch-registry: false # 表示当前是注册中心,不需要检索服务
service-url:
# 设置eureka地址,如果是单机版就写本机地址;否则写另一个注册中心的地址
defaultZone: http://eureka7002.com:7002/eureka/
server:
port: 7002
eureka:
instance:
hostname: eureka7002.com
client:
register-with-eureka: false
fetch-registry: false
service-url:
defaultZone: http://eureka7001.com:7001/eureka/
启动类上需要加注解@EnableEurekaServer
@SpringBootApplication
@EnableEurekaServer
public class EurekaApplication7001 {
public static void main(String[] args) {
SpringApplication.run(EurekaApplication7001.class,args);
}
}
接口:
@RestController
@Slf4j //日志
public class PaymentController {
@Autowired
private PaymentService paymentService;
@Value("${server.port}")
private String serverPort;
/**
* @Description 创建订单
* @Date 18:57 2020/12/23
* @Param [serial]
* @return void
*/
@PostMapping(value = "payment/creatPayment")
public CommonResult createPayment(@RequestBody Payment payment){
int result = paymentService.creatPayment(payment);
log.info("*************插入结果:"+ result);
if (result > 0){
return new CommonResult(200,"创建订单成功,serverPort:" + serverPort,result);
}else {
return new CommonResult(444,"创建订单失败",null);
}
}
/**
* @Description 查看订单列表
* @Date 19:00 2020/12/23
* @Param []
* @return java.util.List<com.wn.springcloud.entities.Payment>
*/
@GetMapping(value = "payment/payments")
public CommonResult selectPayments(){
List<Payment> list = paymentService.selectPayments();
log.info("*************查询订单列表:" );
if (list != null){
return new CommonResult(200,"查询成功,serverPort:" + serverPort,list);
}else {
return new CommonResult(444,"订单为空",null);
}
}
/**
* @Description 查找订单
* @Date 18:59 2020/12/23
* @Param [id]
* @return com.wn.springcloud.entities.Payment
*/
@GetMapping(value = "payment/selectPaymentById/{id}")
public CommonResult selectPaymentById(@PathVariable("id") int id){
Payment payment = paymentService.selectPaymentById(id);
log.info("*************查询结果:"+ payment);
if (payment != null){
return new CommonResult(200,"查询成功,serverPort:" + serverPort,payment);
}else {
return new CommonResult(444,"未查询到对应记录,查询ID:"+ id,null);
}
}
}
- 客户端使用注册中心
2.1 provider端
依赖:
配置文件:<!-- Eureka-client --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>
server:
port: 8001
spring:
application:
name: cloud-payment-service
eureka:
client:
register-with-eureka: true # 表示向注册中心注册自己
fetch-registry: true #是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,但是集群必须设置为true才能配合ribbon使用负载
service-url:
# 设置eureka地址,需要注册到多个注册中心时,地址之间用“,”隔开
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
instance:
instance-id: payment8001 # 在eureka显示的主机名称
prefer-ip-address: true # 鼠标放在主机名称上显示ip地址
启动类上加注解@EnableEurekaClient
@EnableEurekaClient
@SpringBootApplication
public class PaymentApplication8001 {
public static void main(String[] args) {
SpringApplication.run(PaymentApplication8001.class,args);
}
}
2.2 consumer端
依赖、配置等同provider一致,这里主要记录一下怎么使用provider端的接口,这里为了方便直接用RestTemplate来测试调用远程微服务接口,一般是使用feign或者openfeign调用,这里不记录了
@Configuration
public class ApplicationContextConfig {
@LoadBalanced //负载均衡
@Bean
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
@RestController
@Slf4j
public class OrderController {
// "CLOUD-PAYMENT-SERVICE"是provider在注册中心显示的名称
public static final String PAYMENT_URL = "http://CLOUD-PAYMENT-SERVICE";
@Resource
private RestTemplate restTemplate;
/**
* @Description createPayment
* @Date 14:15 2020/12/24
* @Param [payment]
* @return com.wn.springcloud.entities.CommonResult
*/
@GetMapping(value = "/consumer/createPayment")
public CommonResult create(Payment payment){
return restTemplate.postForObject(PAYMENT_URL+"/payment/creatPayment",payment,CommonResult.class);
}
@GetMapping(value = "/consumer/selectPaymentById/{id}")
public CommonResult getPayment(@PathVariable("id") int id){
return restTemplate.getForObject(PAYMENT_URL+"/payment/selectPaymentById/"+id,CommonResult.class);
}
}
三、服务保护模式
-
介绍
默认情况下,**如果Eureka Server在一定时间内(默认90秒)没有接收到某个微服务实例的心跳,Eureka Server将会移除该实例。**但是当网络分区故障发生时,微服务与Eureka Server之间无法正常通信,而微服务本身是正常运行的,此时不应该移除这个微服务,所以引入了自我保护机制。 -
自我保护的机制
默认情况下EurekaClient定时向EurekaServer端发送心跳包,如果在短时间内(默认90秒)内超过85%的客户端节点都没有正常的心跳,那么Eureka就认为客户端与注册中心出现了网络故障,Eureka Server自动进入自我保护机制,此时会出现以下几种情况:
-
Eureka Server不再从注册列表中移除因为长时间没收到心跳而应该过期的服务。
-
Eureka Server仍然能够接受新服务的注册和查询请求,但是不会被同步到其它节点上,保证当前节点依然可用。
-
当网络稳定时,当前Eureka Server新的注册信息会被同步到其它节点中。
因此,Eureka Server可以很好的应对因网络故障导致部分节点失联的情况,而不会像ZooKeeper那样(如果有一半不可用的情况会导致整个集群不可用而变成瘫痪)。
-
-
关闭自我保护
- Eureka Server
eureka:
instance:
# 注册中心在收到最后一次心跳后等待时间(秒),默认90秒,超时将踢出服务
lease-expiration-duration-in-seconds: 2
# 客户端向注册中心发送心跳的时间间隔(秒),默认是30秒
lease-renewal-interval-in-seconds: 1
- Eureka Client
eureka:
server:
# 禁止自我保护,默认打开
enable-self-preservation: false
# 将保护时间由默认的90秒修改为2000毫秒
eviction-interval-timer-in-ms: 2000
后续补充…