Springcloud基础知识(3)- Spring Cloud Eureka (二) | Eureka Server 集群



在微服务架构中,一个系统往往由十几甚至几十个服务组成,若将这些服务全部注册到同一个 Eureka Server 中,就极有可能导致 Eureka Server 因不堪重负而崩溃,最终导致整个系统瘫痪。解决这个问题最直接的办法就是部署 Eureka Server 集群。

在 Eureka 实现服务注册与发现时一共涉及了 3 个角色:服务注册中心、服务提供者以及服务消费者,这三个角色分工明确,各司其职。但是其实在 Eureka 中,所有服务都既是服务消费者也是服务提供者,服务注册中心 Eureka Server 也不例外。

在搭建服务注册中心时,在 application.yml 中涉及了这样的配置:

    eureka:
        client:
            register-with-eureka: false  # false 表示不向注册中心注册自己。
            fetch-registry: false  # false 表示自己端就是注册中心,职责就是维护服务实例,并不需要去检索服务

这样设置的原因是 RegisterServer 本身自己就是服务注册中心,服务注册中心是不能将自己注册到自己身上的,但服务注册中心是可以将自己作为服务向其他的服务注册中心注册自己的。

举个例子,有两个 Eureka Server 分别为 A 和 B,虽然 A 不能将自己注册到 A 上,B 也不能将自己注册到 B 上,但 A 是可以作为一个服务把自己注册到 B 上的,同理 B 也可以将自己注册到 A 上。

这样就可以形成一组互相注册的 Eureka Server 集群,当服务提供者发送注册请求到 Eureka Server 时,Eureka Server 会将请求转发给集群中所有与之相连的 Eureka Server 上,以实现 Eureka Server 之间的服务同步。

通过服务同步,服务消费者可以在集群中的任意一台 Eureka Server 上获取服务提供者提供的服务。这样,即使集群中的某个服务注册中心发生故障,服务消费者仍然可以从集群中的其他 Eureka Server 中获取服务信息并调用,而不会导致系统的整体瘫痪,这就是 Eureka Server 集群的高可用性。


1. 搭建 Eureka Server 集群


    在 “” 里 SpringcloudDemo02 项目实现了单机版的服务注册中心和服务提供者的服务注册与发现功能。

    RegisterServer 模块(服务注册中心)和 ServiceProvider 模块(服务提供者)也都实现了 Spring Boot 独立运行打包。

    本文将使用 SpringcloudDemo02 生成的 *.jar 和 *.yml 文件,在 Windows 10 下构建一个拥有 3 个独立 Register Server(服务注册中心)的 Eureka Server 集群。


    1) 目录结构

        创建 C:\Applications\Java\eureka 目录,该目录下放置三个子目录和相关文件:

 1             eureka
 2               |- server-7001
 3               |    |- RegisterServer-1.0-SNAPSHOT.jar
 4               |    |- application.yml
 5               |    |- start.bat
 6               |
 7               |- server-7002
 8               |    |- RegisterServer-1.0-SNAPSHOT.jar
 9               |    |- application.yml
10               |    |- start.bat
11               |
12               |- server-7003
13               |    |- RegisterServer-1.0-SNAPSHOT.jar
14               |    |- application.yml
15               |    |- start.bat
16               |
17               |- service-8001
18                    |- ServiceProvider-1.0-SNAPSHOT.jar  
19                    |- application.yml
20                    |- start.bat 


        注:*.jar 是 spring-boot-maven-plugin 插件打包的可独立运行包,application.yml 是模块的 src/main/resource/ 目录下的文件。


    2) 配置 server-7001

        (1) 修改 application.yml 文件,内容如下

 1             server:
 2                 port: 7001  # 端口号
 3             eureka:
 4                 instance:
 5                     hostname: eureka7001.com # eureka 服务端的实例名称
 6                 client:
 7                     register-with-eureka: false # false 表示不向注册中心注册自己。
 8                     #fetch-registry: false # false 表示就是注册中心,不需要去检索服务
 9                     service-url:
10                         # defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ # 单机版服务注册中心
11                         defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/ # 集群版   


        (2) 创建 start.bat 文件,内容如下

            java -jar RegisterServer-1.0-SNAPSHOT.jar application.yml


    3) 配置 server-7002

        (1) 修改 application.yml 文件,内容如下

 1             server:
 2                 port: 7002  # 端口号
 3             eureka:
 4                 instance:
 5                     hostname: eureka7001.com # eureka 服务端的实例名称
 6                 client:
 7                     register-with-eureka: false # false 表示不向注册中心注册自己。
 8                     #fetch-registry: false # false 表示就是注册中心,不需要去检索服务
 9                     service-url:
