赞
踩
Eureka是基于REST(Representational State Transfer)服务,主要以AWS云服务为支撑,提供服务发现并实现负载均衡和故障转移。我们称此服务为Eureka服务。Eureka提供了Java客户端组件,Eureka Client,方便与服务端的交互。客户端内置了基于round-robin实现的简单负载均衡。在Netflix,为Eureka提供更为复杂的负载均衡方案进行封装,以实现高可用,它包括基于流量、资源利用率以及请求返回状态的加权负载均衡。
在AWS云,由于其天生的特性,服务器按需进行弹性伸缩。不像传统的负载均衡是基于固定的IP地址和host来实现,在AWS中,则需要提供更为复杂的负载均衡方案,以便对服务器进行注册和注销。由于AWS并未提供中间层负载均衡方案,Eureka的出世便填补了这个领域的巨大空白。
Eureka架构图是来自Eureka官方的架构图,大致描述了Eureka集群的工作过程。图中包含的组件非常多,可能比较难以理解,我们用通俗易懂的语言解释一下:
由图可知,Eureka包含两个组件:Eureka Server 和 Eureka Client,它们的作用如下:
Eureka Client是一个Java客户端,用于简化与Eureka Server的交互;
Eureka Server提供服务发现的能力,各个微服务启动时,会通过Eureka Client向Eureka
Server进行注册自己的信息(例如网络信息),Eureka Server会存储该服务的信息;
微服务启动后,会周期性地向Eureka Server发送心跳(默认周期为30秒)以续约自己的信息。如果Eureka
Server在一定时间内没有接收到某个微服务节点的心跳,Eureka Server将会注销该微服务节点(默认90秒);
每个Eureka Server同时也是Eureka Client,多个Eureka Server之间通过复制的方式完成服务注册表的同步;
Eureka Client会缓存Eureka Server中的信息。即使所有的Eureka
Server节点都宕掉,服务消费者依然可以使用缓存中的信息找到服务提供者。
综上,Eureka通过心跳检测、健康检查和客户端缓存,以及服务之间的数据同步等机制,提高了系统的灵活性、可伸缩性和可用性。(客户端与服务端的连接是信息注册哦,不是实际的连接,注销针对的是注册信息不是连接)
Eureka旨在运行在AWS中,并使用了许多AWS特有的概念和术语。区域(Regions)和可用区(Zone)是两个这样的情况。来自AWS文档:
Amazon
EC2托管在全球多个地点。这些位置由区域和可用区组成。每个区域都是一个独立的地理区域。每个区域都有多个隔离位置,称为可用区…每个区域都是完全独立的。每个区域是d地理分布上是相互隔离的,但区域中的可用区是通过低延迟链接连接的。
Eureka仪表板显示环境和数据中心。值被org.springframework.cloud.netflix.eureka.server.EurekaServerBootstrap,借助使用com.netflix.config.ConfigurationManager,设置为test与default分别。有各种查找和回退,所以如果由于某些原因需要更改它们,请参考上述类的源代码。
Eureka客户端默认偏好相同的可用区(可配置eureka.client.preferSameZone)。来自com.netflix.discovery.endpoint.EndpointUtils.getServiceUrlsFromDNSJavadoc:
eureka客户端从DNS获取所有eureka服务URL的列表,用于eureka客户端交互。客户端从其可用区中取出服务网址,遇到故障后随机地切换到其他可用区。如果同一可用区中有多个服务,则客户端将选择一个服务器进行尝试。在这种故障出现的情况下,请求流量将被分流。
spring-cloud-netflix#203的这篇文章是开放的,有几个人谈论到了区域和可用区。我做任何的验证,所以我不能评论区域和可用区是如何与Eureka一起协同工作的。
一个Eureka实例,通常由eureka.instance.instanceId进行区分,若不存在的情况下将使用eureka.instance.metadataMap.instanceId进行识别。实例间彼此使用eureka.instance.appName来进行查找,Spring Cloud默认使用spring.application.name,在前者参数未被定义的情况下使用UNKNOWN。需要设置spring.application.name,因为具有相同名称的应用程序将聚集在Eureka服务器中。没有必要去设置eureka.instance.instanceId,如果没有设置默认会被设置为CLIENT IP:PORT,但如果您设置它,则它必须在该范围内是唯一的appName。还有一个eureka.instance.virtualHostName,但它并没有被Spring使用,默认设置为spring.application.name或UNKNOWN如上所述。
如果registerWithEureka是true,一个实例使用给定的URL向Eureka服务器注册;然后,它每隔30s(可配置eureka.instance.leaseRenewalIntervalInSeconds)发送心跳。如果服务器没有收到心跳线,则eureka.instance.leaseExpirationDurationInSeconds在从实例注册表中删除实例之前等待90秒(可配置),并禁止该实例的流量。发送心跳是一个异步任务;如果操作失败,它将按指数次数退避2倍,直到eureka.instance.leaseRenewalIntervalInSeconds * eureka.client.heartbeatExecutorExponentialBackOffBound达到最大延迟。对Eureka注册的重试次数没有限制。
心跳与将实例信息更新到Eureka服务器不同。每个实例都由一个com.netflix.appinfo.InstanceInfo记录实例的信息。将InstanceInfo被定期发送到Eureka服务器,启动后40秒发送(通过配置eureka.client.initialInstanceInfoReplicationIntervalSeconds),然后开始每30秒发送(通过配置eureka.client.instanceInfoReplicationIntervalSeconds)。
如果eureka.client.fetchRegistry是true,客户端在启动时获取Eureka服务器注册表,并在本地缓存。从那时起,它只是获取增量(这可以通过设置来关闭eureka.client.shouldDisableDelta=false,尽管这会是浪费带宽)。注册表提取是每30秒调度一个异步任务(可配置eureka.client.registryFetchIntervalSeconds)。如果操作失败,它将按指数级数2倍,直到eureka.client.registryFetchIntervalSeconds * eureka.client.cacheRefreshExecutorExponentialBackOffBound达到最大延迟。获取注册表信息的重试次数没有限制。
客户端任务由com.netflix.discovery.DiscoveryClient调度,在Spring Cloud由org.springframework.cloud.netflix.eureka.CloudEurekaClient扩展实现。
##客户端实例注册过程
1.客户注册
启动后第一次心跳发生在30s(先前已经描述),所以实例在此间隔之前不会出现在Eureka注册表中。
2.服务器响应缓存
服务器维护每30秒更新一次的响应缓存(可配置eureka.server.responseCacheUpdateIntervalMs)。所以即使实例刚刚被注册,它也不会出现在/eureka/apps的REST接口结果中。但是,实例可能会在注册后出现在Eureka面板上。这是因为面板绕过REST API使用的响应缓存。如果知道instanceId,仍然可以通过调用/eureka/apps//接口从Eureka获取一些细节。此端点不会使用响应缓存。
因此,其他客户端可能需要30多秒才能发现新注册的实例。
3.客户端缓存刷新
Eureka客户端保留注册表信息的缓存。这个缓存每30秒刷新一次(如前所述)。因此,客户端决定刷新其本地缓存并发现其他新注册的实例可能需要30多秒。
4.LoadBalancer刷新
Ribbon使用的负载均衡器从本地的Eureka客户端获取其信息。同时还维护一份本地缓存,以避免为每个请求调用客户端。该缓存每30秒刷新一次(可配置ribbon.ServerListRefreshInterval)。因此,可能需要30秒才能使用新注册的实例。
##Eureka服务器
Eureka服务器具有对等感知模式,在其中复制其他Eureka服务器上的服务注册表,以提供负载平衡和弹性。对等感知模式是默认的,所以Eureka服务器也充当Eureka客户端,并在给定的URL上注册到对等体。这是你应该在生产所采取的,但对于演示或概念验证,你可以通过设置registerWithEureka=false运行在独立模式下。
当eureka服务器启动时,它尝试从对等eureka节点获取所有注册表信息。对每个对等体(可配置eureka.server.numberRegistrySyncRetries)重试5次。如果由于某种原因导致此操作失败,服务器将不允许客户端获取注册表信息5分钟(可配置eureka.server.getWaitTimeInMsWhenSyncEmpty)。
Eureka对等体感知,通过引入所谓的“自我保护”的概念,达到了一个全新的更为复杂的水平带(可以通过设置来关闭eureka.server.enableSelfPreservation到false)。事实上,从网上的资料来看,这是我看到大多数人绊倒的地方。来自于Netflix Wiki的描述是这样的:
当Eureka服务器启动时,它尝试从相邻节点获取所有实例注册表信息。如果从节点获取信息时出现问题,服务器会在放弃之前尝试所有对等体。如果服务器能够成功获取所有实例,它将根据该信息设置应该接收的更新阈值。如果有任何时间,续订低于为该值配置的百分比,则服务器将停止到达实例以保护当前实例注册表信息。
场景是这样的:如果有两个客户注册到一个Eureka实例,每一个人每30秒发送一次心跳,实例应该在一分钟内收到4个心跳。Spring将Eureka最小值加1(可配置eureka.instance.registry.expectedNumberOfRenewsPerMin),因此实例预计每分钟会收到5个心跳。然后乘以0.85(可配置eureka.server.renewalPercentThreshold),并天花板到下一个整数,这使我们再次回到5。如果任何时候在10分钟内由Eureka收到的心跳小于5次eureka.server.renewalThresholdUpdateIntervalMs,则进入自我保存模式并停止已经注册的实例。
Eureka服务器作出了一个隐含的假设:客户端每隔30s以固定的速率发送心跳。如果注册了两个实例,则服务器(2 * 2 + 1 ) * 0.85 = 5每分钟都会收到心跳。如果更新率下降到该值以下,则自动保存模式被激活。现在,如果客户端发送的心跳速度要快得多(比如每10秒钟),服务器每分钟会收到12个心跳,即使其中一个实例出现故障,也能接收到6 / min。因此,自我保护模式即使应该被激活。这就是为什么不建议改变eureka.client.instanceInfoReplicationIntervalSeconds。如果你确实需要调整时,可以修改eureka.server.renewalPercentThreshold。
Eureka对等体并不计入预期的续订次数,但是他们的心跳在最近一次收到的续订次数中被考虑。在对等感知模式下,心跳可以去任何Eureka实例;
这一点对运行在负载平衡器或做为Kubernetes服务之后是重要的,其中心跳(通常)以轮询模式发送到每个实例。
Eureka服务器在续订上限超过门槛值时,才会退出自我保存模式。自我保护模式期间,可能会导致客户端获取不再存在的实例。请参阅 了解Eureka对等体通讯。
在默认配置中,Eureka Server在默认90s没有得到客户端的心跳,则注销该实例,但是往往因为微服务跨进程调用,网络通信往往会面临着各种问题,比如微服务状态正常,但是因为网络分区故障时,Eureka Server注销服务实例则会让大部分微服务不可用,这很危险,因为服务明明没有问题。
为了解决这个问题,Eureka 有自我保护机制,通过在Eureka Server配置如下参数,可启动保护机制
eureka.server.enable-self-preservation=true
它的原理是,当Eureka Server节点在短时间内丢失过多的客户端时(可能发送了网络故障),那么这个节点将进入自我保护模式,不再注销任何微服务,当网络故障回复后,该节点会自动退出自我保护模式。
当然,server1、server2可以在对等感知模式下运行,并且它们的注册表被复制。但这与客户端注册是互不依赖的。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。