SpringCloud服务发现组件Eureka常见问题汇总

一.注册服务慢

1.背景
默认情况下,服务启动后,需要注册到Eureka Server上。但是在开发过程中发现,服务注册到Eureka Server的速度较慢。因此,在开发过程中希望缩短服务的注册时间以提高工作效率。
2.原因
服务注册涉及到周期性心跳,默认30秒一次。只有当实例,服务器端和客户端的本地缓存中的元数据都相同时,服务才能被其他客户端发现(所以可能需要3次心跳)。原理如下图所示:
在这里插入图片描述
因此,可以通过缩短客户端的等待时间间隔,也就是缩短客户端向Eureka发送心跳的时间间隔来提高工作效率。在Eureka中存在参数eureka.instance.leaseRenewalIntervalInSeconds,该值用于设置Eureka Client向Eureka Server发送心跳的时间间隔,默认30秒。通过将该参数设置成一个更小的值来实现。
3.解决方案
eureka.instance.leaseRenewalIntervalInSeconds设置成一个更小的值即可。

eureka:
  instance:
    lease-renewal-interval-in-seconds: 10

4.注意事项
生产环境下,该值建议使用默认值,以保证客户端可用。

二.已停止的微服务节点不注销或注销慢
1.背景
在开发环境下,我们会希望Eureka Server能迅速注销已停止的微服务实例。但是在实际开发过程中,往往当微服务停掉或者挂掉后,该服务实例仍然注册在Eureka Server上,需要等待很长一段时长后才消失。
2.原因
幕后的这一切,归结于两个方面:
一方面是因为Eureka Server清理无效节点的周期长(默认90秒);
另一方面,Eureka开启了自我保护模式之后,甚至不会注销任何微服务;
3.解决方案
了解原因之后,可以从上述两方面着手解决:
针对第一种情况,解决方案如下:
在Eureka Client端配置开启健康检查,并配置较短的续约更新时间和较短的到期时间。

eureka:
  client:
    healthcheck:
      enabled: true //开启健康检查
  instance:
    lease-renewal-interval-in-seconds: 10    //配置续约更新时间
    lease-expiration-duration-in-seconds: 10   //配置续约到期时间
  •  

针对第二种情况,解决方案如下:
在Eureka Server端配置关闭自我保护,并配置较短的Eureka Server清理无效节点的时间间隔。

eureka:
  server:
    enable-self-preservation: false    //关闭自我保护
    eviction-interval-timer-in-ms: 4000    //清理无效节点的时间间隔

4.注意事项
这些配置建议在开发或测试时使用,生产环境建议使用默认值。
5.扩展方案
如果读者了解Eureka Server的高级特性,那么在该问题下,也可以通过手动方式解决。
Eureka提供了一些REST端点来供我们进行服务的注册管理。非JVM的微服务可使用这些REST端点操作Eureka,从而实现注册与发现。
另外,Eureka的REST端点可以使用XML或者JSON与这些端点通信(默认是XML),来控制微服务的注册上下线。
因此,在本问题下,可以使用REST端点的删除端点进行删除。例如下列的微服务,如何做下线操作呢?
在这里插入图片描述
可以通过发送下列请求进行删除:

http://${user}:${password}@localhost:8761/eureka/apps/${application_name}/${server_name}

其中,该请求为DELETE方式,user:password为Eureka认证的账号密码;
application_name为Application的名称;
server_name为具体Application下某个Server的名称;
因此,上面的例子的下线方式如下:

http://admin:123456@localhost:8761/eureka/apps/ZZ-PROVIDER-USER/windows10.microdone.cn:zz-provider-user:8001
  •  

三.自定义微服务的InstanceID
1.背景
在Eureka的已注册服务界面中,希望自定义微服务的InstanceID,而不是默认值。
2.原因
在SpringCloud中,服务的InstanceId默认值是:

${spring.cloud.clent.hostname}:${spring.cloud.application.name}:${spring.application.port}

3.解决方案
只需要在微服务中配置eureka.instance.instance-id属性即可。

eureka:
   instance:
      instance-id: ${spring.cloud.client.ipAddress}:${server.port}

