正文第一句——「本文已参与好文召集令活动,点击查看:后端、大前端双赛道投稿,2万元奖池等你挑战!」
背景
上周二的时候 早上 还在上班的路途中,突然接到很多同事反馈 自己负责的任务调度系统DPP 页面打不开,登录 没法反应~
我第一反应是 后端的API 是不是挂了,赶紧打电话给了下运维,让运维看下 ,运维看了以后 服务的2个节点都不可用了,于是
我让运维重启服务看下,但是过了一会儿依旧不能解决问题,我立马飞速赶到公司~ 后来发现 从夜里2点多服务就不可用了!
过程
找问题
到了公司以后 看到K8S 的监控kuboard 里面 从日志上看 一直提示 服务健康检查不过,然后去进入容器最终了服务的日志
发现 服务启动失败了
我从最近的日志 看到 提示 说 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 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个节点后服务正常了~
此事我就很郁闷 为什么此前重启服务不行,后面为什么又可以了~问题依旧没有找到
到了下午 服务又挂了~ 我进入的服务 去看了下日志,报错的日志几乎都是一样,我又追踪了下日志 再日志最初的地方 发现了最终的问题
发现程序启动的是 获取服务配置的时候 超时了,导致 后面的服务 启动的时候 初始化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 的连接,问题就出现在这里
于是 我进入一个测试的环境。模拟了当时的情况 ,看到 虽然服务没有启动成功,但是对应的端口 是可以被开启了的,这就是导致了 通过tcp 直接socket 过来 是成功的~
后面OPS 也修改了这种判断策略~
后面 我通过日志看到 在启动异常以后 有在 Stopping Tomcat Service 但是不知道为什么 这个端口 没有被关闭~
不知道 是不是 这个链接 里面说的的问题
- inux下,socket端口不能释放: blog.csdn.net/iteye_21202…
总结
总结一下 主要是 还是找问题的方法 要精准的定位问题,把报错的信息 掌握清楚 然后去做分析,不能看到一个地方的错误就去判断~
在后面就是 知道了问题 要深耕 出现问题的原因,对现有的方案提出自己的想法和猜测!!!
时间问题,写的有点儿随意!!
在最后 也是巧了 就在出现问题的当天下午 ,InfoQ 微信公众号 推送了一遍文章关于Istio的,里面也说道了Istio 在运行代理前 会导致应用程序容器内的网络失效~