springCloud Euraka知识讲解、问题解决方案、优化方案

目录

​​​​​​​​​​​​​​

概述

介绍

Euraka基本配置

Eureka-server配置参数

基本参数

​​​​​​​Response cache参数

​​​​​​​peer相关参数

​​​​​​​http参数

基本参数

​​​​​​​instance参数

​​​​​​​http参数

​​​​​​​其他参数

问题及分析

单机器多个实例配置问题

个主机上启动多个实例

​​​​​​​健康监测及端点配置,euraka注册页点击服务连接Error

对于健康检查的有效配置参数

​​​​​​​自我保护失效问题

​​​​​​​自注册问题

​​​​​​​改变首次注册时间长问题

缓存

服务器缓存

​​​​​​​Time lag,服务上线下线延迟

​​​​​​​time lang问题

​​​​​​​感知公式

建议配置

Server端

Client端


概述

现在很多项目使用springcloud euraka做为注册中心,现阶段准备统一注册中心,趁现在时间还有空余,就把项目所遇到的问题,及euraka配置参数,统一记录下,以做备忘及后续员工的技术手册。

euraka做为微服务架构里的注册中心,保证服务高可用性和最终一致性,搭建简单,但在正产环境应用还是需要注意很多问题。

 

  1. 介绍

Spring-Cloud Euraka是Spring Cloud集合中一个组件,它是对Euraka的集成,用于服务注册和发现。Eureka是Netflix中的一个开源框架。它和 zookeeper、Consul一样,都是用于服务注册管理的,同样,Spring-Cloud 还集成了Zookeeper和Consul。

在项目中使用Spring Cloud Euraka的原因是它可以利用Spring Cloud Netfilix中其他的组件,如zull等,因为Euraka是属于Netfilix的。

 

Eureka由多个instance(服务实例)组成,这些服务实例可以分为两种:Eureka Server和Eureka Client。为了便于理解,我们将Eureka client再分为Service Provider和Service Consumer。

  • Eureka Server 提供服务注册和发现
  • Service Provider 服务提供方,将自身服务注册到Eureka,从而使服务消费方能够找到
  • Service Consumer服务消费方,从Eureka获取注册服务列表,从而能够消费服务
  1. Euraka基本配置

    Eureka-server配置参数

    1. 基本参数

eureka.server.

  • enable-self-preservation: true

#是否开启自我保护模式,默认是开启的

  • renewal-percent-threshold: 0.85

#每分钟需要收到的续约次数的阈值, server会根据某个应用注册时实例数,计算每分钟应收到的续约次数,若收到的次数少于该阈值,server会关闭该租约,并禁止定时任务剔除失效的实例,保护注册信息

  • renewal-threshold-update-interval-ms: 15

#指定updateRenewalThreshold定时任务的调度频率,来动态更新expectedNumberOfRenewsPerMin和numberOfRenewsPerMinThreshold值

# 心跳阈值重新计算周期,可适当调短些

  • eviction-interval-timer-in-ms: 60000

#指定EvictionTask定时任务的调度频率,用于剔除过期的实例,默认是60秒执行一次

#若有效服务挂掉,并没有告知euraka server,通过EvictionTask任务剔除。

eureka.instance.registry.

  • expected-number-of-renews-per-min(已过时): 1

#指定每分钟需要收到的续约次数值,实际该值在其中被写死为count*2

 

​​​​​​​Response cache参数

Euraka server为了提升自身REST API接口的性能,提供了2个缓存,一个是基于ConcurrentHashMap的readOnlyCacheMap,一个是基于Guava Cache的readWriteCacheMap。

 

eureka.server.

  • use-read-only-response-cache: true

#是否使用只读的response-cache。

  • response-cache-update-interval-ms: 30*1000

#设置CacheUpdateTask的调度时间间隔,用于从readWriteCacheMap更新数据到readOnlyCacheMap,仅仅在eureka.server.use-read-only-response-cache为true的时候才生效

  • response-cache-auto-expiration-in-seconds: 180

#设置readWriteCacheMap的expireAfterWrite参数,指定写入多长时间后过期

 

​​​​​​​peer相关参数

eureka.server.

  • peer-euraka-nodes-update-interval-ms: 10

#默认10分钟,指定peersUpdateTask调度的时间间隔,用于从配置文件刷新peerEurekaNodes节点的配置信息(eureka.client.serviceUrl相关zone的配置)

  • peer-euraka-status-refresh-time-interval-ms: 30*1000

#指定更新peer nodes状态信息的时间间隔

 

​​​​​​​http参数

eureka.server.

  • peer-node-connect-timeout-ms: 200

#server各node间连接超时时长,默认200毫秒,200毫秒没连接上server的其他节点,就会认为该node不可用

  • peer-node-read-timeout-ms: 200