四.名称异常(UNKNOWD)
1.背景
在Eureka Server的注册界面上,显示微服务名称为UNKNOWN,或者应用状态为UNKNOWN。
当微服务名称为UNKNOWN发生时,显然不符合科学。首先微服务的名称不够语义化,无法看出是哪个微服务,其次我们常常使用应用名称消费对应微服务的接口,这样会导致消费的失败。
而当应用状态为UNKNOWN时,微服务不是UP状态(也即是不健康状态),同时会导致消费的失败。
2.原因
以下分两种情况讨论
<1>应用名称为UNKNOWN的情况
一般来说有两种情况会导致该问题的发生:
1~未配置spring.application.name或者eureka.instance.appname属性。如果这两个属性均不配置,则会导致应用UNKNOWN的问题;
2~某些版本的SpringFox会导致该问题。例如SpringFox2.6.0。建议使用SpringFox2.6.1或更新的版本;
<2>微服务实例状态为UNKNOWN的情况
该问题一般由健康检查导致。
3.解决方案
针对第一种情况,可以配置spring.application.name或者eureka.instance.appname属性:

spring:
  application:
    name: zz-provider-user 

针对第二种情况,可以配置eureka.client.healthcheck.enabled属性:

eureka:
  client:
    healthcheck:
      enabled: true

注意:该种情况下,eureka.client.healthcheck.enabled=true必须设置在application.yml中,而不能设置在boostrap.yml,否则一些场景下会导致应用状态UNKNOWN的问题。

五.扩展Eureka客户端元数据
1.背景
在Eureka使用过程中,我们常常需要根据自己定义的元数据,来区分不同的微服务。举个栗子,在测试环境的Eureka集群上注册了2个同样的微服务A,B,我们希望在SIT环境消费微服务时只消费到微服务A,而在UAT环境消费时只消费到微服务B,此时通过自己定义的元数据,区分不同环境在消费微服务时的选择。原理图如下:
在这里插入图片描述
2.相关思路
通过元数据,可以解决这类问题。那么什么是元数据呢?下面简单介绍下Eureka的元数据。
Eureka的元数据包括标准元数据和自定义元数据。
标准元数据指的是主机名,IP地址,端口号,状态页和健康检查等信息。这些信息都会被发布在服务注册表中,用于服务之间的调用;
自定义元数据可以使用eureka.instance.metadata-map配置,这些数据可以在远程客户端中访问,但是并不会改变客户端的行为;
通过使用DiscoveryClient.getInstances(serviceId),可查询指定微服务在Eureka上的实例列表
3.解决方案
配置自定义元数据
<1>配置yml文件

eureka:
  client:
    serviceUrl:
      defaultZone: http://admin:123456@peer1:8761/eureka/,http://admin:123456@peer2:8761/eureka/
  instance:
    prefer-ip-address: true
    metadata-map:
      service-id: 10000
      service-timeout: 60

<2>新增UserController

@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private DiscoveryClient discoveryClient;

    @RequestMapping("/getUserInfo")
    public List<ServiceInstance> getUserInfo () {
        return discoveryClient.getInstances("zz-provider-user");
    }
    
}

<3>访问元数据
启动应用,通过user/getUserInfo访问。
通过上述步骤实现自定义元数据,解决Eureka分组的问题。除此之外,自定义元数据还可以解决其他场景的问题,例如微服务建立唯一标识,微服务消费排序等问题,在此不再赘述。

六.多网卡环境下的IP选择
1.背景
某些微服务所部署的服务器具有多个网卡,这些微服务在注册到Eureka Server时,如果按照默认的注册流程,可能导致该微服务无法被其他服务器访问。
例如某些服务器有eth0,eth1和eth2三张网卡,但是只有eth1可以被其他的服务器访问;如果Eureka Client将eth0或者eth2注册到Eureka Server上,其他微服务就无法通过这个IP调用该微服务的接口。
2.解决方案
针对多网卡的服务器,可以通过指定各个微服务注册到Eureka Server上的IP来实现。
Spring Cloud提供了按需选择IP的能力,从而避免以上的问题。下面提供SpringCloud自带的四种解决方案。
<1>忽略指定名称的网卡:

spring:
  cloud:
    inetutils:
      ignored-interfaces:
        - dokcer0
        - veth.*
eureka:
  instance:
    prefer-ip-address: true

这样就可以忽略docker0网卡以及所有以veth开头的网卡。
<2>使用正则表达式,指定使用的网络地址:

spring:
  cloud:
    inetutils:
      preferredNetworks:
        - 192.168
        - 10.0
eureka:
  instance:
    prefer-ip-address: true

<3>只使用站点本地地址:

spring: 
  cloud: 
    inetutils: 
      useOnlySiteLocalInterfaces: true

<4>手动指定IP地址:

eureka: 
  instance: 
    prefer-ip-address: true
      ip-address: 127.0.0.1

猜你喜欢

转载自blog.csdn.net/rubbertree/article/details/92978544
今日推荐