一、注册中心

1、什么是注册中心

注册中心是微服务构架的通信录,记录服务和服务地址的映射关系。在分布式架构中,服务会注册到这里,当服务需要调用其它服务时,就到这里找到服务的地址,进行调用。注册中心一般有三种角色,他们之间相互交互,如图:
在这里插入图片描述

  • 服务治理:管理服务与服务之间的依赖关系,以实现服务调用,负载均衡,容错等,实现服务注册与服务发现。
  • 服务注册:在服务注册与发现中,有一个注册中心,当服务启动时,会将该服务的相关信息注册到注册中心上去。如:服务url地址,服务消费者会以该别名方式去注册中心上获取对应服务,进而进行远程调用。
  • Service Provider:服务提供者(或Server)。启动时将自己的IP等信息注册到注册中心
  • Service Consumer:服务消费者(或Client)。从注册中心获取提供者的信息
  • Registry:注册中心

2、常见注册中心

1、注册中心之间对比

在这里插入图片描述

2、CAP原则

这里我们讲解一下CAP原则:

CAP原则又称CAP定理,指的是在一个分布式系统中, Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),三者不可得兼。要么AP,要么CP,要么AC,但是不存在CAP(AC情况好像很少)。

  • 一致性(C):在分布式系统中的所有数据备份,在同一时刻是否同样的值。(等同于所有节点访问同一份最新的数据副本)
  • 可用性(A):保证每个请求不管成功或者失败都有响应。
  • 分区容忍性(P):系统中任意信息的丢失或失败不会影响系统的继续运作。

取舍策略

CAP 三个特性只能满足其中两个,那么取舍的策略就共有三种:

  1. CA without P:如果不要求P(不允许分区),则C(强一致性)和A(可用性)是可以保证的。但放弃 P 的同时也就意味着放弃了系统的扩展性,也就是分布式节点受限,没办法部署子节点,这是违背分布式系统设计的初衷的。
  2. CP without A:如果不要求A(可用),相当于每个请求都需要在服务器之间保持强一致,而P(分区)会导致同步时间无限延长(也就是等待数据同步完才能正常访问服务),一旦发生网络故障或者消息丢失等情况,就要牺牲用户的体验,等待所有数据全部一致了之后再让用户访问系统。设计成 CP 的系统其实不少,最典型的就是分布式数据库,如 Redis、HBase 等。对于这些分布式数据库来说,数据的一致性是最基本的要求,因为如果连这个标准都达不到,那么直接采用关系型数据库就好,没必要再浪费资源来部署分布式数据库。
  3. AP without C:要高可用并允许分区,则需放弃一致性。一旦分区发生,节点之间可能会失去联系,为了高可用,每个节点只能用本地数据提供服务,而这样会导致全局数据的不一致性。典型的应用就如某米的抢购手机场景,可能前几秒你浏览商品的时候页面提示是有库存的,当你选择完商品准备下单的时候,系统提示你下单失败,商品已售完。这其实就是先在 A(可用性)方面保证系统可以正常的服务,然后在数据的一致性方面做了些牺牲,虽然多少会影响一些用户体验,但也不至于造成用户购物流程的严重阻塞。

总结
       现如今,对于多数大型互联网应用的场景,主机众多、部署分散,而且现在的集群规模越来越大,节点只会越来越多,所以节点故障、网络故障是常态,因此分区容错性也就成为了一个分布式系统必然要面对的问题。那么就只能在 C 和 A 之间进行取舍。但对于传统的项目就可能有所不同,拿银行的转账系统来说,涉及到金钱的对于数据一致性不能做出一丝的让步,C 必须保证,出现网络故障的话,宁可停止服务,可以在 A 和 P 之间做取舍。而互联网非金融项目普遍都是基于 AP 模式。

总而言之,没有最好的策略,好的系统应该是根据业务场景来进行架构设计的,只有适合的才是最好的。

3、注册中心的作用

了解了什么是注册中心,那么我们继续谈谈,为什么需要注册中心。在分布式系统中,我们不仅仅是需要在注册中心找到服务和服务地址的映射关系这么简单,我们还需要考虑更多更复杂的问题:

  • 服务注册后,如何被及时发现
  • 服务宕机后,如何及时下线
  • 服务如何有效的水平扩展
  • 服务发现时,如何进行路由
  • 服务异常时,如何进行降级
  • 注册中心如何实现自身的高可用

这些问题的解决都依赖于注册中心。简单看,注册中心的功能有点类似于 DNS 服务器或者负载均衡器,而实际上,注册中心作为微服务的基础组件,可能要更加复杂,也需要更多的灵活性和时效性。所以我们还需要学习更多 Spring Cloud 微服务组件协同完成应用开发。

注册中心解决了以下问题:

  • 服务管理
  • 服务之间的自动发现
  • 服务的依赖关系管理

二、Eureka简介

1、介绍

Eureka 是 Netflix 开发的服务发现组件,本身是一个基于 REST 的服务。Spring Cloud 将它集成在其子项目 Spring Cloud Netflix 中,实现 Spring Cloud 的服务注册与发现,同时还提供了负载均衡、故障转移等能力。

2、三种角色

Eureka Server
通过 Register、Get、Renew 等接口提供服务的注册和发现。