10                         # defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ # 单机版服务注册中心
11                         defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7003.com:7003/eureka/ # 集群版   


        (2) 创建 start.bat 文件,内容如下

            java -jar RegisterServer-1.0-SNAPSHOT.jar application.yml


    4) 配置 server-7003

        (1) 修改 application.yml 文件,内容如下

 1             server:
 2                 port: 7003  # 端口号
 3             eureka:
 4                 instance:
 5                     hostname: eureka7001.com # eureka 服务端的实例名称
 6                 client:
 7                     register-with-eureka: false # false 表示不向注册中心注册自己。
 8                     #fetch-registry: false # false 表示就是注册中心,不需要去检索服务
 9                     service-url:
10                         # defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ # 单机版服务注册中心
11                         defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/ # 集群版   


        (2) 创建 start.bat 文件,内容如下

            java -jar RegisterServer-1.0-SNAPSHOT.jar application.yml


    5) 配置 service-8001

        (1) 修改 application.yml 文件,内容如下

 1             server:
 2                 port: 8001      # 服务端口号
 3             spring:
 4                 application:
 5                     name: employee-service-provider   # 微服务名称
 6 
 7             #### Eureka Client ####
 8             eureka:
 9                 client:       # 将客户端注册到 eureka 服务列表内
10                     service-url:
11                         #defaultZone: http://localhost:7001/eureka  # 服务注册中心地址
12                         defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/   # 服务注册中心地址
13 
14                 instance:
15                     instance-id: sevice-provider-8001   # 自定义服务名称信息
16                     prefer-ip-address: true             # 显示访问路径的 ip 地址
17 

        (2) 创建 start.bat 文件,内容如下

            java -jar ServiceProvider-1.0-SNAPSHOT.jar application.yml


    6) 配置本地 DNS 解析

        上文使用的 eureka7001.com、eureka7002.com 和 eureka7003.com 都是本地虚拟域名,使用它们是为了识别 3 个独立 Register Server(服务注册中心),如果有外网 IP 地址的可以使用真实域名。

        使用本地虚拟域名需要修改本地的 host 文件,Windows 10 在 C:/Windows/System32/drivers/etc/hosts 中修改,Mac/linux 系统在 /etc/hosts 中修改,修改内容如下。

            # Spring Cloud Eureka Server 集群
            127.0.0.1 eureka7001.com
            127.0.0.1 eureka7002.com
            127.0.0.1 eureka7003.com


    7) 运行

        (1) 启动 server-7001

            鼠标双击 start.bat 文件,跳出 cmd 窗口:

                C:\Applications\Java\eureka\server-7001>java -jar RegisterServer-1.0-SNAPSHOT.jar application.yml  

                    ...

            浏览器访问 http://eureka7001.com:7001/,页面上 “DS Replicas” 区域显示:

                DS Replicas

                    eureka7003.com
                    eureka7002.com

        (2) 启动 server-7002

            鼠标双击 start.bat 文件,跳出 cmd 窗口:

                C:\Applications\Java\eureka\server-7002>java -jar RegisterServer-1.0-SNAPSHOT.jar application.yml  

                    ...

            浏览器访问 http://eureka7002.com:7002/,页面上 “DS Replicas” 区域显示:

                DS Replicas

                    eureka7003.com
                    eureka7001.com

        (3) 启动 server-7003

            鼠标双击 start.bat 文件,跳出 cmd 窗口:

                C:\Applications\Java\eureka\server-7003>java -jar RegisterServer-1.0-SNAPSHOT.jar application.yml  

                    ...

            浏览器访问 http://eureka7003.com:7003/,页面上 “DS Replicas” 区域显示:

                DS Replicas

                    eureka7001.com
                    eureka7002.com

        (4) 启动 service-8001

            鼠标双击 start.bat 文件,跳出 cmd 窗口:

                C:\Applications\Java\eureka\service-8001>java -jar ServiceProvider-1.0-SNAPSHOT.jar application.yml

                    ...

            浏览器访问 http://eureka7001.com:7001/,页面上 “Instances currently registered with Eureka” 区域显示:

                Instances currently registered with Eureka

                Application                    AMIs       Availability Zones    Status
                EMPLOYEE-SERVICE-PROVIDER    n/a (1)         (1)                     UP (1) - sevice-provider-8001

            浏览器访问 http://eureka7002.com:7002/ 和 http://eureka7003.com:7003/ 也可以看到以上显示的内容,表明 3 个注册中心都收到了注册服务。

            Eureka Server 集群的搭建成功。


