服务注册中心Eureka - Spring Cloud系列(一)

本文章基于spring-boot-starter-parent 2.0.6RELEASE,spring-cloud-dependencies Finchley.SR2。

Eureka是什么

Eureka 是 Netflix的子模块之一, 用于实现服务注册与发现,是微服务架构中最为核心和基础的模块。Eureka有两个组件:一个是EurekaServer,用于定位服务以实现中间层服务器的负载均衡和故障转移;另个一是EurekaClient(集成在我们的微服务中),用于与Server进行交互,并可以通过服务标识符去获取服务。 Spring Cloud 基于 Netflix Eureka做了二次封装,主要负责完成微服务架构中的服务治理功能。

Eureka基础架构

三个核心要素:

  • 服务注册中心: Eureka提供的服务端,提供服务注册于发现功能
  • 服务提供者: 提供服务的应用,可以是spring boot应用,也可以是其他技术平台且遵循Eureka通信机制的应用。
  • 服务消费者: 消费者应用从服务注册中心获取服务列表,从而使消费者可以知道去何处调用其所需要的服务。

下图是来自Eureka官方的基于集群配置的架构图:
eureka netflix

  • 处于不同节点的Eureka Server通过Replicate进行数据同步;
  • Application Service为服务提供者,向Eureka Server注册、服务同步、服务续约等;
  • Application Client为服务消费者,可以向Eureka Server获取服务实例列表、服务调用、服务续约、服务下线等;
  • Make Remote Call完成一次服务调用。

服务治理机制:

服务启动后向Eureka注册,Eureka Server会将注册信息向其他Eureka Server进行同步,当服务消费者要调用服务提供者,则向服务注册中心获取服务提供者地址,然后会将服务提供者地址缓存在本地,下次再调用时,则直接从本地缓存中取,完成一次调用。

当服务注册中心Eureka Server检测到服务提供者因为宕机、网络原因不可用时,则在服务注册中心将服务置为DOWN状态,并把当前服务提供者状态向订阅者发布,订阅过的服务消费者更新本地缓存。

服务提供者在启动后,周期性(默认30秒)向Eureka Server发送心跳,以证明当前服务是可用状态。Eureka Server在一定的时间(默认90秒)未收到客户端的心跳,则认为服务宕机,注销该实例。

Eureka使用

下面用一个用户获取订单的例子,来说明Eureka的使用:

Eureka服务注册中心

Dependency:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>

application.ym:

server:
  port: 8081 #默认值8080

eureka:
  server:
    enable-self-preservation: false #关闭自我保护机制
    eviction-interval-timer-in-ms: 4000 #设置清理间隔(单位:毫秒 默认是60*1000)
  instance:
    hostname: localhost
  client:
    register-with-eureka: false #不把自己作为一个客户端注册到自己身上
    fetch-registry: false #不从服务端获取注册信息(因为在这里自己就是服务端,而且已经禁用自己注 册了)
    serviceUrl:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka

在spring boot启动项目上加上注解:@EnableEurekaServer

@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServerApplication.class);
    }
}

浏览器访问http://localhsot:8081,看到下图则说明服务注册中心启动成功
eureka server

服务提供者(Order)

Dependency:

<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

application.yml:

server:
  port: 6000
  
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8081/eureka     #Eureka服务端提供的注册地址
  instance:
    instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port} #此实例注册到eureka服务端的唯一的实例ID
    prefer-ip-address: true #是否显示IP地址
spring:
  application:
    name: order-microservice #此实例注册到eureka服务端的name

OrderController:

@RestController
public class OrderController {
    @RequestMapping("/getOrder.do")
    public Map<String,Object> getOrder() {
        Map<String, Object> map = new HashMap();
        map.put("key","order");
        return map;
    }
}

启动类加上@EnableEurekaClient注解:

@SpringBootApplication
@EnableEurekaClient
public class AppOrderApplication {
    public static void main(String[] args) {
        SpringApplication.run(AppOrderApplication.class);
    }
}
服务消费者(User)

Dependency:

<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

application.yml:

server:
  port: 5000

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8081/eureka     #Eureka服务端提供的注册地址
  instance:
    instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port} #此实例注册到eureka服务端的唯一的实例ID
    prefer-ip-address: true #是否显示IP地址
spring:
  application:
    name: user-microservice #此实例注册到eureka服务端的name

AppConfig:

@Configuration
public class AppConfig {
    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

UserController:

@RestController
public class UserController {
    @Autowired
    private RestTemplate restTemplate;

    @RequestMapping("/getOrder.do")
    public Object getOrder() {
        return restTemplate.getForObject("http://localhost:6000/getOrder.do",Object.class);
    }
}

启动类上加上@EnableEurekaClient注解:

@SpringBootApplication
@EnableEurekaClient
public class AppUserApplication {
    public static void main(String[] args) {
        SpringApplication.run(AppUserApplication.class);
    }
}

客户端与服务端启动后,访问Eurek注册中心即可看到服务实例已注册:
eureka client instance
浏览器访问http://localhost:5000/getOrder.do ,结果页面如下,说明服务调用成功。
在这里插入图片描述

Eureka集群

Eureka Server的设计一开始就考虑了高可用问题,在Eureka的服务治理设计中,所有节点即是服务提供方,也是服务消费方,服务注册中心也是。在上面的单节点服务注册中心的配置文件中,我们设置了下面两个配置:

