服务注册中心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 - Spring Cloud系列(一)_第1张图片

  • 处于不同节点的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:


    org.springframework.cloud
    spring-cloud-starter-netflix-eureka-server

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 - Spring Cloud系列(一)_第2张图片

服务提供者(Order)

Dependency:


	org.springframework.cloud
	spring-cloud-starter-netflix-eureka-client

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 getOrder() {
        Map 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:


	org.springframework.cloud
	spring-cloud-starter-netflix-eureka-client

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 - Spring Cloud系列(一)_第3张图片
浏览器访问http://localhost:5000/getOrder.do ,结果页面如下,说明服务调用成功。
服务注册中心Eureka - Spring Cloud系列(一)_第4张图片

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
服务注册中心Eureka - Spring Cloud系列(一)_第5张图片
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启动:
服务注册中心Eureka - Spring Cloud系列(一)_第6张图片
三个配置依次填入peer1、peer2、peer3

4.访问Eureka服务注册中心
http://peer1:8081 http://peer2:8082 http://peer3:8083 即可看到集群搭建成功。
服务注册中心Eureka - Spring Cloud系列(一)_第7张图片
服务注册中心Eureka - Spring Cloud系列(一)_第8张图片

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还在,就能注册可用(保证可用性), 只不过查询到的信息不是最新的(不保证强一致)。


------------本文结束感谢您的阅读------------

你可能感兴趣的:(spring,cloud,Spring,Cloud微服务,Quick,Start)