2. Eureka 自我保护机制

    当我们在本地调试 Eureka Server 时,Eureka 服务注册中心页面可能会出现如下图所示的红色警告。

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

    这个警告是触发了 Eureka 的自我保护机制而出现的。默认情况下,如果 Eureka Server 在一段时间内(默认为 90 秒)没有接收到某个服务提供者(Eureka Client)的心跳,就会将这个服务提供者提供的服务从服务注册表中移除。 这样服务消费者就再也无法从服务注册中心中获取到这个服务了,更无法调用该服务。

    但在实际的分布式微服务系统中,健康的服务(Eureka Client)也有可能会由于网络故障(例如网络延迟、卡顿、拥挤等原因)而无法与 Eureka Server 正常通讯。若此时 Eureka Server 因为没有接收心跳而误将健康的服务从服务列表中移除,这显然是不合理的。而 Eureka 的自我保护机制就是来解决此问题的。

    所谓 “Eureka 的自我保护机制”,其中心思想就是 “好死不如赖活着”。如果 Eureka Server 在一段时间内没有接收到 Eureka Client 的心跳,那么 Eureka Server 就会开启自我保护模式,将所有的 Eureka Client 的注册信息保护起来,而不是直接从服务注册表中移除。一旦网络恢复,这些 Eureka Client 提供的服务还可以继续被服务消费者消费。

    综上,Eureka 的自我保护机制是一种应对网络异常的安全保护措施。它的架构哲学是:宁可同时保留所有微服务(健康的服务和不健康的服务都会保留)也不盲目移除任何健康的服务。通过 Eureka 的自我保护机制,可以让 Eureka Server 集群更加的健壮、稳定。

    Eureka 的自我保护机制也存在弊端。如果在 Eureka 自我保护机制触发期间,服务提供者提供的服务出现问题,那么服务消费者就很容易获取到已经不存在的服务进而出现调用失败的情况,此时,我们可以通过客户端的容错机制来解决此问题,详情请参考 Spring Cloud Netflix Ribbon 和 Spring Cloud Netflix Hystrix。

    Eureka 的自我保护机制是开启的,如果想要关闭,则需要在配置文件中添加以下配置。

        eureka:
            server:
                enable-self-preservation: false # false 关闭 Eureka 的自我保护机制,默认是开启

    示例,我们将关闭 server-7001 的自我保护机制。

    1) 修改 server-7001 的 appplication.yml,内容如下

 1         server:
 2             port: 7001  # 端口号
 3         eureka:
 4             server:
 5                 enable-self-preservation: false # false 关闭 Eureka 的自我保护机制,默认是开启
 6             instance:
 7                 hostname: eureka7001.com # eureka 服务端的实例名称
 8             client:
 9                 register-with-eureka: false # false 表示不向注册中心注册自己。
10                 #fetch-registry: false # false 表示就是注册中心,不需要去检索服务
11                 service-url:
12                     # defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ # 单机版服务注册中心
13                     defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/ # 集群版


    2) 重启 server-7001

        浏览器访问 http://eureka7001.com:7001/,页面上 “DS Replicas” 区域上方显示:   

            THE SELF PRESERVATION MODE IS TURNED OFF. THIS MAY NOT PROTECT INSTANCE EXPIRY IN CASE OF NETWORK/OTHER PROBLEMS.

        出现该信息则表示 Eureka 自我保护模式已关闭。

        关闭 service-8001,等待 3 ~ 5 分钟,再次访问 http://eureka7001.com:7001/,页面上 “DS Replicas” 区域上方显示:

            RENEWALS ARE LESSER THAN THE THRESHOLD. THE SELF PRESERVATION MODE IS TURNED OFF. THIS MAY NOT PROTECT INSTANCE EXPIRY IN CASE OF NETWORK/OTHER PROBLEMS.

        出现该信息则表示 Eureka 自我保护模式已关闭,页面上 “Instances currently registered with Eureka” 区域的服务 EMPLOYEE-SERVICE-PROVIDER 被移除。