SpringCloud之Eureka实现服务治理高可用

什么是服务治理

在传统MVC架构的项目中,服务调用往往都是一对一的,这种服务调用关系比较简单同时也很好管理,但是随着业务规模越来越大,一个系统被拆分成多个模块,在不同的模块中进行RPC远程调用,管理每个服务于服务之间的依赖关系比较复杂,所以需要使用服务治理,管理服务之间的依赖关系,可以实现服务调用;负载均衡;集群容错等,实现服务发现和注册。
Spring Cloud封装了Netflix公司开发的Eureka模块来实现服务治理。

Eureka架构图

在这里插入图片描述
Eureka包含两个组件:Eureka Client(客户端)和Eureka Server(服务端)

  • Eureka Server 提供服务注册

各个微服务节点通过配置启动后,会在Eureka Server中进行注册,这样Eureka Server中的服务注册表中将会存储所有可用于服务节点的信息,服务节点的信息可以在Euerka管理界面中看到

  • Eureka Client通过注册中心访问
    是一个Java客户端,内置使用轮询(round-robin)
    负载均衡算法。应用在启动后,会向Eureka Server发送心跳(默认周期30秒);如果Eureka Server在多个心跳周期内没有接受到某个节点心跳,Eureka Server将会从服务注册表中把这个服务节点移除(90秒)。

Eureka Server搭建

  • 引入pom文件
<!--eureka server -->
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
    </dependency>

在Eureka架构图中我们了解到,Eureka分为Client端和Server端,在搭建服务端的时候我们要使用spring-cloud-starter-netflix-eureka-server,版本为2.2.1

  • Eureka Server配置
server:
  port: 7001

spring:
  application:
    name: cloud-eureka-server7001

#单机版配置
eureka:
  instance:
    # eureka 服务端的实例名称
    hostname: localhost
  client:
    # false 表示不向注册中心注册自己(服务端不用自己注册自己)
    register-with-eureka: false
#    # false 表示自己就是注册中心, 我的职责是去维护服务实例,并不需要去检索服务
    fetch-registry: false
    service-url:
#      # 设置与 Eureka Server 交互的地址查询服务和注册服务都需要依赖的这个地址
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
  • 主启动类添加注解
/**
 * @author 张江丰
 * @version 11:10
 * EnableEurekaServer 启用并声明Eureka服务端
 */
@SpringBootApplication
@EnableEurekaServer
public class EurekaMain7001 {

  public static void main(String[] args) {
    SpringApplication.run(EurekaMain7001.class, args);
  }

}

@EnableEurekaServer 开启Eureka Server服务

  • 运行项目查看Eureka管理界面
    在这里插入图片描述
    这样我们就运行了一个单机版的Eureka Server服务端,下面我们在配置客户端注册到我们7001端口的Eureka服务。

Eureka Client搭建

  • 引入Pom文件
<!--eureka client -->
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>

客户端引入spring-cloud-starter-netflix-eureka-client,版本为2.2.1

  • Eureka Client配置
#定义boot的项目名称,同时也是在eureka中注册的服务名称,相同的服务使用同一个名称
eureka:
  client:
    # false 表示不向注册中心注册自己(客户端需要向服务端注册自己)
    register-with-eureka: true
    # 是否从 EurekaServer 抓取已有的注册信息,默认为 true. 单节点无所谓,集群必须设置为 true,才能配置 ribbon 使用负载均衡
    fetch-registry: true
    service-url:
      #defaultZone: http://localhost:7001/eureka/  连接单机版eureka
      # 设置与 Eureka Server 交互的地址查询服务和注册服务都需要依赖的这个地址,这里eureka集群
      defaultZone: http://localhost:7001/eureka/
  • 启动类添加注解
/**
 * EnableEurekaClient 配置并声明这是Eureka客户端
 * EnableDiscoveryClient 配置客户端服务发现DiscoveryClient
 */
@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
public class PanymentMain8001 {

  public static void main(String[] args) {
    SpringApplication.run(PanymentMain8001.class, args);
  }

}

@EnableEurekaClient 开启Eureka Client服务;@EnableDiscoveryClient 配置客户端服务发现DiscoveryClient

  • 分别启动Eureka Server和Eureka Client项目
    在这里插入图片描述
    可以看到Eureka Client客户端已经注册到Eureka Server服务端

Eureka Server 服务端集群搭建实现高可用

