美文网首页
2、spring cloud服务治理之Eureka

2、spring cloud服务治理之Eureka

作者: lsyzl | 来源:发表于2019-11-29 14:20 被阅读0次

    spring cloud eureka

    目录

    • spring cloud eureka
      • 是什么?
      • 为什么需要服务治理?
      • eureka server 和eureka client 示例图
      • 其他的服务注册与发现组件
    • 使用Eureka
      • 搭建一个Eureka Server 服务注册中心
      • 搭建一个Eureka client 端:service provider
      • server端和client端yaml配置的一些说明
      • 关于eureka控制台出现红字的几种情况
      • eureka server 添加认证
    • Eureka集群
      • 搭建高可用的Eureka Server
      • eureka-server 配置
      • eureka consumer搭建
      • 启动服务和测试eureka server的高可用
    • github源码地址
      • 地址
      • 代码所在模块

    是什么?

    spring cloud eureka是spring cloud Netflix微服务套件中的一部分,它基于Netflix做了二次封装,主要负责微服务架构中的服务治理功能,服务治理可以说是微服务架构中最为核心和基础的模块,它主要用来实现各个微服务实例的自动化注册与发现。

    为什么需要服务治理?

    考虑当前有两个微服务实例A和B,A服务需要调用B服务的某个REST接口。假如某一天B服务迁移到了另外一台服务器,IP和端口也发生了变化,这时候我们不得不去修改A服务中调用B服务REST接口的静态配置。随着公司业务的发展,微服务的数量也越来越多,服务间的关系可能变得非常复杂,传统的微服务维护变得愈加困难,也很容易出错。所谓服务治理就是用来实现各个微服务实例的自动化注册与发现,在这种模式下,服务间的调用不再通过指定具体的实例地址来实现,而是通过向服务注册中心获取服务名并发起请求调用实现。

    eureka server 和eureka client 示例图

    eureka server和eureka client示例.png
    • Eureka Server:服务的注册中心,负责维护注册的服务列表。
    • Service Provider:服务提供方,作为一个Eureka Client,向Eureka Server做服务注册、续约和下线等操作,注册的主要数据包括服务名、机器ip、端口号、域名等等。
    • Service Consumer:服务消费方,作为一个Eureka Client,向Eureka Server获取Service Provider的注册信息,并通过远程调用与Service Provider进行通信。
    • Service Provider和Service Consumer不是严格的概念,Service Consumer也可以随时向Eureka Server注册,来让自己变成一个Service Provider。

    其他的服务注册与发现组件

    • Consul
    • Zookeeper
    • Dubbo
    • Nacos

    使用Eureka

    搭建一个Eureka Server 服务注册中心

    新建一个Spring Boot项目,artifactId填eureka-server,然后引入Greenwich.SR3和spring-cloud-starter-netflix-eureka-server:

        <!--spring cloud 版本 Greenwich.SR3 -->
        <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-dependencies</artifactId>
                    <version>Greenwich.SR3</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
            </dependencies>
        </dependencyManagement>
        
        <dependencies>
             <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter</artifactId>
            </dependency>
        </dependencies>
    

    启动类上加上注解@EnableEurekaServer表明这是一个Eureka Server端

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

    yaml配置:

    server:
      port: 8761 #指定端口为8761
    spring:
      application:
        name: @artifactId@ #eureka服务的名字
    eureka:
      instance:
        hostname: localhost #指定了eureka服务端的IP
      server:
        enable-self-preservation: false #用于开启Eureka Server自我保护功能,默认值为true,如果是true的话,eureka client在dev环境下会经常上线和下线,然后eureka server就认为client不是一个稳定的服务,不确定是否是真的可用还是不可用,就会报一串红色的警告。
      client:
        register-with-eureka: false #表示是否将服务注册到Eureka服务端,由于自身就是Eureka服务端,所以设置为false;
        fetch-registry: false #表示是否从Eureka服务端获取服务信息,因为这里只搭建了一个Eureka服务端,并不需要从别的Eureka服务端同步服务信息,所以这里设置为false;
        service-url:
          defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ #指定Eureka服务端的地址,默认值为http://localhost:8761/eureka。
    

    搭建一个Eureka client 端:service provider

    新建一个Spring Boot项目,artifactId填eureka-server,然后引入Greenwich.SR3和spring-cloud-starter-netflix-eureka-client:

            <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>
    

    启动类上加上注解@EnableDiscoveryClient表明这是一个Eureka Client端

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

    yaml配置:

    server:
      port: 8762
    spring:
      application:
        name: @artifactId@
    eureka:
      client:
        enabled: true #是否启用Eureka Client
        fetch-registry: true #表示是否从Eureka Server获取注册的服务信息
        register-with-eureka: true #表示是否将自己注册到Eureka Server
        service-url:
          defaultZone: http://localhost:8761/eureka/ #配置Eureka Server地址,用于注册服务和获取服务
        registry-fetch-interval-seconds: 30 #默认值为30秒,即每30秒去Eureka Server上获取服务并缓存
        instance-info-replication-interval-seconds: 30 #更新实例信息的变化到Eureka服务端的间隔时间,单位为秒
        eureka-service-url-poll-interval-seconds: 300 #轮询Eureka服务端地址更改的间隔时间,单位为秒。
        healthcheck:
          enabled: false #默认Eureka Server是通过心跳来检测Eureka Client的健康状况的,通过置为true改变Eureka Server对客户端健康检测的方式,改用Actuator的/health端点来检测。
      instance:
        lease-renewal-interval-in-seconds: 30 #向Eureka Server发送心跳的间隔时间,单位为秒,用于服务续约
        lease-expiration-duration-in-seconds: 90 #定义服务失效时间,即Eureka Server检测到Eureka Client木有心跳后(客户端意外下线)多少秒将其剔除.
        prefer-ip-address: false #表示使用IP进行配置为不是域名
        hostname: localhost #指定了eureka服务端的IP
    management:
      endpoints:
        web:
          exposure:
            include: "*" #暴露所有的actuator端点
      endpoint:
        health:
          show-details: always #健康检查展示所有详情:always
    

    server端和client端yaml配置的一些说明

    在上面的server端和client端的yaml配置,我把一些本来就是默认值得配置也写了进去(在项目里面可以按住ctrl+鼠标左键可以进源码看到是否为默认值),是因为显示的显示这些配置,并标注每个配置的使用含义,让配置更加直观。实际项目可以简化配置。下面是常用配置的表格:

    常用配置 配置含义 默认值
    eureka.client.enabled 是否启用Eureka Client true
    eureka.client.register-with-eureka 表示是否将自己注册到Eureka Server true
    eureka.client.fetch-registry 表示是否从Eureka Server获取注册的服务信息 true
    eureka.client.serviceUrl.defaultZone 配置Eureka Server地址,用于注册服务和获取服务 http://localhost:8761/eureka
    eureka.client.registry-fetch-interval-seconds 默认值为30秒,即每30秒去Eureka Server上获取服务并缓存 30
    eureka.instance.lease-renewal-interval-in-seconds 向Eureka Server发送心跳的间隔时间,单位为秒,用于服务续约 30
    eureka.instance.lease-expiration-duration-in-seconds 定义服务失效时间,即Eureka Server检测到Eureka Client木有心跳后(客户端意外下线)多少秒将其剔除 90
    eureka.server.enable-self-preservation 用于开启Eureka Server自我保护功能 true
    eureka.client.instance-info-replication-interval-seconds 更新实例信息的变化到Eureka服务端的间隔时间,单位为秒 30
    eureka.client.eureka-service-url-poll-interval-seconds 轮询Eureka服务端地址更改的间隔时间,单位为秒。 300
    eureka.instance.prefer-ip-address 表示使用IP进行配置为不是域名 false
    eureka.client.healthcheck.enabled 默认Erueka Server是通过心跳来检测Eureka Client的健康状况的,通过置为true改变Eeureka Server对客户端健康检测的方式,改用Actuator的/health端点来检测。 false

    其它配置参考:

    • org.springframework.cloud.netflix.eureka.server.EurekaServerConfigBean
    • org.springframework.cloud.netflix.eureka.EurekaClientConfigBean
    • org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean
      修改一些默认配置需要注意的点:

    官方:In production it's probably better to stick with the default because there are some computations internally in the server that make assumptions about the lease renewal period.

    译:在生产中,最好坚持使用默认值,因为服务器内部有一些计算可以对租赁更新期进行假设。

    关于eureka控制台出现红字的几种情况

    1、在配置上,自我保护机制关闭(eureka.server.enable-self-preservation=false)

    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.

    2、自我保护机制开启了(
    大致意思是Eureka已经进入了保护模式。微服务在部署之后可能由于网络问题造成Eureka客户端无法成功的发送心跳给Eureka服务端,这时候Eureka服务端认定Eureka客户端已经挂掉了,虽然实际上Eureka客户端还在正常的运行着。而保护模式就是为了解决这个问题,即当Eureka服务端在短时间内同时丢失了过多的Eureka客户端时,Eureka服务端会进入保护模式,不去剔除这些客户端。因为我们这里只部署了一个Eureka客户端服务,所以关闭客户端后满足“短时间内丢失过多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.

    3、在配置上,自我保护机制关闭了,但是一分钟内的续约数没有达到85% , 可能发生了网络分区,会有如下提示

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

    eureka server 添加认证

    server端添加:

            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-security</artifactId>
            </dependency>
    

    server端开启端点忽略:

    • You can secure your Eureka server simply by adding Spring Security to your server’s classpath via spring-boot-starter-security. By default when Spring Security is on the classpath it will require that a valid CSRF token be sent with every request to the app. Eureka clients will not generally possess a valid cross site request forgery (CSRF) token you will need to disable this requirement for the /eureka/** endpoints. For example:
    • 译:只需通过Spring boot starter Security将Spring Security添加到服务器的类路径中,就可以保护Eureka服务器。默认情况下,当Spring Security位于类路径上时,它将要求每次请求应用程序时都发送一个有效的CSRF令牌。Eureka客户端通常不会拥有有效的跨站点请求伪造(CSRF)令牌,您需要对/Eureka/**端点禁用此要求。例如:
    @EnableWebSecurity
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.csrf().ignoringAntMatchers("/eureka/**");
            super.configure(http);
        }
    }
    

    client端的配置也必须配置上用户名和密码,格式为:eureka.client.serviceUrl.defaultZone=http://{userName}:{password}@{hosetname}:{port}/eureka/,例如:

    eureka:
      client:
        service-url:
          defaultZone: http://root:123456@localhost:8761/eureka/ #配置Eureka Server地址,用于注册服务和获取服务
    

    Eureka集群

    eureka server 高可用.png

    搭建高可用的Eureka Server

    Eureka服务端充当了重要的角色,所有Eureka客户端都将自己提供的服务注册到Eureka服务端,然后供所有服务消费者使用。如果单节点的Eureka服务端宕机了,那么所有服务都无法正常的访问,这必将是灾难性的。为了提高Eureka服务端的可用性,我们一般会对其集群部署,即同时部署多个Eureka服务端,并且可以相互间同步服务。

    首先我们得检查这两个配置是否开启

    eureka:
      client:
        register-with-eureka: false
        fetch-registry: false
    

    这两个配置register-with-eureka=true是将自己注册到eureka服务端,然后fetch-registry是从服务端获取注册信息,搭建eureka server集群的话这两个得设置为true,才能各个eureka server之间相互发现。

    下面来部署这几个服务:

    服务名字 端口
    eureka-server 8761
    eureka-server 8762
    eureka-server 8763
    eureka-client-provider 8764
    eureka-client-provider 8765
    eureka-client-consumer 8766

    eureka-server 配置

    我们按照eureka集群的图来配置三个eureka server之间的互相通信,达成高可用的eureka server

    peer1:

    server:
      port: 8761 
    spring:
      application:
        name: eureka-server
    eureka:
      instance:
        hostname: peer1
      client:
        service-url:
          defaultZone: http://peer2:8762/eureka/,http://peer3:8763/eureka/
      server:
        enable-self-preservation: false
    

    peer2:

    server:
      port: 8762 
    spring:
      application:
        name: eureka-server
    eureka:
      instance:
        hostname: peer2
      client:
        service-url:
          defaultZone: http://peer1:8761/eureka/,http://peer3:8763/eureka/
      server:
        enable-self-preservation: false
    

    peer3:

    server:
      port: 8763 
    spring:
      application:
        name: eureka-server
    eureka:
      instance:
        hostname: peer3
      client:
        service-url:
          defaultZone: http://peer1:8761/eureka/,http://peer2:8762/eureka/
      server:
        enable-self-preservation: false
    

    这里peer1、peer2、peer3和本地映射的关系建议使用工具switchhost配置下,没switchhost的找到hosts文件改下也可以。


    switchhost本地映射关系.png

    eureka consumer搭建

    eureka-client-consumer配置:

    server:
      port: 8766
    spring:
      application:
        name: @artifactId@
    eureka:
      client:
        fetch-registry: true
        register-with-eureka: true
        service-url:
          defaultZone: http://peer1:8761/eureka/,http://peer2:8762/eureka/,http://peer3:8763/eureka/
      instance:
        hostname: localhost
    

    在启动类上加上负载均衡的注解等下测试eureka server 的高可用和 consumer调用provider默认采用均衡调用的规则

    @EnableDiscoveryClient
    @SpringBootApplication
    public class EurekaClientConsumerApplication {
        public static void main(String[] args) {
            SpringApplication.run(EurekaClientConsumerApplication.class, args);
        }
    
        @Bean
        @LoadBalanced
        public RestTemplate restTemplate(RestTemplateBuilder builder) {
            return builder.build();
        }
    }
    

    然后在consumer服务的controller写个调用provider服务的测试接口

    @Slf4j
    @RestController
    @RequestMapping("/consumer")
    @RequiredArgsConstructor(onConstructor = @__(@Autowired))
    public class ConsumerController {
    
        private final RestTemplate restTemplate;
    
        @RequestMapping("/getProviderInfo")
        public Integer getProviderInfo() {
            ResponseEntity<List> responseEntity = restTemplate.getForEntity("http://eureka-client-provider/provider/findInstance", List.class);
            List list = responseEntity.getBody();
            log.info("调用provider服务获取到的信息为:{}", JSON.toJSONString(list));
            if (null != list) {
                return list.size();
            }
            return 0;
        }
    }
    

    然后在provider定义接口:

    @Slf4j
    @RestController
    @RequestMapping("/provider")
    @RequiredArgsConstructor(onConstructor = @__(@Autowired))
    public class ProviderController {
        private final DiscoveryClient discoveryClient;
    
        /**
         * 测试eureka-client-provider服务能找到eureka server。
         * @return
         */
        @GetMapping(value = "/findInstance", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
        public List<ServiceInstance> findInstance() {
            //测试 (eureka client) provider 是否可以找到eureka server
            List<ServiceInstance> instances = discoveryClient.getInstances("eureka-server");
            log.info("根据服务名eureka-server获取到的服务实例明细:{}", JSON.toJSONString(instances));
            return instances;
        }
    }
    

    启动服务和测试eureka server的高可用

    启动三个eureka server、打开idea启动设置,运行多实例启动,启动两个provider服务,启动一个consumer服务,启动完成访问:http://localhost:8761/

    五个服务启动完成.png

    然后访问:http://localhost:8766/consumer/getProviderInfo

    这时候可以观察到provider服务两个节点的控制台会被轮流访问。

    然后干掉一个eureka server,继续访问你可以发现仍然是能通过其他两个eureka server 去调用到provider服务。

    github源码地址

    地址

    https://gitee.com/zhouliangde/spring-project-learing

    代码所在模块

    代码模块.png

    相关文章

      网友评论

          本文标题:2、spring cloud服务治理之Eureka

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