今天遇到一个Eureka集群的一个坑。
问题现场类似是这样的:两台Eureka组成的服务注册中心集群,两台服务提供方server1、server2,两个服务调用方client1、client2。
正常的情况下:
client1和client2通过服务中心获取的服务提供方的注册的元数据信息,然后本地缓存调用server2、server1的服务API是没问题的。调用server的api服务时采用的FeignClient通过eureka注册中心获取服务信息调用。
以下简写成client服务、server服务、eureka服务:
但今天遇到的情况是client调用server时,返回结果不稳定,以下是排查过程。
1、习惯性的先查看client方日志,发现接口调用有一定的概率失败,但是并没有抛异常,而仅仅是response返回null。
2、查看server方日志,并没有发现异常,也没有发现response为null的情况,并且server方的本机上访问接口都是响应正常。
3、通过分析两方日志,猜想client端的请求可能没有打到server方。
4、分析整个调用流程,只差eureka服务这一个环节没有排查了,然后查看eureka服务上的server方注册信息是否正常。
5、发现两台eureka服务,有一台tomcat假死了,至此猜想是假死的eureka服务假死所致。
6、验证猜想,重启假死的eureka的tomcat服务,问题验证解决。
那么问题来了,
1、为了一台eureka假死了,没有抛异常,只在response中返回个null?
2、eureka集群的一台实例假死,为什么会导致服务间调用不稳定?
3、eureka服务跑了大半年,怎么突然一台实例假死了?
接下来,我们来探讨这三个问题。
1、为了一台eureka假死了,没有抛异常,只在response中返回个null?
这个问题经查,eureka假死,导致调用方调用服务方时,触发了hystrix熔断器,项目实现的熔断降级接口直接在熔断自动降级时返回null,这就回答了第一个问题。
2、eureka集群的一台实例假死,为什么会导致服务间调用不稳定?
这个得翻看一下eureka的机制源码了,猜想feign端在本地缓存90s后去刷新本地服务列表信息时,卡在调用eureka服务上了(此时恰好通过假死的eureka服务刷新),从而服务不可用。
3、eureka服务跑了大半年,怎么突然一台实例假死了?
生产环境有多台虚拟机eureka服务器,配置都一样,其它的服务器没有出过问题,只有一台eureka服务会有类似周期性假死的问题,由于笔者生产环境权限所限,只能猜想可能是宿主机的原因,估计换台机器可能就没问题了,待验证。
还有几个等思考的问题,之后待续。。。。。。。。。。。。。
1、服务提供方配置了多个eureka 地址,是服务注册时,是调用注册到哪个上? ---> 猜想优化使用第一个,那第二个是何时用到的(除了第一个宕机的情况)
2、feign接口通过eureka调用服务时,是不需要自己项目也注册到eureka上的,怎么处理?
3、服务调用方配置了多个eureka 地址,是获取服务列表调用时,是调用注册到哪个上? --> 猜想优化使用第一个,那第二个是何时用到的(除了第一个宕机的情况)
另外,昨天查eureka假死日志时,日志打的异常堆栈如下:
2019-06-13 18:07:58.907 INFO 23945 --- [a-EvictionTimer] c.n.e.registry.AbstractInstanceRegistry : Running the evict task with compensationTime 0ms
2019-06-13 18:08:04.949 ERROR 23945 --- [nio-8001-exec-5] o.s.boot.web.support.ErrorPageFilter : Forwarding to error page from request [/] due to exception [Filter execution threw an exception]
javax.servlet.ServletException: Filter execution threw an exception
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:255) [catalina.jar:8.0.30]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) [catalina.jar:8.0.30]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:101) [spring-web-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) [catalina.jar:8.0.30]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) [catalina.jar:8.0.30]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:101) [spring-web-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) [catalina.jar:8.0.30]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) [catalina.jar:8.0.30]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:101) [spring-web-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) [catalina.jar:8.0.30]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) [catalina.jar:8.0.30]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:101) [spring-web-4.3.5.RELEASE.jar:4.3.5.RELE