之前我们分析了eureka的注册服务实例信息,下面我们来分析下eureka的续租。当一个租约到期后,就有两种情况,一种是过期,EurekaServer将下线过期的节点,一种是续租,当EurekaServer检测到节点还能正常通信时,将执行续租的 *** 作。我们知道,检测节点状态是ScheduledExecutorService的schedule方法,那么定时检测节点状态的任务是怎么执行的呢,答案就是TimedSupervisorTask。我们先来看下TimedSupervisorTask都有哪些属性
TimedSupervisorTask 执行时,提交 task 到 executor 执行任务。
当 task 执行正常,TimedSupervisorTask 再次提交自己到scheduler 延迟 timeoutMillis 执行。
当 task 执行超时,重新计算延迟时间( 不允许超过 maxDelay ),再次提交自己到scheduler 延迟执行。
再来看下run方法的具体实现
续租应用实例信息的请求,映射 InstanceResource的renewLease方法,看下具体的实现
调用 AbstractInstanceRegistry的renew方法,续租应用实例信息,看下具体的实现
调用 Lease的renew方法,设置租约最后更新时间( 续租 ),看下具体的实现
整个过程修改的租约的过期时间,即使并发请求,也不会对数据的一致性产生不一致的影响,因此不需要加锁。
Eureka续租的 *** 作就完成了。
TimedSupervisorTask的分析就到这里了。
在我们启动一个服务后,可能要过一分多钟才能被其他服务调用到,那么这种情况不管是开发/测试环境,亦或是生产环境都会影响效率。出现该问题的原因有以下几种:
所以终上所述,一个服务注册上线需要的最大时间为30(eurekaserverresponse-cache-update-interval-ms)+30(eurekaclientregistry-fetch-interval-seconds)+30(ribbonServerListRefreshInterval)=90秒。
在服务停掉后,Eureka Server并不能快速的将已停止的服务实例剔除,对调用方而言,请求到已停止的服务实例上则会提示拒绝连接,出现该问题的原因有以下几种:
综合以上服务注册慢/注销慢的原因,我们的解决方案其实就是将上述的一些参数时间缩短。参考配置如下:
上述的配置只适用于中小型应用,需要注意的是,如果把请求Eureka Server的时间都调小的话(比如获取注册表、发送心跳等),在系统服务实例的数量很大的情况下,那么会对Eureka Server造成压力。
如果Eureka服务节点在短时间里丢失了大量客户端的心跳连接时,(注:可能发生了网络故障,有可能客户端实例还在正常运行),那么这个Eureka节点会进入”自我保护模式“,同时保留那些“心跳死亡“的服务注册信息不过期。此时,这个Eureka节点对于新的服务还能提供注册服务,对于”死亡“的仍然保留,以防还有客户端向其发起请求。当网络故障恢复后,这个Eureka节点会退出”自我保护模式“。所以Eureka的哲学是,同时保留”好数据“与”坏数据“总比丢掉任何”好数据“要更好。
对于不存在跨区、跨网络机房的中小型应用而言,建议关闭自我保护模式。
产生该问题是由于Eureka的自我保护机制引起的。
Spring Boot默认开启自我保护机制,一旦开启,它将不会从注册列表中剔除因长时间没收到心跳导致租期过期的服务,从而出现服务停止,但实例仍在线的情况。
leaseRenewalIntervalInSeconds:EurekaClient 向注册中心发送心跳的时间间隔,(单位:秒)客户端告诉注册服务端自己会按照该规则发送心跳
leaseExpirationDurationInSeconds:EurekaServer在收到最后一次心跳后等待的时间上限,(单位:秒),超过则剔除。客户端告诉注册服务端自己会按照该规则发送心跳
添加配置关闭自我保护,主要是提供者服务:
eureka:
server:
enableSelfPreservation: false #关闭保护机制
instance:
leaseRenewalIntervalInSeconds: 1
leaseExpirationDurationInSeconds: 2
1、调用/service-registry端点将状态置为 OUT_OF_SERVICE
2、sleep 缓存刷新时间 + 单个请求处理时间
3、kill 服务pid,让容器执行相关资源的释放以及扫尾工作
4、kill -9 终止服务,杀死进程
5、调用 /service-registry端点将状态置为 CANCEL_OVERRIDE,其实就是向Server端发送DELETE overriddenstatus的请求,这会让Server端 status=UNKNOWN 且 overriddenstatus=UNKNOWN
这里可以写个类容器启动时自动向eureka发出这个请求
6、服务定时更新状态线程更新Up状态给Eureka,服务发布完成。无缝发布不影响业务
参考文章地址: >
啃了n天eureka,其实我个人对他的理解: 用起来简单,理解起来抽象。 喏,手打不易,大家动动小手分享转发点赞评论啥的~~~~
打个比方:我们知道太阳东升西落是因为地球的自转。但是我们知道为什么地球会自传么?而且为什么是沿着一个方向转而不是来回来去转?好吧~这个我也不知道~~所以谈下一话题,eureka集群是怎么实现的。
电脑自带的画图用不明白~~手画吧。。三个server,两个client,关系如下:
其实每一个服务端(这里指实例)都内置了一个Eureka Client,也就是说一个服务端可以接受其他Client的注册,也可以作为一个Client注册到其他Server上,被其他Client发现和调用。一个服务端实例你可以理解为由一个Server+Client组成。也可以理解为两个容器,他们仅仅在初始化时是一样的ip,端口号,名字等。没有什么其他的联系。
然后我们设置的两个属性: registerWithEureka 和 fetchRegistry 也是对这个实例的client端的配置。
- registerWithEureka :是否要注册到其他Server上。如果我的Server上有一些对外开放的接口,那肯定需要注册啦~这样其他的Client才能发现我的服务。如果我的Server没有提供对外接口,那么这个参数可以设置为false。
- fetchRegistry :是否需要拉取服务信息。和是否注册一样,如果我的Server需要以客户端的身份调用其他的Client的接口,那么就需要获取相应的服务发现信息,这样才能正常的调用。同时这个参数还有一个重要的作用,就是决定Server在初始化时是否立即全量同步其他节点的服务信息!!!Server初始化时会先初始化其内置的Client。若配置了fetchRegistry=true,那么Client在初始化时会从其他Server全量拉取服务信息,放进Client容器中。Server在初始化时会尝试同步Client容器里的服务信息,如果fetchRegistry=false,服务信息不存在,只能被动的等其他Server节点以增量的形式同步过来(Client在执行注册和心跳时对应的注册Server节点会广播此事件,同步给其他的Server节点。当其他Server节点还没有此服务信息时,改为注册此服务信息)。当然正常的通过心跳来同步也可以,是否需要设置此参数就看各自的需求了。
这涉及到了Server节点间的同步机制—— Client在与Server交互时,只会与其中的一个Server进行交互 。
是个比较绕的事,所以我这里还是用图来解释。
因为上个图节点间关系比较简单不能说明问题,所以我这加了两个客户端和一个服务端。如图上关系。
-首先 Server4 与 Server1 互相注册了。所以我们可以通过 Server1 调用 Client3( 这是是指直接通过 ) 。也就是 Client4 可以发现 Client3。
-然后注意,重点来了! Server1 与 Server3,Server4 都相互注册了,但是 Server3 和 Server4 没有相互注册,所以 Client3 和 Client2 是互相发现不了的。
-刚刚画的各种问题,我还得加一笔。(看下图理解我说的话)如果 client2 也在 Server1 上注册了 , 因为 Server节点间的同步机制 所以 Client2 只能会与 1,3 中一个交互。
——如果它与 Server1 交互,这个时候是可以发现 Client3 的。
——但是如果它与 Server3 交互,则发现不了 Client3
-还有一种情况。 Server4 down了。理论上讲 Client3 就失联了。不过因为 Server1 中还有c3的信息,所以在Server1中还是可以暂时用用Client3的但是因为client3不会续约所以时间到了就会被踢了(默认90s不续约就踢了)。至于 Client3 自己,如果在那之前它用过谁还可以继续用~~不过就不动态了,别人发生的变化它得不到通知,而且后续新增的其他服务它也发现不了。
其实这个用一种现实关系打比喻:Server是人。Client是东西。然后东西的给予规则就是只能给信任的人”自己“的东西。所谓的发现就是在讲个东西在一个人家里。
这么想, S1 信任 S2,S3,S4 所以C4可以在任何人家里。所以 C4 可以与 C1,C2,C3 都交互。
然后 S4 只信任 S1 ,所以 C3 只会在 S4 或者 S1 家里出现。所以 C3 只能与 S1 家里的 C4,C2 交互(反过来想也可以,反正就这个意思)。
然后通俗理解可以这么理解。但是其实形成的原因是 :Server之间的服务同步是异步执行的。同时Server之间的同步只会传播一次,它们通过Header里的一个参数来表名是来自Client的请求还是Server的请求。如果是Server的请求,那么接收到此请求后不会再进行传播。 所以可以理解是一条线走下来的。这也是 client2 与 Server3 交互,则发现不了Client3的原因。
言语表达太无能了~~原谅我语文不好。差不多一天才把语言组织好~~然后我也是看官网做demo还有看各种帖子得出的结论。如果哪里理解错了或者说错了有偏颇欢迎指出纠错~~~欢迎各位留言探讨~~
咋说呢,从概念上首先你要明白什么是自我保护机制。如果有不懂的可以戳我前两篇文章:
什么是自我保护机制: eureka术语详解
设置自我保护机制: eureka配置详解
这里要说明的是一个很容易出现又容易被人忽略的问题:我们的微服务可能就几个。比如说5个,然后其中一个down了。eureka的默认阙值是85%。也就是低于百分之八十五的正常率就触发自我保护机制开始怀疑人生了~~所以说五个down一个直接到百分之八十。完了,eureka也不踢人了~你说这个服务信息回收不是用来搞笑的么?所以说这个时候我们要自己设置阙值了。可以修改成适当的值,比如05之类的!要根据具体情况来判断。(这个其实和集群实现关系不大,主要是因为我在这坑了~所以提出来说一下~~本来都预计收尾了又想起来这么个事~我这可怜的排版啊)
全文手打,连都是手画的~~~这么不容易的写个文~~如果你觉得用到了理解了~不留个言点个赞转个发什么的合适么?~
以上就是关于字节三面:到底知不知道什么是Eureka全部的内容,包括:字节三面:到底知不知道什么是Eureka、Spring Cloud之Eureka源码分析2、SpringCloud之Eureka Feign简介等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)