2、spring cloud服务治理之Eureka

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 示例图

2、spring cloud服务治理之Eureka_第1张图片
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:

    
    
        
            
                org.springframework.cloud
                spring-cloud-dependencies
                Greenwich.SR3
                pom
                import
            
        
    
    
    
         
            org.springframework.cloud
            spring-cloud-starter-netflix-eureka-server
        
        
            org.springframework.boot
            spring-boot-starter
        
    

启动类上加上注解@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:

        
            org.springframework.cloud
            spring-cloud-starter-netflix-eureka-client
        
         
            org.springframework.boot
            spring-boot-starter-web
        

启动类上加上注解@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端添加:

        
            org.springframework.boot
            spring-boot-starter-security
        

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://{password}@{port}/eureka/,例如:

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

Eureka集群

2、spring cloud服务治理之Eureka_第2张图片
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文件改下也可以。


2、spring cloud服务治理之Eureka_第3张图片
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 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 findInstance() {
        //测试 (eureka client) provider 是否可以找到eureka server
        List instances = discoveryClient.getInstances("eureka-server");
        log.info("根据服务名eureka-server获取到的服务实例明细:{}", JSON.toJSONString(instances));
        return instances;
    }
}

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

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

2、spring cloud服务治理之Eureka_第4张图片
五个服务启动完成.png

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

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

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

github源码地址

地址

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

代码所在模块

2、spring cloud服务治理之Eureka_第5张图片
代码模块.png

你可能感兴趣的:(2、spring cloud服务治理之Eureka)