自学内容网 自学内容网

SpringCloud系列之一---搭建高可用的Eureka注册中心

前言

本篇文章主要介绍的是SpringCloud相关知识、微服务架构以及搭建服务注册与发现的服务模块(Eureka)以及Eureka集群。

GitHub源码链接位于文章底部。

什么是SpringCloud

Spring Cloud 是一系列框架的有序集合。 它利用 Spring Boot 的开发便利性巧妙地简化了分布式系统基础设施的开发, 如服务发现注册、配置中心、消息总线、负载均衡、熔断器、数据监控等,都可以用 Spring Boot 的开发风格做到一键启动和部署。Spring 并没有复制造轮子,它只是将目前各家公司开发的比较成熟、经得起实际考验的服务框架组合起来,通过 SpringBoot 风格进行再封装屏蔽掉了复杂的配置和实现原理,最终开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具包。

SpringCloud 与 SpringBoot 的关系

Spring Boot是Spring的一套快速配置脚手架,可以基于Spring Boot快速开发单个微服务,Spring Cloud是一个基于Spring Boot实现的云应用开发工具;Spring Boot专注于快速、方便集成的单个微服务个体,Spring Cloud关注全局的服务治理框架;Spring Boot 使用了默认大于配置的理念,很多集成方案已经帮你选择好了,能不配置就不配置,Spring Cloud很大的一部分是基于Spring Boot来实现,可以不基于Spring Boot吗?不可以。
Spring Boot可以离开Spring Cloud独立使用开发项目, 但是Spring Cloud离不开Spring Boot,属于依赖的关系。

SpringCloud 主要组件
用途组件
服务发现Netflix Eureka
服务调用Netflix Feign
熔断器Netflix Hystrix
服务网关Netflix Zuul
分布式配置Spring Cloud Config
消息总线Spring Cloud Bus
SpringCloud 与 Dubbo 对比

dubbo由于是二进制的传输,占用带宽会更少。
springCloud是http协议传输,带宽会比较多,同时使用http协议一般会使用JSON报文,消耗会更大。
dubbo的开发难度较大,原因是dubbo的jar包依赖问题很多大型工程无法解决。
Dubbo只是实现了服务治理,而Spring Cloud下面有很多个子项目分别覆盖了微服务架构下的方方面面,服务治理只是其中的一个方面,一定程度来说,Dubbo 只是 Spring CloudNetflix 中的一个子集。

DubboSpringCloud
服务注册中心ZookeeperSpring Cloud Netflix Eureka
服务调用方式RPCREST API
服务网关Spring Cloud Netflix Zuul /Spring Cloud GateWay
熔断器不完善Spring Cloud Netflix Hystrix
分布式配置Spring Cloud Config
服务跟踪Spring Cloud Sleuth
消息总线Spring Cloud Bus
数据流Spring Cloud Stream
批量任务Spring Cloud Task
..................
SpringCloud 的版本

SpringCloud 由于是一系列框架组合,为了避免与包含的自框架版本产生混淆,采用伦敦地铁站的名称作为版本名,形式为版本名+里程碑号。M9为第 9 个里程碑版本。以下是SpringBoot与Spring Cloud版本的对照表。

Spring BootSpring Cloud
1.2.xAngel 版本
1.3.xBrixton 版本
1.4.xCamden 版本
1.5.xDalston 版本、 Edgware 版本
2.0.xFinchley 版本
服务发现组件 Eureka

Eureka是Netflix 开发的服务发现框架,SpringCloud将它集成在自己的子项目spring-cloud-netflix中,实现SpringCloud的服务发现功能。Eureka包含两个组件:Eureka Server和Eureka Client。

Eureka Server提供服务注册服务,各个节点启动后,会在Eureka Server中进行注册,这样EurekaServer中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观的看到。

自我保护机制