Service Provider(Eureka Client)
服务提供方,把自身的服务实例注册到 Eureka Server 中。同时拉取服务列表,消费其他服务。

Service Consumer(Eureka Client)
服务调用方,通过 Eureka Server 获取服务列表,消费服务。

在这里插入图片描述
在这里插入图片描述

三、搭建Eureka服务端

1、创建maven工程

在这里插入图片描述

2、导入依赖

导入Eureka服务端、web模块依赖

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
    </dependency>
    <!-- web开发场景一般都需要这个包 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- 应用监控,可图形化管理 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
</dependencies>

3、配置application.yml

server:
  port: 7001
 
eureka:
  instance:
    hostname: localhost
 
  client:
  	# 是否将自己注册到注册中心,默认为 true
    register-with-eureka: false
    # 是否从注册中心获取服务注册信息,默认为 true
    fetchRegistry: false
    # 注册中心对外暴露的注册地址
    service-url:
      defaultZone: http://localhost:7001/eureka

4、创建主启动类

@SpringBootApplication
//Eureka服务端注解
@EnableEurekaServer
public class Eureka7001 {
    public static void main(String[] args) {
        SpringApplication.run(Eureka7001.class,args);
    }
}

5、启动Eureka注册中心

访问http://localhost:7001

在这里插入图片描述

四、搭建服务提供者

1、创建maven工程

在这里插入图片描述

2、导入依赖

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

3、配置application.yml

server:
  port: 8003
 
spring:
  application:
    name: provider8003
 
eureka:
  client:
  	# 是否将自己注册到注册中心,默认为 true
    register-with-eureka: true
    # 是否从注册中心获取服务注册信息,默认为 true
    fetchRegistry: true
    service-url:
   	  # 注册中心对外暴露的注册地址
      defaultZone: http://localhost:7001/eureka

4、创建启动类

@SpringBootApplication
//指明该服务为Eureka客户端
@EnableEurekaClient
public class Provider8003 {
    public static void main(String[] args) {
        SpringApplication.run(Provider8003.class,args);
    }
}

5、创建controller


@RestController
public class HelloController {
    @GetMapping("/hello")
    public String hello(){
        return "Hello,Eureka";
    }
}

6、测试该服务

启动访问http://localhost:8003/hello

可以发现注册中心已经注册该服务

在这里插入图片描述
注意:这行红字先不用管,这里是Eureka的自我保护机制,后续章节七会讲。

五、搭建服务消费者

1、创建maven工程

在这里插入图片描述

2、导入依赖

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

3、配置application.yml

server:
  port: 8004
 
spring:
  application:
    name: Consumer8004
 
eureka:
  client:
    register-with-eureka: true
    fetchRegistry: true
    service-url:
      defaultZone: http://localhost:7001/eureka

4、创建主启动类

开启Eureka客户端

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

5、创建配置类配置远程调用

@Configuration
public class ResConfig {
    @Bean
    //负载均衡注解
    @LoadBalanced
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}

6、创建controller

①PROVIDER8003:服务提供者的名称,其在注册中心上注册,可以通过该名称找到对应ip地址;
 
②restTemplate.getForObject(”远程调用服务ip地址“,“调用服务方法返回类型”)


@RestController
public class HelloController {
    //调用服务地址
    private final static String url="http://PROVIDER8003";
 
    @Autowired
    RestTemplate restTemplate;
 
    @GetMapping("consumer")
    public String hello(){
        return restTemplate.getForObject(url+"/hello",String.class);
    }
}

六、整体测试

①启动Eureka7001

②启动服务提供者Provider8003

③启动服务消费者Consumner8004

④访问http://loaclhost:8004/hello

结果如下:

在这里插入图片描述
在这里插入图片描述
测试成功!!!!

七、Eureka 自我保护

还记得第四章搭建服务提供者后访问Eureka网页时出现的那两行红色警示吗,那个就是eureka的自我保护。

1、启动条件

一般情况下,服务在 Eureka 上注册后,会每 30 秒发送心跳包,Eureka 通过心跳来判断服务是否健康,同时会定期删除超过 90 秒没有发送心跳的服务。

有两种情况会导致 Eureka Server 收不到微服务的心跳:

  • 微服务自身的原因
  • 微服务与 Eureka 之间的网络故障

自我保护模式

Eureka Server 在运行期间会去统计心跳失败比例在 15 分钟之内是否低于 85%,如果低于 85%,Eureka Server 会将这些实例保护起来,让这些实例不会过期,同时提示一个警告。这种算法叫做 Eureka Server 的自我保护模式。

2、为什么要启动自我保护

  • 因为同时保留"好数据"与"坏数据"总比丢掉任何数据要更好,当网络故障恢复后,这个 Eureka 节点会退出"自我保护模式"。
  • Eureka还有客户端缓存功能(也就是微服务的缓存功能)。即使 Eureka 集群中所有节点都宕机失效,微服务的 Provider 和Consumer 都能正常通信。
  • 微服务的负载均衡策略会自动剔除死亡的微服务节点。

3、如何关闭自我保护

注册中心配置自我保护

eureka:
  server:
    enable-self-preservation: false # true:开启自我保护模式,false:关闭自我保护模式
    eviction-interval-timer-in-ms: 60000 # 清理间隔(单位:毫秒,默认是 60*1000)
Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