记录一次istio网络问题 导致Spring Boot 启动失败的问题

正文第一句——「本文已参与好文召集令活动,点击查看:后端、大前端双赛道投稿,2万元奖池等你挑战!

背景

上周二的时候 早上 还在上班的路途中,突然接到很多同事反馈 自己负责的任务调度系统DPP 页面打不开,登录 没法反应~

我第一反应是 后端的API 是不是挂了,赶紧打电话给了下运维,让运维看下 ,运维看了以后 服务的2个节点都不可用了,于是

我让运维重启服务看下,但是过了一会儿依旧不能解决问题,我立马飞速赶到公司~ 后来发现 从夜里2点多服务就不可用了!

过程

找问题

到了公司以后 看到K8S 的监控kuboard 里面 从日志上看 一直提示 服务健康检查不过,然后去进入容器最终了服务的日志

发现 服务启动失败了

image-20210702173011714.png

我从最近的日志 看到 提示 说 getAMQClient 的时候 错误了,我立马去查看了下代码

@Configuration
@ConfigurationProperties(prefix = "activemq")
public class AmqConfig {
    private String broker;
    private String username;
    private String password;
    public PooledConnectionFactory getAMQClient() {
        return ActiveMQUtils.init(broker, username, password, 20);
    }
}
复制代码

然后 我一直跟踪到堆栈信息里面发现最终的错误是这边的:

报错的堆栈信息:

java.lang.NullPointerException: null
        at java.net.URI$Parser.parse(URI.java:3042)
        at java.net.URI.<init>(URI.java:588)
        at org.apache.activemq.ActiveMQConnectionFactory.createURI(ActiveMQConnectionFactory.java:233)
        at org.apache.activemq.ActiveMQConnectionFactory.<init>(ActiveMQConnectionFactory.java:196)
        at com.patsnap.base.core.util.ActiveMQUtils.init(ActiveMQUtils.java:108)
        at com.patsnap.data.ms.beans.AmqConfig.getAMQClient(AmqConfig.java:46)
        at com.patsnap.data.ms.beans.AmqConfig$$EnhancerBySpringCGLIB$$684a548c.CGLIB$getAMQClient$14(<generated>)
        at com.patsnap.data.ms.beans.AmqConfig$$EnhancerBySpringCGLIB$$684a548c$$FastClassBySpringCGLIB$$20a5ed08.invoke(<generated>)
        at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:244)
        at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:363)
        at com.patsnap.data.ms.beans.AmqConfig$$EnhancerBySpringCGLIB$$684a548c.getAMQClient(<generated>)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154)
        ... 145 common frames omitted
复制代码
     /* 
     * @param  str   The string to be parsed into a URI
     *
     * @throws  NullPointerException
     *          If {@code str} is {@code null}
     *
     * @throws  URISyntaxException
     *          If the given string violates RFC&nbsp;2396, as augmented
     *          by the above deviations
     */ 
    public URI(String str) throws URISyntaxException {
        new Parser(str).parse(false);
    }
复制代码

看到此处 我个是基础的方法 怎么会报错呢~ 只有Str 为空 才会有这个情况呀~

这个时候我想到 我们的配置 都是从Spring Config 中获取过来的,我去看下Spring Config 的服务是否存在问题,我去看了下 服务正常 没有任务问题,此时已经过了20分钟,运维在容器中 把进程杀掉了,杀掉后 检测到服务不可用,k8s重启了2个节点后服务正常了~

此事我就很郁闷 为什么此前重启服务不行,后面为什么又可以了~问题依旧没有找到

到了下午 服务又挂了~ 我进入的服务 去看了下日志,报错的日志几乎都是一样,我又追踪了下日志 再日志最初的地方 发现了最终的问题

image-20210705102541197.png

发现程序启动的是 获取服务配置的时候 超时了,导致 后面的服务 启动的时候 初始化bean 的时候 失败!原来最终的问题 是这个~

找原因

那为什么获取不到配置呢?配置中心服务问题还是网络问题?

下面我去看了下配置中心 没有问题,然后我又在机器上telnet 了下 配置中心,发现网络没问题?那真的是太奇怪了

最后 我和OPS 那边 问了下 是不是 最近 调整过什么,OPS 和我说 前一天 确实调整过网络 但是应该和这个没关系

但是 往往说和这个没关系的 往往就是 这个导致的问题,最终果然就是这个问题

后面经过测试和分析,定位到就是网络的问题,原因是 OPS 那边 在每个容器里面加了一个 istio-proxy 网络的代理,来监控每个容器里面的流量,这个istio的网络代理服务 是和 java程序服务 运行在同一个容器中的, 但是 容器里面的服务存在 启动先后的问题,当istio-proxy这个代理服务 启动的晚的时候,我程序服务 访问 别的服务 是没法访问的,这就解释了 为什么 我程序启动的时候 访问config 服务失败的问题

那为什么 我们在程序里面通过kill java程序服务 就是可以的呢~ 原因是因为 当服务kill 调的时候 ,k8s 通过健康检查 监控到服务已经不可用,此此时会重新启动一个java程序服务节点,但是问题就出现在 istio-proxy 网络的服务和java程序的服务 的获取image 策略不一致 , java 的服务是每次都会获取image 代理服务是 如果机器上已经有这个image, 就不会重新拉取,这就会导致 有的机器 代理服务启动的快 就不会出现 java 服务 网络的问题。

再分析

通过上面的分析 问题的原因也找到了~,OPS 也做了修改了启动策略,让代理服务优先启动!

但是 后面又想OPS 提出了一个问题,为什么 服务启动不成功,健康检查一直不过,服务为什么没有去做重启,而是一直假死在那边夜里2 点多 服务已经不可用了

通过通过和OPS的沟通得知,判断服务的健康状况 是通过暴露的一个restful的API接口,但是判断这个服务是否存活是通过一个TCP 的连接,问题就出现在这里

image-20210622153623262.png

于是 我进入一个测试的环境。模拟了当时的情况 ,看到 虽然服务没有启动成功,但是对应的端口 是可以被开启了的,这就是导致了 通过tcp 直接socket 过来 是成功的~

后面OPS 也修改了这种判断策略~

image-20210705134607898.png

后面 我通过日志看到 在启动异常以后 有在 Stopping Tomcat Service 但是不知道为什么 这个端口 没有被关闭~

不知道 是不是 这个链接 里面说的的问题

总结

总结一下 主要是 还是找问题的方法 要精准的定位问题,把报错的信息 掌握清楚 然后去做分析,不能看到一个地方的错误就去判断~

在后面就是 知道了问题 要深耕 出现问题的原因,对现有的方案提出自己的想法和猜测!!!

时间问题,写的有点儿随意!!

在最后 也是巧了 就在出现问题的当天下午 ,InfoQ 微信公众号 推送了一遍文章关于Istio的,里面也说道了Istio 在运行代理前 会导致应用程序容器内的网络失效~

image-20210705135818019.png

文章链接:mp.weixin.qq.com/s/9x4XgAYGn…

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享