什么是高可用就不说了,对于服务发现治理的Eureka如果仅仅只是单机版,如果单节点服务挂掉了,那么整个微服务系统都会挂掉,所以我们要实现高可用就必须搭建集群服务。
Eureka 集群关键词就是:相互注册,相互守望。

  • Eureka Server配置
    分别创建两个Eureka Server项目端口分别为7001,7002;我本地通过hosts配置了两个本地域名分别为eureka7001.com对应7001端口,eureka7002.com对应7002端口
#-----------spring cloud---------------
#eureka注册中心服务搭建集群,在一台电脑上无法配置两个eureka映射地址,这里用两个本地域名映射两个eureka服务名来替代
127.0.0.1 eureka7001.com
127.0.0.1 eureka7002.com

#---------------------------------------
#集群配置
eureka:
  instance:
    # eureka 服务端的实例名称(在hosts文件中定义映射)
    hostname: eureka7001.com
  client:
    # false 表示不向注册中心注册自己(服务端不用自己注册自己)
    register-with-eureka: false
    # false 表示自己就是注册中心, 我的职责是去维护服务实例,并不需要去检索服务
    fetch-registry: false
    service-url:
      # 设置与 Eureka Server 交互的地址查询服务和注册服务都需要依赖的这个地址,集群设置7002,相互注册
      #如果是多个集群,通过,号分割;例如:defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
      defaultZone: http://eureka7002.com:7002/eureka/
  server:
      #关闭eureka自我保护机制(服务不可用(心跳交互超时)删除服务),默认是开启(开启状态,eureka不会立即剔除失效的服务信息【可能存在网络抖动等因素无法与eureka服务交换心跳,但是服务本身是可用的】)
    enable-self-preservation: false
      #设置接收客户端心跳时间间隔(单位毫秒,默认是90秒),
    eviction-interval-timer-in-ms: 2000
#集群配置
eureka:
  instance:
    # eureka 服务端的实例名称
    hostname: eureka7002.com
  client:
    # false 表示不向注册中心注册自己
    register-with-eureka: false
    # false 表示自己就是注册中心, 我的职责是去维护服务实例,并不需要去检索服务
    fetch-registry: false
    service-url:
      # 设置与 Eureka Server 交互的地址查询服务和注册服务都需要依赖的这个地址,集群设置7001,相互注册
       #如果是多个集群,通过,号分割;例如:defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
      defaultZone: http://eureka7001.com:7001/eureka/
  server:
    #关闭eureka自我保护机制(服务不可用(心跳交互超时)删除服务),默认是开启(开启状态,eureka不会立即剔除失效的服务信息【可能存在网络抖动等因素无法与eureka服务交换心跳,但是服务本身是可用的】)
    enable-self-preservation: false
    #设置接收客户端心跳时间间隔(单位毫秒,默认是90秒)
    eviction-interval-timer-in-ms: 2000

两个Eureka Server配置,defaultZone配置另一个Eureka服务(相互注册),如果有多个集群环境搭建,通过逗号分隔。

  • 分别启动Eureka Server 7001;7002两个服务
    在这里插入图片描述
    在这里插入图片描述
    可以看到Eureka Server两台服务实现集群服务,相互注册,相互守望。。。

Eureka Client 客户端搭建

  • 微服务Provoder配置连接Eureka集群服务
#定义的项目名称,同时也是在eureka中注册的服务名称,相同的服务使用同一个名称
spring:
  application:
    name: cloud-payment-service
    
#定义boot的项目名称,同时也是在eureka中注册的服务名称,相同的服务使用同一个名称
eureka:
  client:
    # false 表示不向注册中心注册自己(客户端需要向服务端注册自己)
    register-with-eureka: true
    # 是否从 EurekaServer 抓取已有的注册信息,默认为 true. 单节点无所谓,集群必须设置为 true,才能配置 ribbon 使用负载均衡
    fetch-registry: true
    service-url:
      #defaultZone: http://localhost:7001/eureka/  连接单机版eureka
      # 设置与 Eureka Server 交互的地址查询服务和注册服务都需要依赖的这个地址,这里eureka集群
      defaultZone: http://localhost:7001/eureka/,http://eureka7002.com:7002/eureka/

-微服务Consumer配置连接Eureka集群服务

spring:
  application:
    name: cloud-consumer-order80

