Eureka Client关闭后要被同步到其他Client需要等待多久

问:Eureka Client关闭后要被同步到其他Client需要等待多久?

1. 死的服务让eureka server确认它是死了,那就是3次heartbeat的时间3*30=90s

2. 新的服务要去重新刷新cache 的时间30s, 如果一次刷新连接服务器,也会尝试重新刷新

那么总的算下来应该坏的情况是> 90 + 30 = 120s

那么有办法优化吗?我们期望降低等待时间

以前在服务停止之后,eureka server需要3个heartbeat(30s*3),即一分半的时间才会把已经停止的eureka client从eureka server上拿掉,这对白天上线和日常测试都带来不小的麻烦。

其实eureka client中已经实现了使用@PreDestroy注解的shutdown hook方法(DiscoveryClient类的shutdown方法),会在服务停止的时候自动从eureka server上unregister。

但之前ECS和Docker的服务实例在实际开发中都没有收益于这个shutdown hook,下面解释一下之前两个环境均不能实现unregister的原因。

IN ECS 

老ECS服务的停止多使用kill -9,kill -9不会调用JVM中注册的shutdown hook,所以在服务停止之后仍需等待3个heartbeat。而使用kill命令则会给服务的shutdown hook留下时间,让服务完成unregister。

所以ECS方面只要不使用kill -9命令停止实例,就可以实现服务停止时的自动unregister。

用法以service-xxx为例:ps ax | grep java | grep app.name=service-xxx | grep -v grep | awk '{print $1}' | xargs kill -SIGTERM

IN DOCKER

在docker中,如果使用docker stop停止服务(阿里云控制台的停止操作同理),会先向容器中PID为1的进程发送系统信号SIGTERM,然后等待容器中的应用程序终止执行,如果等待时间达到设定的超时时间,或者默认的10秒,会继续发送SIGKILL的系统信号强行kill掉进程。在容器中的应用程序,可以选择忽略和不处理SIGTERM信号,不过一旦达到超时时间,程序就会被系统强行kill掉,因为SIGKILL信号是直接发往系统内核的,应用程序没有机会去处理它。

所以如果我们的服务进程能接收到SIGTERM信号,就可以实现shutdown hook来进行unregister,但目前的run.sh脚本中使用java ${JAVA_OPTS} -jar app.jar来启动服务,这样会使得服务的进程PID不为1,如下图所示,PID为1的进程是bash ./run.sh。而服务进程的PID为75,所以目前我们的服务进程接收不到这个SIGTERM信号,导致了shutdown hook没有被调用,进程直接被杀死。


改进方法是将run.sh中的java ${JAVA_OPTS} -jar app.jar改成exec java ${JAVA_OPTS} -jar app.jar,在命令前加上exec,就可以将服务进程的PID变为1,这样在容器进行重启,停止等操作的时候,会自动从eureka server上把自己unregister掉。

比如在arch-demo应用中测试通过,改进后的容器内进程如下图:

 

 

ref 1 : https://stackoverflow.com/questions/31836498/sigterm-not-received-by-java-process-using-docker-stop-and-the-official-java-i

ref 2 : http://veithen.github.io/2014/11/16/sigterm-propagation.html


你可能感兴趣的:(微服务实践之路)