eureka注册中心

我们通过RestTemplate就可以实现服务远程调用,但存在一些问题?

  • 在consumer中,我们把url地址硬编码到代码中不方便后期维护
  • consumer需要记忆user-service的地址,如果出现变更,可能得不到通知,地址将失效
  • consumer不清楚user-service的状态,服务宕(dang)机
  • user-service只有1台服务器,不具备高可用
  • 即便user-service形成集群,consumer还需要自己实现负载均衡

概括一下分布式服务必然需要面临的问题:

  • 服务管理
    • 如何自动注册和发现
    • 如何实现状态监管
    • 如何实现动态路由
  • 服务如何实现负载均衡
  • 服务如何解决容灾问题

而Eureka就是实现了服务的自动注册、发现、状态监控

一、简介

Spring Cloud Eureka,使用Netflix Eureka 来实现服务的注册与发现, 他既包含了服务端组件,也包含了客户端组件,并且服务端与客户端均采用Java编写,所以Eureka主要适用于通过Java编写的分布式系统,或是与JVM兼容语言构建的系统。

Eureka服务端,我们也称为服务注册中心,它同其他服务注册中心一样,支持高可用配置。它依托于强一致性提供良好的服务实例可用性,可以应对多种不同的故障场景。如果Eureka以集群模式部署,当集群中有分片出现故障时,那么Eureka就转入自我保护模式。它允许在分片故障的期间继续提供服务的发现和注册,当故障分片恢复运行时集群中的其他分片会把它们的状态再次同步回来。
Eureka客户端,主要处理服务的注册与发现。客户端服务通过注解和参数配置的方式,嵌入在客户端应用程序的代码中,在应用程序运行时,Eureka客户端向注册中心注册自身提供的服务并定期性的发送心跳来更新它的服务租约。同时,它也能从服务端查询当前注册的服务信息并把它们缓存到本地并周期性的刷新服务状态。

二、Eureka服务治理体系

Eureka服务治理体系三个核心角色:服务注册中心、服务提供者以及服务消费者。
服务提供者和服务的消费者,本质上也是 Eureka Client 角色。整体上可以分为两个主体:Eureka Server 和 Eureka Client。
image.png

Eureka Server:注册中心服务端

注册中心服务端主要对外提供了三个功能:

服务注册

服务提供者启动时,会通过 Eureka Client 向 Eureka Server 注册信息,Eureka Server 会存储该服务的信息,Eureka Server 内部有二层缓存机制来维护整个注册表

提供注册表

服务消费者在调用服务时,如果 Eureka Client 没有缓存注册表的话,会从 Eureka Server 获取最新的注册表

同步状态

Eureka Client 通过注册、心跳机制和 Eureka Server 同步当前客户端的状态。

Eureka Client:注册中心客户端

Eureka Client 是一个 Java 客户端,用于简化与 Eureka Server 的交互。Eureka Client 会拉取、更新和缓存 Eureka Server 中的信息。因此当所有的 Eureka Server 节点都宕掉,服务消费者依然可以使用缓存中的信息找到服务提供者,但是当服务有更改的时候会出现信息不一致。

Register: 服务注册

服务的提供者,将自身注册到注册中心,服务提供者也是一个 Eureka Client。当 Eureka Client 向 Eureka Server 注册时,它提供自身的元数据,比如 IP 地址、端口,运行状况指示符 URL,主页等。

Renew: 服务续约

Eureka Client 会每隔 30 秒发送一次心跳来续约。 通过续约来告知 Eureka Server 该 Eureka Client 运行正常,没有出现问题。 默认情况下,如果 Eureka Server 在 90 秒内没有收到 Eureka Client 的续约,Server 端会将实例从其注册表中删除,此时间可配置,一般情况不建议更改。

服务续约的两个重要属性
#服务续约任务的调用间隔时间,默认为30秒
eureka.instance.lease-renewal-interval-in-seconds=30
#服务失效的时间,默认为90秒。
eureka.instance.lease-expiration-duration-in-seconds=90

Eviction 服务剔除