eureka:
  client:
    # false 表示不向注册中心注册自己(客户端需要向服务端注册自己)
    register-with-eureka: true
    # false 表示自己就是注册中心, 我的职责是去维护服务实例,并不需要去检索服务
    fetch-registry: true
    service-url:
      #defaultZone: http://localhost:7001/eureka/  连接单机版eureka
      # 设置与 Eureka Server 交互的地址查询服务和注册服务都需要依赖的这个地址,这里连接的是eureka集群
      defaultZone: http://localhost:7001/eureka/,http://eureka7002.com:7002/eureka/
  • 分别启动Eureka服务集群,微服务Customer和Provider
    在这里插入图片描述

  • 服务接口调用测试
    使用RestTemplate进行服务接口调用,使用@LoadBalanced实现负载均衡(默认是轮询)

/**
 * @author 张江丰
 * @version 20:34
 * RestTemplate提供了多种便捷访问远程Http服务的方法,是一种简单便捷的访问restful服务的模板类,是spring提供的用于访问Rest服务的客户端模板工具集。
 */

@Configuration
public class ApplicationContextConfig {

  @Bean
  @LoadBalanced //开启RestTemplate的负载均衡,Ribbon轮训“顺序”调用集群服务
  public RestTemplate getRestTemplate() {
    return new RestTemplate();
  }

}

微服务消费者通过接口调用服务提供者,调用地址为注册到Eureka的服务名

@RestController
@Slf4j
public class OrderController {

  //写死IP地址,相当于是通过restTemplate直连指定服务
//  private final static String PAYMENT_URL = "http://localhost:8001";

  //配置eureka服务名称,通过服务名在euraka集群服务列表获取服务
  //必须配置负载均衡(RestTemplate),否则在服务名称下存在多个服务实体,否则无法确定到服务提供者
  private final static String PAYMENT_URL = "http://CLOUD-PAYMENT-SERVICE";

  @Autowired
  private RestTemplate restTemplate;

  @GetMapping("/consumer/payment/get/{id}")
  public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id) {
    return restTemplate.getForObject(PAYMENT_URL + "/payment/get/" + id, CommonResult.class, id);
  }

实现负载均衡,服务提供者8001与8002端口交替出现
在这里插入图片描述

微服务信息完善

-显示微服务名称与IP地址

#定义boot的项目名称,同时也是在eureka中注册的服务名称,相同的服务使用同一个名称
eureka:
  client:
    # false 表示不向注册中心注册自己(客户端需要向服务端注册自己)
    register-with-eureka: true
    # 是否从 EurekaServer 抓取已有的注册信息,默认为 true. 单节点无所谓,集群必须设置为 true,才能配置 ribbon 使用负载均衡
    fetch-registry: true
    service-url:
      #defaultZone: http://localhost:7001/eureka/  连接单机版eureka
      # 设置与 Eureka Server 交互的地址查询服务和注册服务都需要依赖的这个地址,这里eureka集群
      defaultZone: http://localhost:7001/eureka/,http://eureka7002.com:7002/eureka/

  instance:
      #配置Eureka显示主机名
      instance-id: payment8001
      #显示主机IP地址
      prefer-ip-address: true

在这里插入图片描述
-服务发现DiscoveryClient
在微服务提供者8001启动类,加上注解@EnableDiscoveryClient

/**
 * EnableEurekaClient 配置并声明这是Eureka客户端
 * EnableDiscoveryClient 配置客户端服务发现DiscoveryClient
 */
@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
public class PanymentMain8001 {

  public static void main(String[] args) {
    SpringApplication.run(PanymentMain8001.class, args);
  }

}

引入DiscoveryClient对象,主要有两个方法getServices()获取微服务实例名集合;getInstances(服务实例名)获取服务实例的信息

  //引入服务发现客户端DiscoveryClient,获取服务信息;启动类需要配置开启DiscoveryClient
  @Resource
  private DiscoveryClient discoveryClient;
 
 @GetMapping("/getDiscoveryClient")
  public Object getDiscoveryClient(){
    //获取服务名称
    List<String> elements = discoveryClient.getServices();
    for (String element : elements) {
      log.info("*****element:"+element);
    }
    //获取指定服务名称的信息
    List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
    for (ServiceInstance instanceInfo : instances) {
      log.info("获取CLOUD-PAYMENT-SERVICE服务的信息:"+instanceInfo.getHost()+"\t"+instanceInfo.getPort()+"\t"+instanceInfo.getUri());
    }
    return discoveryClient;
  }