Eureka Client是一个java客户端,用于简化与Eureka Server的交互,客户端同时也就别一个内置的、使用轮询(round-robin)负载算法的负载均衡器。在应用启动后,将会向EurekaServer发送心跳,默认周期为30秒,如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳,Eureka Server将会从服务注册表中把这个服务节点移除(默认90秒)。但是在短时间内丢失大量的实例心跳,这时候EurekaServer会开启自我保护机制,Eureka不会踢出该服务,这就是Eureka的自我保护机制。
产生原因:在开发测试时,需要频繁地重启微服务实例,但是我们很少会把eureka server一起重启(因为在开发过程中不会修改eureka注册中心),当一分钟内收到的心跳数大量减少时,会触发该保护机制。可以在eureka管理界面看到Renews threshold和Renews(last min),当后者(最后一分钟收到的心跳数)小于前者(心跳阈值)的时候,触发保护机制,会出现红色的警告:

EMERGENCY!EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY'RE NOT.RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEGING EXPIRED JUST TO BE SAFE.

从警告中可以看到,eureka认为虽然收不到实例的心跳,但它认为实例还是健康的,eureka会保护这些实例,不会把它们从注册表中删掉。

该保护机制的目的是避免网络连接故障,在发生网络故障时,微服务和注册中心之间无法正常通信,但服务本身是健康的,不应该注销该服务,如果eureka因网络故障而把微服务误删了,那即使网络恢复了,该微服务也不会重新注册到eureka server了,因为只有在微服务启动的时候才会发起注册请求,后面只会发送心跳和服务列表请求,这样的话,该实例虽然是运行着,但永远不会被其它服务所感知。所以,eureka server在短时间内丢失过多的客户端心跳时,会进入自我保护模式,该模式下,eureka会保护注册表中的信息,不在注销任何微服务,当网络故障恢复后,eureka会自动退出保护模式。自我保护模式可以让集群更加健壮。

但是我们在开发测试阶段,需要频繁地重启发布,如果触发了保护机制,则旧的服务实例没有被删除,这时请求有可能跑到旧的实例中,而该实例已经关闭了,这就导致请求错误,影响开发测试。所以,在开发测试阶段,我们可以把自我保护模式关闭,只需在eureka server配置文件中加上如下配置即可:

#eureka基本配置信息
eureka:
  client:
    service-url:
      #Eureka 客户端与 Eureka 服务端进行交互的地址
      defaultZone: http://127.0.0.1:${server.port}/eureka
    #是否将自己注册到Eureka服务中,本身就是注册中心所以无需注册
    register-with-eureka: false
    #是否从Eureka中检索注册信息,本身就是注册中心所以无需检索
    fetch-registry: false
  server:
    # 测试时关闭自我保护机制,保证不可用服务及时踢出
    enable-self-preservation: false
    ##剔除失效服务间隔
    eviction-interval-timer-in-ms: 2000

在eureka client配置文件中加上:

#eureka基本配置信息
eureka:
  client:
    service-url:
      #Eureka 客户端与 Eureka 服务端进行交互的地址
      defaultZone: http://127.0.0.1:8100/eureka/
  # 心跳检测检测与续约时间
  # 测试时将值设置设置小些,保证服务关闭后注册中心能及时踢出服务
  instance:
    # Eureka客户端向服务端发送心跳的时间间隔,单位为秒(客户端告诉服务端自己会按照该规则)
    lease-renewal-interval-in-seconds: 1
    # Eureka服务端在收到最后一次心跳之后等待的时间上限,单位为秒,超过则剔除(客户端告诉服务端按照此规则等待自己)
    lease-expiration-duration-in-seconds: 2

但在生产环境,不会频繁重启,所以,一定要把自我保护机制打开,否则网络一旦中断,就无法恢复。
当然关于自我保护还有很多个性化配置,这里不详细说明。

注意考虑网络不可达情况下:调用接口幂等、重试、补偿等。

创建工程
1. 目前工程结构
image
2. 首先创建父工程springcloud,以后这个工程下存放子工程eureka,feign,zuul等组件

