Springboot服务启动卡死?!

390 阅读4分钟

晚上8.30即将下班,正准备开始摸会鱼,驻场的同事电话就打过来了,得嘞,这鱼是摸不成了。接起电话,同事反馈现场生产环境某服务起不来了,但是同一个镜像测试环境正常运行,而生产环境已经重启3、4次了,遂开启视频远程支持。

现象

观察pod状态一直处于 running 0/1状态,并且在重启次数可以看到已经被重启3次了。(客户现场没法截图,这里p了一张)

describe下pod,可以看到connect 127.0.0.1:8080 connect refused。显然是服务没起来导致健康检查未通过。

直接查看pod的日志可以看到日志一直卡在了 Root WebApplicationContext: initialization completed in xxxx ms 一行,这里使用本地的日志用作表示。

排查

按照日常的经验,一般在输出完这行日志后是创建数据库连接池的流程,遂怀疑是数据库连接不上,可能连接耗尽了,或者可用连接数小于druid连接池大小,这点也较符合上面的现象,可能测试环境数据库连接占用少,而生产环境占用多导致服务连接不上。但是又觉得奇怪,就算是连接不上,日志中应该也会有类似于connection refused的报错才对。

遂让现场的同事查看数据库连接状况

# 查看当前连接数
show status like 'threads_connected';
# 查看最大连接数
show VARIABLES like 'max_connections';

不出意外地,当前连接数远小于最大连接数。(这里截图也以本地作为示例)

既然不是数据库的问题,也不是代码的问题,毕竟同一个镜像测试环境服务正常运行。看起来似乎毫无头绪了,突然,死去的记忆复苏了,springboot可以配置日志等级到debug(原谅我太久没看debug日志了),于是让同事修改配置重启服务。

logging:
  root:
    level: debug

重启后日志中果然出现了端倪,关键异常在org.apache.tomcat.jni.LibraryNotFoundError。 Can't load library: /bin/liblibtcnative-2.so, Can't load library:... 。嗯?加载不到动态链接库?遂让同学查看了pod所在节点,发现节点是今天新加入的,遂咨询同事这台机器的操作系统,得到答复麒麟,终于找到问题的根因了。

main] o.a.catalina.core.AprLifecycleListener   : The Apache Tomcat Native library could not be found using names [tcnative-2, libtcnative-2, tcnative-1, libtcnative-1] on the java.library.path [/usr/java/packages/lib:/usr/lib64:/lib64:/lib:/usr/lib]. The errors reported were [Can't load library: /bin/libtcnative-2.so, Can't load library: /bin/liblibtcnative-2.so, Can't load library: /bin/libtcnative-1.so, Can't load library: /bin/liblibtcnative-1.so, no tcnative-2 in java.library.path: [/usr/java/packages/lib, /usr/lib64, /lib64, /lib, /usr/lib], no libtcnative-2 in java.library.path: [/usr/java/packages/lib, /usr/lib64, /lib64, /lib, /usr/lib], no tcnative-1 in java.library.path: [/usr/java/packages/lib, /usr/lib64, /lib64, /lib, /usr/lib], no libtcnative-1 in java.library.path: [/usr/java/packages/lib, /usr/lib64, /lib64, /lib, /usr/lib]]

org.apache.tomcat.jni.LibraryNotFoundError: Can't load library: /bin/libtcnative-2.so, Can't load library: /bin/liblibtcnative-2.so, Can't load library: /bin/libtcnative-1.so, Can't load library: /bin/liblibtcnative-1.so, no tcnative-2 in java.library.path: [/usr/java/packages/lib, /usr/lib64, /lib64, /lib, /usr/lib], no libtcnative-2 in java.library.path: [/usr/java/packages/lib, /usr/lib64, /lib64, /lib, /usr/lib], no tcnative-1 in java.library.path: [/usr/java/packages/lib, /usr/lib64, /lib64, /lib, /usr/lib], no libtcnative-1 in java.library.path: [/usr/java/packages/lib, /usr/lib64, /lib64, /lib, /usr/lib]
        at org.apache.tomcat.jni.Library.<init>(Library.java:93)
        at org.apache.tomcat.jni.Library.initialize(Library.java:234)
        at org.apache.catalina.core.AprLifecycleListener.init(AprLifecycleListener.java:201)
        at org.apache.catalina.core.AprLifecycleListener.isAprAvailable(AprLifecycleListener.java:112)
        at org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory.getDefaultLifecycleListeners(TomcatServletWebServerFactory.java:174)
        at org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory.<init>(TomcatServletWebServerFactory.java:121)
        at org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryConfiguration$EmbeddedTomc

稍微百度下也能够找到类似的报错

最终,为了防止服务被调度到新加入的节点上,让同事给新加的麒麟系统的节点加上污点,让服务调度到老的节点上,服务正常运行。

回顾事件起始,让我感觉比较坑爹的是这么严重的错误,tomcat居然没有打印error级别的日志。还有就是在发现客观问题的根因前,不要妄加猜测,先通过现有的一切手段找到问题根因,实在找不到再去大胆猜。

添加污点

在 Kubernetes 中,给节点加上污点(taint)可以防止特定的 Pod 被调度到该节点。你可以使用 kubectl taint nodes 命令为节点添加污点。以下是步骤:

kubectl taint nodes <node-name> key=value:taint-effect
  • <node-name>:你要加污点的节点名称。
  • key=value:污点的键和值。
  • taint-effect:污点的影响,可能的值有:
    • NoSchedule:新的 Pod 不会被调度到该节点。
    • PreferNoSchedule:尽量不调度 Pod 到该节点,但不强制。
    • NoExecute:会驱逐已经存在的 Pod,并阻止新的 Pod 调度。