-调用信息显示

2020-08-13 16:21:39.117  INFO 2132 --- [nio-8001-exec-1] c.z.s.c.controller.PaymentController     : *****element:cloud-payment-service
2020-08-13 16:21:39.117  INFO 2132 --- [nio-8001-exec-1] c.z.s.c.controller.PaymentController     : *****element:cloud-consumer-order80
2020-08-13 16:21:39.119  INFO 2132 --- [nio-8001-exec-1] c.z.s.c.controller.PaymentController     : 获取CLOUD-PAYMENT-SERVICE服务的信息:172.23.200.33	8002	http://172.23.200.33:8002
2020-08-13 16:21:39.120  INFO 2132 --- [nio-8001-exec-1] c.z.s.c.controller.PaymentController     : 获取CLOUD-PAYMENT-SERVICE服务的信息:172.23.200.33	8001	http://172.23.200.33:8001

Eureka自我保护机制

默认情况下,如果EurekaServer在一定时间内没有接受到某个注册微服务实例的心跳,EurekaServer将会注销该实例(默认90秒),但是当网路故障发生(延迟,卡顿…),EurekaServer与微服务之间无法正常通行,那么直接注销微服务实例就不那么合适了,因为微服务实例本身是健康的,当网络故障修复后还能继续提供服务。Eureka通过“自我保护机制”来解决这个问题,当微服务节点在短时间内丢失过多客户端时(可能发生网络故障),那么这个节点就会进入自我保护机制,EurekaServer不会删除该微服务注册实例信息。
在这里插入图片描述
Eureka由此可见属于分布式微服务的AP分支,即保证了分布式微服务的可用性与分区容错性,无法保证微服务的一致性。

-关闭EurekaServer自我保护机制
EurekaServer服务配置

#集群配置
eureka:
  instance:
    # eureka 服务端的实例名称(在hosts文件中定义映射)
    hostname: eureka7001.com
  client:
    # false 表示不向注册中心注册自己(服务端不用自己注册自己)
    register-with-eureka: false
    # false 表示自己就是注册中心, 我的职责是去维护服务实例,并不需要去检索服务
    fetch-registry: false
    service-url:
      # 设置与 Eureka Server 交互的地址查询服务和注册服务都需要依赖的这个地址,集群设置7002,相互注册
      #如果是多个集群,通过,号分割;例如:defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
      defaultZone: http://eureka7002.com:7002/eureka/
  server:
      #关闭eureka自我保护机制(服务不可用(心跳交互超时)删除服务),默认是开启(开启状态,eureka不会立即剔除失效的服务信息【可能存在网络抖动等因素无法与eureka服务交换心跳,但是服务本身是可用的】)
    enable-self-preservation: false
      #设置接收客户端心跳时间间隔(单位毫秒,默认是90秒),
    eviction-interval-timer-in-ms: 2000

EurekaClient微服务实例配置,以8001服务提供者为例

#定义boot的项目名称,同时也是在eureka中注册的服务名称,相同的服务使用同一个名称
eureka:
  client:
    # false 表示不向注册中心注册自己(客户端需要向服务端注册自己)
    register-with-eureka: true
    # 是否从 EurekaServer 抓取已有的注册信息,默认为 true. 单节点无所谓,集群必须设置为 true,才能配置 ribbon 使用负载均衡
    fetch-registry: true
    service-url:
      #defaultZone: http://localhost:7001/eureka/  连接单机版eureka
      # 设置与 Eureka Server 交互的地址查询服务和注册服务都需要依赖的这个地址,这里eureka集群
      defaultZone: http://localhost:7001/eureka/,http://eureka7002.com:7002/eureka/

  instance:
      #配置Eureka显示主机名
      instance-id: payment8001
      #显示主机IP地址
      prefer-ip-address: true
      #指定Eureka客户端向服务端发送心跳时间,单位秒默认是(30秒)
      lease-expiration-duration-in-seconds: 1
      #指定Eureka服务端在最后一次接收到心跳后等待时间,两次心跳等待时间单位秒(默认90秒),剔除服务
      lease-renewal-interval-in-seconds: 2

关闭自我保护机制,EurekaServer启动效果
在这里插入图片描述
当停止8001微服务实例后,EurekaServer会立即删除该微服务
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_41714882/article/details/106751061