美文网首页
Spring Cloud服务治理之Eureka

Spring Cloud服务治理之Eureka

作者: 巨子联盟 | 来源:发表于2017-12-03 22:19 被阅读0次

    什么是服务治理

    主要是用来实现各个微服务实例的自动化注册与发现,解决随着微服务的增加,静态配置变得越来越难以维护的问题.

    服务注册

    1. 维护注册

    维护一个类似下面的清单


    image.png
    2. 服务发现

    向注册中心发起咨询服务请求,以获取某个服务可用的位置清单 ,再以客户端负载均衡的方式调用.

    搭建服务注册中心

    1. 添加POM依赖
    
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>1.3.7.RELEASE</version>
            <relativePath/>
        </parent>
    
        <properties>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <java.version>1.8</java.version>
        </properties>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-eureka-server</artifactId>
            </dependency>
    
            <!--<dependency>-->
                <!--<groupId>org.springframework.boot</groupId>-->
                <!--<artifactId>spring-boot-starter-actuator</artifactId>-->
            <!--</dependency>-->
        </dependencies>
    
        <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-dependencies</artifactId>
                    <version>Brixton.SR5</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
            </dependencies>
        </dependencyManagement>
        
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    
    1. 通过 @EnableEurekaServer 启动一个服务注册中心
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.boot.builder.SpringApplicationBuilder;
    import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
    
    @EnableEurekaServer
    @SpringBootApplication
    public class Application {
    
        public static void main(String[] args) {
            new SpringApplicationBuilder(Application.class).web(true).run(args);
        }
    
    }
    
    1. 配置几个配置,如,禁用客户端注册行为
    eureka.instance.hostname=localhost
    
    # 关闭保护机制
    #eureka.server.enable-self-preservation=false
    # false代表不向注册中心注册自己
    eureka.client.register-with-eureka=false
    #false代表不需要去检索服务,因为自己就是维护服务
    eureka.client.fetch-registry=false
    eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka/
    
    
    启动看一下界面
    image.png

    注册服务提供者

    1. 修改pom文件
    
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>1.3.7.RELEASE</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
    
        <properties>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
            <java.version>1.8</java.version>
        </properties>
    
        <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>
    
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-eureka</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-hystrix</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-actuator</artifactId>
            </dependency>
    
        </dependencies>
    
        <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-dependencies</artifactId>
                    <version>Brixton.SR5</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
            </dependencies>
        </dependencyManagement>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    
    1. 修改启动类,添加@EnableDiscoveryClient,激活Eureka的实现
    @EnableDiscoveryClient
    @SpringBootApplication
    public class HelloApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(HelloApplication.class, args);
        }
    
    }
    
    1. 修改配置
    #配置服务名称
    spring.application.name=hello-service
    #指定服务注册中心的位置
    eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/
    
    

    启动结果


    image.png

    搭建高可用注册中心

    原理是搭建两台注册中心,然后分别把自己作为客户端服务向对方注册,对方就把自己当成服务.

    1. 添加配置application-peer1.properties,内容如下:
    spring.application.name=eureka-server
    server.port=1111
    eureka.instance.hostname=peer1
    
    eureka.client.serviceUrl.defaultZone=http://peer2:1112/eureka/
    

    2.添加配置application-peer2.properties,内容如下:

    spring.application.name=eureka-server
    server.port=1112
    eureka.instance.hostname=peer2
    
    eureka.client.serviceUrl.defaultZone=http://peer1:1111/eureka/
    
    1. 其他的配置不变,然后我们部署两台注册中心,启动命令如下
      java -jar eureka-server-ha-1.0.0.jar --spring.profiles.active=peer1
      java -jar eureka-server-ha-1.0.0.jar --spring.profiles.active=peer2
    2. 向高可用的注册中心注册服务
      修改上面的工程配置文件如下:
    #eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/
    eureka.client.service-url.defaultZone=http://peer1:1111/eureka/,http://peer2:1112/eureka/
    
    • 查看结果
    image.png
    image.png
    我们这时访问一下刚刚的接口
    http://localhost:8082/hello1?name=zzj
    发现没有问题.
    这时再把peer2杀掉.再访问,也是没有问题的.同时在peer1的后台中可以看到如下报错:
    image.png
    peer1上也显示peer2也为不可用服务
    image.png

    peer1在不停的尝试连接peer2
    至此,我们实现了注册中心的高可用.
    我们再启动一下peer2,观察peer1的报错停止了.出现了以下的信息,

    image.png
    同时访问peer2也能访问了.
    如果不想用主机名来定义注册中心,也可以使用IP地址的形式.修改配置如下:
    eureka.instance.prefer-ip-address=true
    默认为false
    服务的发现与消费

    服务的发现是由eureka完成,消费是由Ribbon完成,Ribbon可以通过客户端配置的ribbonServerList服务端列表去轮询以达到负载均衡的效果
    ribbonServerListDiscoveryEnabledNIWSServerList重写
    NIWSDiscoveryPing取代IPing

    1. 启动之前的eureka-server以及hello-service服务,如下:
    java -jar hello-service-eureka-1.3.7.RELEASE.jar --server.port=8083
    java -jar hello-service-eureka-1.3.7.RELEASE.jar --server.port=8082
    
    image.png image.png
    创建ribbon-customer工程
    1. 添加依赖
        <name>ribbon-consumer</name>
        <description>Demo project for Spring Boot</description>
    
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>1.3.7.RELEASE</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
    
        <properties>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
            <java.version>1.8</java.version>
        </properties>
    
        <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>
    
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-eureka</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-ribbon</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-actuator</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-hystrix</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-netflix-hystrix-amqp</artifactId>
            </dependency>
        </dependencies>
    
        <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-dependencies</artifactId>
                    <version>Brixton.SR5</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
            </dependencies>
        </dependencyManagement>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    
    
    1. 添加注解@EnableDiscoveryClient以获得服务发现能力,@LoadBalanced开启客户端的负载均衡,代码如下
    @EnableCircuitBreaker
    @EnableDiscoveryClient
    @SpringBootApplication
    public class ConsumerApplication {
    
        @Bean
        @LoadBalanced
        RestTemplate restTemplate() {
            return new RestTemplate();
        }
        public static void main(String[] args) {
            SpringApplication.run(ConsumerApplication.class, args);
        }
    
    }
    

    3.创建Controller,实现/ribbon-consumer1接口
    代码如下:

        @Autowired
        RestTemplate restTemplate;
    
        @RequestMapping(value="/ribbon-consumer1",method = RequestMethod.GET)
        public String helloConsumer1() {
            return restTemplate.getForEntity("http://HELLO-SERVICE/hello", String.class).getBody();
        }
    

    地址用服务名


    image.png
    1. 修改application.properties,启动服务
    spring.application.name=ribbon-consumer
    server.port=9000
    
    eureka.client.serviceUrl.defaultZone=http://peer1:1111/eureka/,http://peer2:1112/eureka/
    
    
    image.png
    访问 http://localhost:9000/ribbon-consumer1 会发现两个服务提供者的后台会交替显示访问日志:
    image.png
    image.png

    Eureka基础架构

    image.png
    • 服务注册中心

      • 失效剔除
      • 自我保护
        Eureka Server在运行期间, 会统计心跳失败的比例在15分钟之内是否低于85%(在单机调试的时候很容易满足)

    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.server.enable-self-preservation=false默认为true
    true的意思是Eureka会将当前的实例信息保护起来,让这些实例不过期.

    客户端对于此问题必须要有容错机制,比如:请求重试,断路器等机制

    • 服务提供者

      • 服务注册,启动时注册,Eureka保存在一个双层结构的Map中
      • 服务同步
        只要向其中一台Eureka注册,另一台就会自动同步到另外一台

    peer1的发现方式

    2017-12-03 17:47:13.807 INFO 7336 --- [nio-1111-exec-5] c.n.e.registry.AbstractInstanceRegistry : Registered instance RIBBON-CONSUMER/loca
    lhost:ribbon-consumer:9000 with status UP (replication=false)

    peer2的发现日志

    2017-12-03 17:47:14.913 INFO 19480 --- [nio-1112-exec-5] c.n.e.registry.AbstractInstanceRegistry : Registered instance RIBBON-CONSUMER/loc
    alhost:ribbon-consumer:9000 with status UP (replication=true)
    一个 replication=false 另一个 replication=true . 说明peer2是通过peer1同步过来的

    • 服务续约(renew)
    #定义服务续约任务的调用间隔时间
    eureka.instance.lease-renewal-interval-in-seconds=30
    #定义服务失效的时间
    eureka.instance.lease-expiration-duration-in-seconds=90
    
    • 服务消费者

      有Ribbon 和 Feign
      很多时候,客户端即使服务提供者也是服务消费者
      • 获取服务
        确保 eureka.client.fetch-registrytrue
        修改缓存清单的更新时间eureka.client.registry-fetch-interval-seconds=30
      • 服务调用
        Ribbon会默认采取轮询的方式进行调用
        对访问实例的选择,Eureka有 RegionZone 的概念
        1. 一个Region包含多个Zone
        2. 在服务调用的时候,优先访问同一个Zone中的服务提供方
      • 服务下线

    源码分析

    @EnableDiscoveryClient

    image.png
    EurekaDiscoveryClient
    EndpointUtils.getServiceUrlsFromConfig-->eureka.client.service-url.defaultZone=
    eureka.client.region= 指定region
    eureka.client.availability-zones=指定zone
    通过对Zone的定义,配合实际部署的物理结构,可以设计出对区域性故障的容错集群

    服务注册

    服务获取

    服务续约

    服务注册中心

    InstanceRegistry.register

    配置详解

    • Eureka服务端的配置可查看 EurekaServerConfigBean
    • Eureka客户端的配置

    服务注册类配置

    参数名 说明 默认值
    registryFetchIntervalSeconds Indicates how often(in seconds) to fetch the registry information from the eureka server 30
    instanceInfoReplicationIntervalSeconds Indicates how often(in seconds) to replicate instance changes to be replicated to the eureka server 30
    initialInstanceInfoReplicationIntervalSeconds Indicates how long initially (in seconds) to replicate instance info to the eureka server 40
    eurekaServiceUrlPollIntervalSeconds Indicates how often(in seconds) to poll for changes to eureka server information.Eureka servers could be added or removed and this setting controls how soon the eureka clients should know about it. 300
    eurekaServerReadTimeoutSeconds Indicates how long to wait (in seconds) before a read from eureka server needs to timeout. 8
    eurekaServerConnectTimeoutSeconds Indicates how long to wait (in seconds) before a connection to eureka server needs to timeout 5
    eurekaServerTotalConnections Gets the total number of connections that is allowed from eureka client to all eureka servers. 200
    eurekaServerTotalConnectionsPerHost Gets the total number of connections that is allowed from eureka client to a eureka server host. 50
    eurekaConnectionIdleTimeoutSeconds Indicates how much time (in seconds) that the HTTP connections to eureka server can stay idle before it can be closed 30
    heartbeatExecutorThreadPoolSize The thread pool size for the heartbeatExecutor to initialise with 2
    heartbeatExecutorExponentialBackOffBound Heartbeat executor exponential back off related property. It is a maximum multiplier value for retry delay, in case where a sequence of timeouts occurred.心跳超时延迟时间的最大乘数值 10
    cacheRefreshExecutorThreadPoolSize The thread pool size for the cacheRefreshExecutor to initialise with 2
    cacheRefreshExecutorExponentialBackOffBound Cache refresh executor exponential back off related property. It is a maximum multiplier value for retry delay, in case where a sequence of timeouts occurred缓存刷新重试 延迟时间的最大乘数值 10
    useDnsForFetchingServiceUrls Indicates whether the eureka client should use the DNS mechanism to fetch a list of eureka servers to talk to false
    registerWithEureka Indicates whether or not this instance should register its information with eureka server for discovery by others. true
    preferSameZoneEureka Indicates whether or not this instance should try to use the eureka server in the same zone for latency and/or other reason true
    filterOnlyUpInstances Indicates whether to get the applications after filtering the applications for instances with only InstanceStatus UP states true
    fetchRegistry Indicates whether this client should fetch eureka registry information from eureka server. true

    EurekaClientConfigBean
    服务注册中心加入安全校验

    参数名 说明 默认值
    registryFetchIntervalSeconds Indicates how often(in seconds) to fetch the registry information from the eureka server 30
    instanceInfoReplicationIntervalSeconds Indicates how often(in seconds) to replicate instance changes to be replicated to the eureka server 30
    initialInstanceInfoReplicationIntervalSeconds Indicates how long initially (in seconds) to replicate instance info to the eureka server 40
    eurekaServiceUrlPollIntervalSeconds Indicates how often(in seconds) to poll for changes to eureka server information.Eureka servers could be added or removed and this setting controls how soon the eureka clients should know about it. 300
    eurekaServerReadTimeoutSeconds Indicates how long to wait (in seconds) before a read from eureka server needs to timeout. 8
    eurekaServerConnectTimeoutSeconds Indicates how long to wait (in seconds) before a connection to eureka server needs to timeout 5
    eurekaServerTotalConnections Gets the total number of connections that is allowed from eureka client to all eureka servers. 200
    eurekaServerTotalConnectionsPerHost Gets the total number of connections that is allowed from eureka client to a eureka server host. 50
    eurekaConnectionIdleTimeoutSeconds Indicates how much time (in seconds) that the HTTP connections to eureka server can stay idle before it can be closed 30
    heartbeatExecutorThreadPoolSize The thread pool size for the heartbeatExecutor to initialise with 2
    heartbeatExecutorExponentialBackOffBound Heartbeat executor exponential back off related property. It is a maximum multiplier value for retry delay, in case where a sequence of timeouts occurred.心跳超时延迟时间的最大乘数值 10
    cacheRefreshExecutorThreadPoolSize The thread pool size for the cacheRefreshExecutor to initialise with 2
    cacheRefreshExecutorExponentialBackOffBound Cache refresh executor exponential back off related property. It is a maximum multiplier value for retry delay, in case where a sequence of timeouts occurred缓存刷新重试 延迟时间的最大乘数值 10
    useDnsForFetchingServiceUrls Indicates whether the eureka client should use the DNS mechanism to fetch a list of eureka servers to talk to false
    registerWithEureka Indicates whether or not this instance should register its information with eureka server for discovery by others. true
    preferSameZoneEureka Indicates whether or not this instance should try to use the eureka server in the same zone for latency and/or other reason true
    filterOnlyUpInstances Indicates whether to get the applications after filtering the applications for instances with only InstanceStatus UP states true
    fetchRegistry Indicates whether this client should fetch eureka registry information from eureka server. true

    服务实例类配置

    EurekaInstanceConfigBeaneureka.instance开头

    元数据

    InstanceInfo 中的private volatile Map<String, String> metadata = new ConcurrentHashMap<String, String>()是自定义元数据信息,其他的标准化的元数据信息

    1. 配置自定义元数据
    #自定义元数据配置
    eureka.instance.metadata-map.zone=shanghai
    
    1. 配置标准化元数据
      eureka.instance.<EurekaInstanceConfigBean中的属性> = <value>
    实例名配置

    随机端口配置

    eureka.instance.instance-id=${spring.application.name}:${random.int}
    

    上面配置能够实现在同一台主机上,不指定端口就能启动多个实例的效果

    端点配置

    确保/info和/health是有效的
    1.当修改了management.context-path时需要修改端点

    # 端点配置
    management.context-path=/hello
    eureka.instance.statusPageUrlPath=${management.context-path}/info
    eureka.instance.healthCheckUrlPath=${management.context-path}/health
    
    1. 为了安全考虑
    endpoints.info.path=appInfo
    endpoints.health.path=healthInfo
    eureka.instance.statusPageUrlPath=/${endpoints.info.path}
    eureka.instance.healthCheckUrlPath=/${endpoints.health.path}
    
    1. HTTPS的端点配置
    #HTTPS的端点配置
    eureka.instance.status-page-url=https://${eureka.instance.hostname}/info
    eureka.instance.health-check-url=https://${eureka.instance.hostname}/health
    eureka.instance.home-page-url=https://${eureka.instance.hostname}
    
    健康检测

    心跳方式的健康检查不能说明服务是可用的,因为服务可能还依赖一些数据库等,所以我们需要用/health端点来实现更全面的健康维护,步骤如下:

    1. 添加jar包至服务提供者
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-actuator</artifactId>
            </dependency>
    
    1. 在application.properties中添加配置
    # 健康检查
    #eureka.client.healthcheck.enabled=true
    
    1. 保证/health端点路径是有效的
      就是确保 eureka.instance.health-check-url 是有效访问的,具体可参考上面的端点配置
    其他配置
    image.png

    相关文章

      网友评论

          本文标题:Spring Cloud服务治理之Eureka

          本文链接:https://www.haomeiwen.com/subject/lmrabxtx.html