Eureka 一般是springcloud 的第一个要学习使用的模块.

这个模块的特点是几乎没有代码,上来就运行,然后没有代码并不意味着开发者就很轻松,

很多东西看上去简单,背后会有很多的问题

之前出差在甲方的升级的时候就遇到一个问题

https://blog.csdn.net/a897180673/article/details/83280477

当时的情况:
测试环境每个微服务都部署了2台搞了集群,为了测试方便,抓紧时间回去,当时和测试把每个微服务都启动一台,测试没问题就把2台都起来
我们想象着所有的请求都会路由到启动的微服务.

然后事实打脸

在这里插入图片描述

eureka 就是把请求路由到没有启动的微服务上面,可是服务都没有起来啊,结果可想而知,请求肯定没有数据.

当时时间紧急,没办法,把2台都启动起来 给测试进行测试,当时候还不知道是eureka 的问题

后来和头头聊过这个事情,头头说是eureka 的心跳机制的问题

在到后来,在慕课上面分享了springcloud 的开发经验,有一个用过springcloud 的人和我分享了一些springcloud 的开发经验

在谈到上面的问题时,他说要优雅的关闭微服务,不要使用kill -9

怎么样才叫优雅的关闭了?

在我们学习c++的时候有个函数叫做析构函数,专门用来清除销毁对象
在java 中也有垃圾的回收机制

我对优雅关闭的理解就是:每个对象,或者工程都有他的生命周期,像人一样从出生到死亡,你启动jar 用java -jar 没有错,

但是关闭的时候,直接非常粗暴的关掉了,根本就没有让 java 去做一些善后处理工作.那这样肯定能是要回出问题的.

看一下kill -9的解释:

https://www.cnblogs.com/grefr/p/6088521.html

kill -9


ok,回到正题,后来我通过慢慢的学习了解,这个和Eureka 自我保护模式有关

今天我们来聊聊这个问题

统一环境: SpringBoot 2.1.3.RELEASE

相关代码上传git仓库:
eurekaServer:https://github.com/897180673/EurekaTest
eurekaClient: https://github.com/897180673/EurekaClient

Eureka的自我保护模式的开启,会让不发送心跳的微服务仍然处于在线模式,Eureka不会把它从注册列表踢掉

先把EurekaServer启动起来,过一会访问EurekaServer的界面,注意要过一会再访问

先看下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.

翻译一下:

注意,Eureka可能会错误的将已经下线的实例申明为上线,续订低于阈值因此实例不会过期,仅仅是为了安全起见

这句话比较拗口,但是大概的意思就是,即使微服务挂掉了,我Eureka也会说他没有挂掉,这个是为了安全考虑.
在这里插入图片描述

WTF,为了啥安全? 怎么就安全了?既然微服务下线了,Eureka你直接说微服务下线不就行了,微服务上线,你就请求路由到上线的微服务这不就行了?

为什么需要搞这一套了?

直觉告诉我事情肯定没有那么的简单,既然他弄了肯定会有他的道理

查了一些资料,看了一些介绍,大概的意思就是为了防止网络阻塞的问题

想象一个场景,以前在农村的小黑网吧里面,也就2m的网络 大概也就200kb/s的下载速度,却要给4-6台左右的电脑使用,带宽就比较的紧张了的,我以前在农村网吧上网的时候,老板就说,不要开迅雷下载啊,影响大家玩游戏

这个时候游戏服务器就相当于是Eureka,想一想,如果有人在网吧下载东西,导致其他的几个人网卡,玩游戏连接不了服务器,那么游戏服务器该怎么办呢?

立刻判断用户已经下线?

当然不是,比如最近的手机 吃鸡游戏 刺激战场,在网络卡的情况下是提醒再次等待连接,多次连接不行才让你下线重新登录.
在这里插入图片描述

所以Eureka也是这个道理.只不过他的保护模式有点过头了.

他为什么要这么保护么?

我们没有看源码只能猜测下:我觉得可能有这几种情况,一种是体验不好,如果网络环境糟糕,频繁上下线会很麻烦,
在游戏中本身就存在很多的用户的上线和下线行为,游戏服务器必定会对此做一些优化,但是微服务是跑得应用怎么能随随便便的下线了,尽管对于EurekaServer而言,微服务是Client端,但是对于前端而言,他们都是Server,必须要稳定

第二个就是浪费时间,Tcp通信都还要3次握手,频繁的通信断开连接,时间大量的花费在沟通上,得不偿失.


ok,我们接着聊

前几天甲方的开发找到我突然聊到eureka不下线的问题,当时候我给的解决方法是eurekaServer添加一个配置

eureka.server.enable-self-preservation=false

这样可以取消EurekaServer的自我保护模式

可是甲方的开发说,他之前在测试的并没有在eurekaServer 的配置文件中添加什么配置,也可以实现自动的下线.

这个问题引起了我的注意,最终通过实践发现了问题,也是我最终要写下这个博客的原因.

那么为什么他没有配置自我保护却可以自动下线了?

我没有具体的问甲方开发的测试的情况,但我觉的他应该是在本地测试的.

那么为什么在本地测试就ok了?

因为他的微服务完整了走完了微服务的生命周期.

这一点很重要.

我们来做一个测试:

1.删除EurekaServer自我保护的配置

2.在idea中启动EurekaServer,并注意观察日志
在这里插入图片描述

3.在idea中启动EurekaClient,并注意观察EurekaClent日志

在这里插入图片描述

EurekaClient在日志中已经说明了 去注册了

看下 EurekaServer的信息