#从其他节点读取数据超时时间 ,默认200毫秒

  • peer-node-total-connections: 1000

#server的单个node连接池最大的活动连接数

  • peer-node-total-connections-per-host: 500   

#server的单个node每个hot能使用的最大连接数

  • peer-node-connection-idle-timeout-seconds: 30    

#server的node连接池连接的空闲时间

 

  1. Eureka-client配置参数
    1. 基本参数

eureka.client.

  • availability-zones: null

#告知Client有哪些region和availability-zones,支持配置修改运行时生效

  • filter-only-up-instances: true

#是否过滤出注册到eureka中所有InstanceStatus为UP的实例,默认为true

  • register-with-eureka: true

#是否将该实例注册到 eureka server,eureka注册中心配置为false,不把自身注册到eureka

  • prefer-same-zone-eureka: true

#是否优先使用与该实例处于相同zone的Eureka server ,默认为true

#即默认会使用与实力处于相同zone的server,如果找不到,才会默认使用defaultZone中配置的。

  • on-demand-update-status-change: true

#是否将本地实例状态通过ApplicationInfoManager实时同步到到Eureka Server中,默认是true,一般情况下不要改,默认就行

  • instance-info-replication-interval-seconds: 30

#变更同步到Eureka Server的时间间隔

  • register-fetch- interval-seconds: 30

#从Eureka服务端获取注册信息的间隔时间,单位为秒

  • initiall-instance-info-replication-interval-seconds: 30

#初始化实例信息到Eureka服务端的间隔时间,单位为秒,单位为秒

  • fetch-register: true

#是否从Eureka服务端获取注册信息

  • service-url:

#指定注册中心

 

 

​​​​​​​instance参数

eureka.instance.

  • metadata-map:

#指定该应用实例的元数据信息。

  • prefer-ip-address: false

#是否优先使用IP地址来代替host name,默认是false。

  • response-cache-auto-expiration-in-seconds: 180

#指定Eureka Client间隔多久向Eureka Server发送心跳来告知Eureka Server该实例还存活,默认是90秒

  • lease-renewal-interval-in-seconds: 30

# Eureka Client向Server发送心跳的时间间隔,默认CLient隔30秒就会向Server发送一次心跳

#客户端首次注册时间是30S,首次注册与首次心跳绑定,首次心跳发送后会收到not found的响应,若要加快首次注册速度,可查看1.2.1基本参数

 

​​​​​​​http参数

eureka.client.

  • eureka-server-connect-timeout-seconds: 5

#连接server的超时时间 默认5秒

  • eureka-server-read-timeout-seconds: 8

# client 从server读取数据超时时间,默认8秒

  • eureka-server-total-connections: 200

#连接池最大的活动连接数 最大默认200个连接数

  • eureka-server-total-connections-per-host: 50

#每个host能使用的最大连接数 ,默认每个主机最多只能使用50个连接

  • eureka-connection-idle-timeout-seconds: 30

#连接池中连接的空闲时间

  • eureka-service-url-poll-interval-seconds: 300

#轮询Eureka服务端地址更改的间隔时间,单位为秒。当我们与Spring CLoud Config整合,动态刷新Eureka的serviceURL地址时需要关注该参数

 

​​​​​​​其他参数

eureka.client.

  • heartbeat-executor-thread-pool-size: 2

#心跳连接池的初始化线程数

  • heartbeat-executor-exponential-back-off-bound: 10

#心跳超时重试延迟时间的最大乘数值

  • cache-refresh-executor-thread-pool-size: 2

#缓存刷新线程池的初始化线程数

  • cache-refresh-executor- exponential-back-off-bound: 10

#缓存刷新重试延迟时间的最大乘数值。

  • use-dns-for-fetching-service-urls: false

#使用DNS来获取Eureka服务端的serviceUrl

 

 

  1. 问题及分析

    1. 单机器多个实例配置问题

  • 个主机上启动多个实例

Eureka的配置中,针对统一主机中启动多实例的情况,对实例名的默认命名作了更为合理的扩展,它采用了如下默认规则:

${spring.cloud.client.hostname}:${spring.application.name}:${spring.application.instance_id:${server.port}}

对于实例名的命名规则,我们也可以通过eureka.instance.instanceId参数来进行配。如:

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

通过上面的配置,利用应用名加随机数的方式来区分不同的实例,从而实现在统一主机上,不指定端口就能轻松启动多个实例的效果。

 

​​​​​​​健康监测及端点配置,euraka注册页点击服务连接Error

home-page-url:应用主页的URL

status-page-url:状态页的URL

health-check-rl:健康检查的URL