将该工程的src文件夹删除,在pom文件中添加依赖

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.1.RELEASE</version>
        <relativePath ></relativePath>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    
    <!--引用仓库-->
    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>

    <!--管理依赖,子项目中的依赖不用列出版本号-->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Finchley.M9</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
创建eureka父工程

新建springcloud-eureka项目,在pom文件中添加依赖

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
    </dependencies>
创建eureka服务端

以springcloud-eureka为父工程,新建springboot-eureka-server项目,这里不需要添加eureka-server依赖,因为父工程中有了。

1. 添加配置

在resources目录中添加application.yml文件,在文件中添加配置

#服务端口号
server:
  port: 8100

spring:
  application:
    name: eureka-server
    
#eureka基本配置信息
eureka:
  client:
    service-url:
      #Eureka 客户端与 Eureka 服务端进行交互的地址
      defaultZone: http://127.0.0.1:${server.port}/eureka
    #是否将自己注册到Eureka服务中,本身就是注册中心所以无需注册
    register-with-eureka: false
    #是否从Eureka中检索注册信息,本身就是注册中心所以无需检索
    fetch-registry: false
  server:
    # 测试时关闭自我保护机制,保证不可用服务及时踢出
    enable-self-preservation: false
    ##剔除失效服务间隔
    eviction-interval-timer-in-ms: 2000

2. 启动类

java目录下创建com.lxg二级目录,然后创建EurekaServerApp启动类

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

在类上加EnableEurekaServer注解,启动EurekaServer。

创建eureka客户端

以springcloud-eureka为父工程,新建springboot-eureka-client项目。在pom文件中添加依赖:

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
    </dependencies>
1. 添加配置

在resources目录中添加application.yml文件,在文件中添加配置

#端口号
server:
  port: 9100

spring:
  application:
    name: eureka-client

#eureka基本配置信息
eureka:
  client:
    service-url:
      #Eureka 客户端与 Eureka 服务端进行交互的地址
      defaultZone: http://127.0.0.1:8100/eureka/
  # 心跳检测检测与续约时间
  # 测试时将值设置设置小些,保证服务关闭后注册中心能及时踢出服务
  instance:
    # Eureka客户端向服务端发送心跳的时间间隔,单位为秒(客户端告诉服务端自己会按照该规则)
    lease-renewal-interval-in-seconds: 1
    # Eureka服务端在收到最后一次心跳之后等待的时间上限,单位为秒,超过则剔除(客户端告诉服务端按照此规则等待自己)
    lease-expiration-duration-in-seconds: 2
2. 启动类

java目录下创建com.lxg二级目录,然后创建EurekaClientApp启动类,这里启动类名称不能为EurekaClient,否则会起冲突导致启动失败。类上使用EnableEurekaClient注解。

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

先启动服务端,再启动客户端,访问127.0.0.1:8100 ,访问监控页面。


image

图中的红色字体是在提示已经关闭了eureka的自我保护机制,此时如果关闭客户端,页面中的服务就会被踢出,如果没有关闭的话,即使客户端关闭了,服务依然会存在。

高可用注册中心(Eureka集群)

在微服务中,注册中心非常核心,可以实现服务治理,如果一旦注册出现故障的时候,可能会导致整个微服务无法访问,在这时候就需要对注册中心实现高可用集群模式。

Eureka高可用原理

默认情况下Eureka是让服务注册中心,不注册自己,但是在集群中,需要设置能注册自己,因为这两个属性默认为true,只需要不写就行了。

###使该注册中心注册自己
    register-with-eureka: true
###需要去注册中心上检索服务
    fetch-registry: true

Eureka高可用实际上将自己作为服务向其他服务注册中心注册自己,这样就可以形成一组相互注册的服务注册中心,从而实现服务清单的互相同步,达到高可用效果。

Eureka集群环境搭建

新增server1,server2,server3三个节点。


image

server1配置:

#服务端口号
server:
  port: 8100

spring:
  application:
    name: eureka-server