 register-with-eureka: false #不把自己作为一个客户端注册到自己身上
 fetch-registry: false #不从服务端获取注册信息(因为在这里自己就是服务端,而且已

Eureka Server的高可用就是将自己作为服务向其他服务注册中心注册自己。

下面进行实例演示,在单台机器上模拟集群环境:
1.修改/etc/host文件,mac上路径为/etc/hosts,Windows系统路径C:\Window\System32\drivers\etc\hosts
修改hosts
2.简单起见,就不复制两个工程了,直接通过配置三个profile来启动三个Eureka Server

spring:
  application:
    name: eureka-server

---
spring:
  profiles: peer1
server:
  port: 8081

eureka:
  server:
    enable-self-preservation: false #关闭自我保护机制
    eviction-interval-timer-in-ms: 4000 #设置清理间隔(单位:毫秒 默认是60*1000)
  instance:
    hostname: peer1

  client:
    serviceUrl:
      defaultZone: http://peer2:8082/eureka,http://peer3:8083/eureka

---
spring:
  profiles: peer2
server:
  port: 8082

eureka:
  server:
    enable-self-preservation: false #关闭自我保护机制
    eviction-interval-timer-in-ms: 4000 #设置清理间隔(单位:毫秒 默认是60*1000)
  instance:
    hostname: peer2

  client:
    serviceUrl:
      defaultZone: http://peer1:8081/eureka,http://peer3:8083/eureka

---
spring:
  profiles: peer3
server:
  port: 8083

eureka:
  server:
    enable-self-preservation: false #关闭自我保护机制
    eviction-interval-timer-in-ms: 4000 #设置清理间隔(单位:毫秒 默认是60*1000)
  instance:
    hostname: peer3

  client:
    serviceUrl:
      defaultZone: http://peer1:8081/eureka,http://peer2:8082/eureka

.yml文件中 ---标识文件分割.

3. 启动项目
打成jar包启动方式:

java -jar eurka-server-0.0.1.jar --spring.profiles.active=peer1
java -jar eurka-server-0.0.1.jar --spring.profiles.active=peer2
java -jar eurka-server-0.0.1.jar --spring.profiles.active=peer3

这里使用IDEA启动:
idea启动eureka
三个配置依次填入peer1、peer2、peer3

4.访问Eureka服务注册中心
http://peer1:8081 http://peer2:8082 http://peer3:8083 即可看到集群搭建成功。
eureka jq1
eureka jq2

Eureka的自保护机制

服务注册到Eureka Server之后,会维护一个心跳连接,告诉Eureka Server自己还活着。Eureka Server在运行期间,会统计心跳失败的比例在15分钟之内是否低于85%,如果出现低于的情况,Eureka Server会认为客户端与注册中心出现了网络故障,会将当前的实例注册信息保护起来,让这些实例不会过期,尽可能保护这些注册信息,此时会出现以下情况:

  • Eureka 不再从注册列表中移除因为长时间没有收到心跳而过期的服务。
  • Eureka 仍然能够接收新服务的注册和查询请求,但是不会被同步到其它节点上(即保证当前节点可用)
  • 当网络稳定后,当前实例新的注册信息会被同步到其它节点中

另外,在保护期间如果实例出现问题,Eureka Server则会出现可用性问题,部分请求会失败。所以客户端也要配套容错机制,比如可以使用请求重试、断路器等机制。

本地开发的时候,可以使用eureka.server.enable-self-preservation=false参数来关闭保护机制,以确保注册中心可以将不可用的实例正确剔除。

Eureka与Zookeeper的区别

不知道CAP定理的同学请先去了解CAP定理知识。

Zookeeper在设计的时候遵循的是CP原则,即保证一致性和分区容错性,Zookeeper会出现这样一种情况,当master节点因为网络故障与其他节点失去联系时剩余节点会重新进行leader选举,问题在于,选举leader的时间太长:30~120s,且选举 间整个Zookeeper集群是不可用的,这就导致在选举期间注册服务处于瘫痪状态,在云部署的环境下,因网络环境使Zookeeper集群失去master节点是较大概率发生的事情,虽然服务能够最终恢复,但是漫长的选举时间导致长期的服务注册不可用是不能容忍的。

Eureka在设计的时候遵循的是AP原则,即可用性和分区容错性。Eureka各个节点(服务)是平等的, 没有主从之分,几个节点 down掉不会影响正常工作,剩余的节点(服务) 依然可以提供注册与查询服务,而Eureka的客户端在向某个 Eureka注册或发现连接失败,则会自动切换到其他节点,也就是说,只要有一台Eureka还在,就能注册可用(保证可用性), 只不过查询到的信息不是最新的(不保证强一致)。


------------本文结束感谢您的阅读------------
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值