状态页和健康检查的URL在Spring Cloud Eureka中默认使用了spring-boot-actuator模块提供的/info端点和/health端点。但并不代表Eureka各个服务实例的健康监测通过spring-boot-actuator模块/health端点来实现;他是依靠依靠客户端心跳的方式来保持服务实例的存活,我们需要配置为actuator来实现健康检查。

为了服务的正常运作,我们必须确保Eureka客户端的/health端点在发送元数据的时候,是一个能被注册中心访问到的地址,否则服务注册中心不会根据应用的健康检查来更改状态(仅当开启了healthcheck功能时,以该端点信息作为健康检查标准)。而/info端点如果不正确的话,会导致在Eureka面板中单机服务实例时,无法访问到服务实例提供的信息接口。 大多数情况下,我们并不需要修改这几个URL配置。

 

  • 对于健康检查的有效配置参数

需要配置eureka.client.healthcheck.enabled=true

健康检查参数如下:

参数名

说明

默认值

preferIpAddress

是否优先使用IP地址作为主机名的标识

FALSE

leaseRenewalIntervalInSeconds

Eureka客户端向服务端发送心跳的时间间隔,单位为秒

30

leaseExpirationDurationInSeconds Eureka

服务端在收到最后一次心跳之后等待的时间上限,单位为秒。超过该时间之后服务端会将该服务实例从服务清单中剔除,从而禁止服务调用请求被发送到该实例上

90

nonSecurePort

非安全的通信端口号

80

securePort

安全的通信端口号

443

nonSecurePortEnabled

是否启用非安全的通信端口号

TRUE

securePortEnabled

是否启用安全的通信端口号

 

appname

服务名,默认取spring.application.name的配置值,如果没有则为unknown

 

hostname

主机名,不配置的时候讲根据操作系统的主机名来获取

 

 

 

​​​​​​​自我保护失效问题

修改client的心跳时间,会导致自我保护失效。

lease-renewal-interval-in-seconds: 30

eureka server认为客户端是以30s的频率发送心跳,服务器端收到的最大心跳时间是:N个instance * 2(60s/30s)* threshold

即若有2个服务注册,2*2*85%=3.4个心跳

若改为15S,1个注册服务1分钟会发送4次心跳,而euraka server 的阈值还是3次心跳,那么自我保护模式失效。

  核心原因就是在Eureka Server计算期望心跳数的时候写死了每分钟的心跳间隔,即30秒,所以他永远会是*2(60s/30s)

 

Euraka启动时:

eureka-core-1.4.12-sources.jar!/com/netflix/eureka/registry/PeerAwareInstanceRegistryImpl.java

client注册时:

eureka-core-1.4.12-sources.jar!/com/netflix/eureka/registry/AbstractInstanceRegistry.java

由于eureka-core-1.4.12版本里头,你去调整eureka.instance.leaseRenewalIntervalInSeconds的话,代码里头没有相应调整factor,也就是代码还是60/30=2,所以会破坏eureka内置的设计思路。不过对于小型项目来说,没有跨机房,网络没有那么恶劣的话,想避免自我保护导致的服务注册列表不能修改的问题,可以选择以下任一方式尝试下:

调小eviction-interval-timer-in-ms: 5000,清理间隔(单位毫秒, 默认是60*1000)

 

  • 关闭自我保护enable-self-preservation =false
  • 调小lease-renewal-interval-in-seconds,比如设置为10秒
  • 调小renewal-percent-threshold,比如改为0.49
  • 另外,还有一个参数可以调整,就是心跳阈值重新计算的周期:可以适当调整心跳阈值重新计算的周期renewal-threshold-update-interval-ms: 15,时间适当短一些,如改为5分钟

 

​​​​​​​自注册问题

单机模式下:

register-with-eureka和fetch-registry应为false,否则启动会报错:Cannot execute request on any known server。原因,在默认设置下,eureka服务注册中心会将自己作为客户端来尝试注册自己。

 

集群模式下:

fetch-registry与register-with-eureka,一定要设置为true或者不写,否则会出现unavailable-replicas

并且尽量把所有的euraka服务地址都要写在客户端defaultzone下。

 

 

​​​​​​​改变首次注册时间长问题

首次注册和首次心跳是绑定在一起的,首次心跳发送后会收到not found的响应,client识别还没有注册过,client会马上注册。

由参数initiall-instance-info-replication-interval-seconds: 30控制,可适当调整此参数加快首次注册过程。他是控制首次改变实例状态(UP/DOWN )的时间,启动的时候状态肯定是需要改变的,所以他可以用来加快首次注册速度,并且改变这个值不会影响到保护模式

如果使用的是springcloud-euraka的话,没有这种问题。

 

 

  1. 缓存

    1. 服务器缓存

Eureka内部的缓存分很多级,主要有registry、readWriterCacheMap、readOnlyCacheMap;另外还有一个维护最近180s增量的队列recentlyChangedQueue。