#eureka基本配置信息
eureka:
  client:
    service-url:
      #Eureka 客户端与 Eureka 服务端进行交互的地址
      defaultZone: http://127.0.0.1:8200/eureka,http://127.0.0.1:8300/eureka
  server:
    # 测试时关闭自我保护机制,保证不可用服务及时踢出
    enable-self-preservation: false
    ##剔除失效服务间隔
    eviction-interval-timer-in-ms: 2000

server2配置:

#服务端口号
server:
  port: 8200

spring:
  application:
    name: eureka-server

#eureka基本配置信息
eureka:
  client:
    service-url:
      #Eureka 客户端与 Eureka 服务端进行交互的地址
      defaultZone: http://127.0.0.1:8100/eureka,http://127.0.0.1:8300/eureka
  server:
    # 测试时关闭自我保护机制,保证不可用服务及时踢出
    enable-self-preservation: false
    ##剔除失效服务间隔
    eviction-interval-timer-in-ms: 2000

server3配置:

#服务端口号
server:
  port: 8300

spring:
  application:
    name: eureka-server

#eureka基本配置信息
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:8100/eureka,http://127.0.0.1:8200/eureka
  server:
    # 测试时关闭自我保护机制,保证不可用服务及时踢出
    enable-self-preservation: false
    ##剔除失效服务间隔
    eviction-interval-timer-in-ms: 2000

然后修改客户端的配置,因为以前是单个eureka注册中心,只需要注册进一个地址就行了,现在要注册进所有的注册中心。

#端口号
server:
  port: 9100

spring:
  application:
    name: eureka-client

#eureka基本配置信息
eureka:
  client:
    service-url:
      #Eureka 客户端与 Eureka 服务端进行交互的地址
      #单机
      #defaultZone: http://127.0.0.1:8100/eureka/
      #集群
      defaultZone: http://127.0.0.1:8100/eureka/,http://127.0.0.1:8200/eureka/,http://127.0.0.1:8300/eureka/
  # 心跳检测检测与续约时间
  # 测试时将值设置设置小些,保证服务关闭后注册中心能及时踢出服务
  instance:
    # Eureka客户端向服务端发送心跳的时间间隔,单位为秒(客户端告诉服务端自己会按照该规则)
    lease-renewal-interval-in-seconds: 1
    # Eureka服务端在收到最后一次心跳之后等待的时间上限,单位为秒,超过则剔除(客户端告诉服务端按照此规则等待自己)
    lease-expiration-duration-in-seconds: 2

先启动所有的服务端节点,再启动客户端。访问localhost:8100 ,localhost:8200 ,localhost:8300 都能进入eureka的界面,同时看到客户端服务和其他的注册中心。这个时候即使有某一个节点挂了,服务依然是可用的,而且性能肯定比单机版要好。

搭建eureka集群有几点需要注意的:

1.与先前独立运行注册不同,注意defaultZone属性,它的值为除了自己以外的所有eureka节点的地址,以英文逗号分割。
2.去掉fetch-registry 与 register-with-eureka配置(其实这样做就会取对应的默认值,两个值均为true),需要让自己能被注册和检索。
3.启动第一个注册中心时会报Cannot execute request on any known server的错误,暂时不管它,实际上eureka注册中心的ui界面是能打开的,当所有的节点启动完毕,就能找到服务,此错误就会消失。
4.所有注册中心的节点的spring.application.name必须保持一致。
5.当客户端需要往注册中心集群注册服务时defaultZone属性需要把所有节点地址都加上,如果像单节点一样的话,你连接的那个节点挂了,集群中其他节点就无法获取到该服务,也就不能达到高可用。

本文GitHub源码:https://github.com/lixianguo5097/springcloud/tree/master/springcloud-eureka

CSDN:https://blog.csdn.net/qq_27682773
简书:https://www.jianshu.com/u/e99381e6886e
博客园:https://www.cnblogs.com/lixianguo

最后编辑于:2024-09-18 20:52:00


喜欢的朋友记得点赞、收藏、关注哦!!!


原文地址:https://blog.csdn.net/pingguocu3/article/details/142367580

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!