在这里插入图片描述

EurekaServer也说明了接收到一个注册的请求.

4.看下Eureka的Server 的web界面

在这里插入图片描述

这一会界面上没有红色的大写字母了,不过放心,一会就回出现了,只不过我截图比较早而已

这一次我加上了一个红框,注意看下他的值

我想说的是这个值不是一成不变的,这个值是动态变化的,尽管他现在是false.

我们在idea中关掉EurekaClient应用,关掉应用后, 过了t2时间,迅速的切换到EurekaServer 的web页面,如下:

在这里插入图片描述

神奇的事情发生了,注意看右上角的红框,他是true了 (再过一会又会变成false) ,并且下面注册的微服务也下线了.

这个情况就是甲方开发所说的情况了,为什么会这样了?

注意看下idea 的日志,从日志中找到答案

先看EurekaClient 的:
在这里插入图片描述

再看EurekaServer 的:

在这里插入图片描述

所以是不是知道原因了?

因为他们是通过idea关闭,idea让他们正常的走了应用消亡的生命周期,让资源得到了回收.

而之前了?都是非常粗暴的kill -9杀进程这样是非常不可取的,具体的大家可以测试下,如果是杀进程的话,是没有这样的日志输出的.

这个也恰好解释了为什么上了甲方的caas后依旧不下线的问题

虽然我们是开发不太了解k8s具体的是怎么控制容器关闭的,但是我可以肯定,一定没有让容器里面的springboot正常的走完生命周期. 推测是k8s非常粗暴的杀掉了docker的容器.导致EurekaServer认为运行微服务的docker还在,一定是因为网络原因才没有注册.

这么一看Eureka其实也不是那么不智能,只要我们能够规范开发都是没有问题的.

ok,再补一点吧,在现实的环境中总会有不可预知的问题发生,如果Eureka就是不下线微服务怎么办了?

这里有2中方法提供参考下

1.手动通知Eureka下线,这个之前懒,一直没有找,这次特地找了试了一下
向EurekaServer发送一个http请求就ok

DELETE /eureka/apps/appID/instanceID

比如:

DELETE  127.0.0.1:8761/eureka/apps/EUREKACLIENT1/192.168.10.104:eurekaClient1:8765

记住是delete请求

通过这种方式下线的时间是t3

参考:https://blog.csdn.net/zhxdick/article/details/78517021

2.通过运行指定的代码下线
在EurekaClient的代码中添加一个接口

    @GetMapping(  "/offline" )
    public void offLine(){
        DiscoveryManager.getInstance().shutdownComponent();
    }

通过这种方式下线的时间是t4

只要访问这个接口就可以实现下线的功能.

这两种方法亲测有效,大家可以试试

好了这里一共用到了4个时间,根据我自己的测试t1的时间是要大于t2 ,t3和t4 的 也就是说你关闭的自我保护,EurekaServe踢掉下线微服务的时间是比较长的,当你打开自我保护,并且规范开发,反而可以做到更快的下线已经停掉的微服务

最后来聊一聊要不要关闭EurekaServer的自我保护模式吧

网上有人建议,测试关闭,生产打开,因为,测试要实时响应所以关闭,生产要稳定所以不关闭,默认就好

我个人建议都不要关闭,因为EurekaServer本身就已经做了非常完善的下线机制,而且下线的时间还是非常快的.

只要规范开发,打开自我保护响应时间就是比关闭自我保护响应时间短

我自己测试了一下 ,kill pid 是可以让微服务走完生命周期的,不要用kill -9

所以打开EurekaServer的保护模式+kill pid 是一个不错的选择

至于k8s管理的docker,k8s一定有一套控制docker生命周期的方式,好好控制下就ok

k8s这个技术比较的新,如果难于找到文档,可以在微服务中加接口,用脚本访问接口去下线,或者用脚本去通知EurekaServer

下线也是不错的选择


ok,到这里也就结束了,最后聊聊感想和总结吧

出现这个问题的本质原因还是没有做到规范开发

EurekaServer本身我觉的做的还是不错的,

大学里面看韩顺平老师讲servlet的课程的时候,当时候老师演示的是Tomcat 的服务器

老师点击的startup.bat启动,当时老师说了一下,关闭不应该直接关掉startup.bat的窗口,
而是应该运行shutdown.bat 关闭Tomcat

后来到中投出差的时候,我关闭 linux 上面的tomcat的时候运行了 shutdown.sh
可是奇怪了tomcat 好像没有停掉,这个时候我旁边的同事说,这个好办你应该这么关

ps -ef | grep tomcat 

然后

 kill -9 pid

我一看还真的关了,从那个时候起,我就一直这么关应用,也一直都没有发现什么问题

一直到接触到Eureka 的这个问题

你说这个问题怪谁,怪EurekaServer设计的不够好?还是应该怪开发粗暴开发?

我觉的应该是后者

应用的启动和关闭应该像人一样从出生到死亡有一个过程,而不是突然一刀砍头,从此杳无音讯

虽然以后在一些环境中为了一时爽快可能还会使用kill -9

但是我们要强烈谴责这种行为

在这里插入图片描述

还有一个就是要养成看日志的习惯,其实各种上线下线的问题EurekaServer和EurekaClient的日志都已经告诉你了

还有Eureka的Server,人家还贴心的给你做了一个web的可视化界面

只要你认真去看一下,就可以知道答案

当时由于甲方内网的严格控制,所以一直都没有想到去看,只能瞎猜,可惜啊,要命。

ok 就到这里吧。

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