当 Eureka Client 和 Eureka Server 不再有心跳时,Eureka Server 会将该服务实例从服务注册列表中删除,即服务剔除。

Cancel: 服务下线

Eureka Client 在程序关闭时向 Eureka Server 发送取消请求。 发送请求后,该客户端实例信息将从 Eureka Server 的实例注册表中删除。该下线请求不会自动完成,它需要调用以下内容:

DiscoveryManager.getInstance().shutdownComponent()
GetRegisty: 获取注册列表信息

Eureka Client 从服务器获取注册表信息,并将其缓存在本地。客户端会使用该信息查找其他服务,从而进行远程调用。该注册列表信息定期(每30秒钟)更新一次。每次返回注册列表信息可能与 Eureka Client 的缓存信息不同,Eureka Client 自动处理。
如果由于某种原因导致注册列表信息不能及时匹配,Eureka Client 则会重新获取整个注册表信息。 Eureka Server 缓存注册列表信息,整个注册表以及每个应用程序的信息进行了压缩,压缩内容和没有压缩的内容完全相同。Eureka Client 和 Eureka Server 可以使用 JSON/XML 格式进行通讯。在默认情况下 Eureka Client 使用压缩 JSON 格式来获取注册列表的信息。
获取服务是服务消费者的基础,所以必有两个重要参数需要注意:

# 启用服务消费者从注册中心拉取服务列表的功能
eureka.client.fetch-registry=true
# 设置服务消费者从注册中心拉取服务列表的间隔
eureka.client.registry-fetch-interval-seconds=30
Remote Call: 远程调用

当 Eureka Client 从注册中心获取到服务提供者信息后,就可以通过 Http 请求调用对应的服务;服务提供者有多个时,Eureka Client 客户端会通过 Ribbon 自动进行负载均衡。

三、自我保护机制

默认情况下,如果 Eureka Server 在一定的 90s 内没有接收到某个微服务实例的心跳,会注销该实例。但是在微服务架构下服务之间通常都是跨进程调用,网络通信往往会面临着各种问题,比如微服务状态正常,网络分区故障,导致此实例被注销。
固定时间内大量实例被注销,可能会严重威胁整个微服务架构的可用性。为了解决这个问题,Eureka 开发了自我保护机制,那么什么是自我保护机制呢?
Eureka Server 在运行期间会去统计心跳失败比例在 15 分钟之内是否低于 85%,如果低于 85%,Eureka Server 即会进入自我保护机制。
Eureka Server 触发自我保护机制后,页面会出现提示:
image.png
Eureka Server 进入自我保护机制,会出现以下几种情况:

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

Eureka 自我保护机制是为了防止误杀服务而提供的一个机制。当个别客户端出现心跳失联时,则认为是客户端的问题,剔除掉客户端;当 Eureka 捕获到大量的心跳失败时,则认为可能是网络问题,进入自我保护机制;当客户端心跳恢复时,Eureka 会自动退出自我保护机制。
如果在保护期内刚好这个服务提供者非正常下线了,此时服务消费者就会拿到一个无效的服务实例,即会调用失败。对于这个问题需要服务消费者端要有一些容错机制,如重试,断路器等。

通过在 Eureka Server 配置如下参数,开启或者关闭保护机制,生产环境建议打开:

eureka.server.enable-self-preservation=true

四、Eurka 工作流程

1、Eureka Server 启动成功,等待服务端注册。在启动过程中如果配置了集群,集群之间定时通过 Replicate 同步注册表,每个 Eureka Server 都存在独立完整的服务注册表信息
2、Eureka Client 启动时根据配置的 Eureka Server 地址去注册中心注册服务
3、Eureka Client 会每 30s 向 Eureka Server 发送一次心跳请求,证明客户端服务正常
4、当 Eureka Server 90s 内没有收到 Eureka Client 的心跳,注册中心则认为该节点失效,会注销该实例
5、单位时间内 Eureka Server 统计到有大量的 Eureka Client 没有上送心跳,则认为可能为网络异常,进入自我保护机制,不再剔除没有上送心跳的客户端
6、当 Eureka Client 心跳请求恢复正常之后,Eureka Server 自动退出自我保护模式
7、Eureka Client 定时全量或者增量从注册中心获取服务注册表,并且将获取到的信息缓存到本地
8、服务调用时,Eureka Client 会先从本地缓存找寻调取的服务。如果获取不到,先从注册中心刷新注册表,再同步到本地缓存
9、Eureka Client 获取到目标服务器信息,发起服务调用
10、Eureka Client 程序关闭时向 Eureka Server 发送取消请求,Eureka Server 将实例从注册表中删除