写操作

包括注册、取消注册等,都直接操作在registry上,同时也会更新recentlyChangedQueue和readWriterCacheMap

读操作

读默认是从readOnlyCacheMap读取,读不到的话再从readWriterCacheMap,若还不命中,从registry中取。

滥用缓存的读操作

这个读操作的三级缓存结构,非常让人困惑,registry已经是ConcurrentHashMap,纯内存操作,性能非常高了,为什么前面还要加两级缓存;readWriterCacheMap的数据是在写入以后responseCacheAutoExpirationInSeconds(默认180)秒内失效,readOnlyCacheMap则是一个定时任务,每responseCacheUpdateIntervalMs(默认30)秒从readWriterCacheMap获取最新数据

去掉readOnlyCacheMap

从CAP理论上看,Eureka是一个AP系统,但是在C层面这么弱,就是因为各种无谓的缓存造成的,看了下readWriterCacheMap去掉比较难,但是readOnlyCacheMap有一个开关use-read-only-response-cache。

 

服务端默认会有个read only response cache,每30秒更新一次,通过response-cache-update-interval-ms控制,注册后需要等待刷新后才能看到。(通过rest api不能看到,但是你可以在web ui上看到,因为ui没有缓存)

 

​​​​​​​Time lag,服务上线下线延迟

了解time lag之前,先看几个问题及解决方案。

Client 下线没有通知 Eureka Server 的问题:

应用实例异常挂掉,没能在挂掉之前告知Eureka server要下线掉该服务实例信息。这个就需要依赖Eureka server的EvictionTask去剔除

 

针对 response cache 的问题:

可以根据情况考虑关闭 readOnlyCacheMap

use-read-only-response-cache: false

# 设置read Write CacheMap的expire After Write参数,指定写入多长时间后过期

# 有效防止的问题是:应用实例下线时有告知Eureka server下线,但是由于Eureka server的REST API有response cache,因此需要等待缓存过期才能更新

response-cache-auto-expiration-in-seconds: 60

 

​​​​​​​time lang问题

Eureka wiki中提到的2min time lag问题,其实分多个角度看,不一定是120s。

服务正常上线/修改,最大可能会有120s滞后。

30(首次注册 init registe) + 30(readOnlyCacheMap)+30(client fetch interval)+30(ribbon)=120

如果是在Spring Cloud环境下使用这些组件(Eureka, Ribbon),不会有首次注册30秒延迟的问题,服务启动后会马上注册,所以从注册到发现,最多可能是90s。

服务异常下线:

最大可能会有270s滞后

定时清理任务每eviction-interval-timer-in-ms(默认60)执行一次清理任务,每次清理任务会把90秒(3个心跳周期,eureka.instance.lease-expiration-duration-in-seconds)没收到心跳的踢除,但是根据官方的说法 ,因为代码实现的bug,这个时间其实是两倍,即180秒,也就是说如果一个客户端因为网络问题或者主机问题异常下线,可能会在180秒后才剔除。 读取端,因为readOnlyCacheMap以及客户端缓存的存在,可能会在30(readOnlyCacheMap)+30(client fetch interval)+30(ribbon)=90,所以极端情况最终可能会是180+90=270

 

​​​​​​​感知公式

异常下线最长感知时间计算公式:

2*eureka.instance.leaseExpirationDurationInSeconds+ eureka.server.evictionIntervalTimerInMs+ eureka.client.registryFetchIntervalSeconds+ ribbon. ServerListRefreshInterval

正常上下线感知公式:eureka.client.registryFetchIntervalSeconds+ribbon. ServerListRefreshInterval

 

 

 

  1. 建议配置

Server端

## 中小规模下,自我保护模式坑比好处多,所以关闭它

eureka.server.enable-self-preservation=false

## 心跳阈值计算周期,如果开启自我保护模式,可以改一下这个配置

## eureka.server. renewal-threshold-update-interval-ms:120000

 

## 主动失效检测间隔,配置成5秒

eureka.server.eviction-interval-timer-in-ms=5000

## 心跳间隔,5秒

eureka.instance. lease-renewal-interval-in-seconds=5

## 没有心跳的淘汰时间,10秒

eureka.instance. lease-expiration-duration-in-seconds=10

## 禁用readOnlyCacheMap

eureka.server. use-read-only-response-cache=false

 

 

Client端

## 心跳间隔,5秒

eureka.instance.lease-renewal-interval-in-seconds=5

## 没有心跳的淘汰时间,10秒

eureka.instance.lease-expiration-duration-in-seconds=10

# 定时刷新本地缓存时间

eureka.client.registry-fetch-interval-seconds=5

# ribbon缓存时间

ribbon.server-list-refresh-interval=2000

你可能感兴趣的:(技术架构)