五、使用

springcloud版本:

 <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Finchley.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

服务端

导入依赖

  <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
   </dependency>
application.yml
server:
  port: 9001 #启动端口

spring:
  application:
    name: eureka-server
eureka:
  instance:
    #单机hostname: localhost 127.0.0.1
    hostname: localhost        #eureka服务端的实例名称
  client:
    ##是否需要将自己注册到注册中心(集群时需要设为true)#false表示不向注册中心注册自己。
    register-with-eureka: false
    #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
    fetch-registry: false
    service-url:
      #单机设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址(单机)。
      #defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
      #Eureka高可用时设置其他的Eureka之间通信
      #defaultZone: http://eureka7003.com:7003/eureka/,http://eureka7004.com:7004/eureka/
      defaultZone: http://localhost:9001/eureka/
      server:
    #Eureka服务端关闭心跳连接测试
        enable-self-preservation: false

启动类添加注解@EnableEurekaServer

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

}

启动

访问:http://localhost:9001/
image.png

客户端

导入依赖

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

启动类添加注解@EnableEurekaClient

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

}

application.yml

server:
  port: 9002

spring:
  application:
    name: eureka-client
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:9001/eureka
    ##是否需要将自己注册注册中心
    register-with-eureka: true
    ##是否需要检索服务信息
    fetch-registry: true

访问

http://localhost:9001/
服务注册成功:
image.png

六、服务之间调用

服务提供者 eureka-client

@RestController
public class DemoRest {

    @Value("${server.port}")
    private Integer port;

    @RequestMapping("/hello")
    public String hello() {
        return "hello world:" + port;
    }
}

服务消费者 eureka-client1

添加RestTemplate实例进行服务之间的调用,使用@LoadBalanced负载均衡,不使用则一般的调用

package com.zengqingfa.eureka.client;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

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

    /**
     * @return
     * LoadBalanced 使用负载均衡
     */
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate1() {
        return new RestTemplate();
    }

    /**
     * @return
     * 不使用负载均衡,直接使用ip地址进行调用
     */
    @Bean
    public RestTemplate restTemplate2() {
        return new RestTemplate();
    }

}

服务消费:

package com.zengqingfa.eureka.client.rest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.HashMap;
import java.util.Map;

@RestController
public class DemoRest {

    /**
     * eureka-client:为Eureka Server中心的微服务实例名称
     * RestTemplate如果生成Bean的时候加了@LoadBalanced注解,则不能在请求路径里写ip,必须写服务名称service_id
     * 要想在请求路径里写ip地址和端口,不能使用 @LoadBalanced
     * private static final String REST_URL_PREFIX_B = "http://10.74.131.39:9002";
     */
    private static final String REST_URL_PREFIX_A = "http://eureka-client";


    @Autowired
    RestTemplate restTemplate1;

    @RequestMapping("/demo1")
    public String hello() {
        String resultA = restTemplate1.getForObject(REST_URL_PREFIX_A + "/hello", String.class);
        return resultA;
    }


    private static final String REST_URL_PREFIX_B = "http://127.0.0.1:9002";

    @Autowired
    RestTemplate restTemplate2;

    @RequestMapping("/demo2")
    public String hello2() {
        String resultA = restTemplate2.getForObject(REST_URL_PREFIX_B + "/hello", String.class);
        return resultA;
    }
}

调用结果:
[http://localho](http://localho)st:9444/demo1
[http://localho](http://localho)st:9444/demo2

hello world:9002

七、注册中心高可用

八、安全

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值