在Tomcat启动逻辑相关脚本bin/catalina.sh里面加上启动参数,打印Class加载的日志:
JAVA_OPTS="$JAVA_OPTS -verbose:class"
可以看到:
... [Loaded io.netty.buffer.PoolThreadCache$MemoryRegionCache from file:$WEBAPP-DIR/WEB-INF/lib/WEB-INF/lib/netty-buffer-4.1.5.Final.jar] ... [Loaded io.netty.util.internal.MathUtil from file:$WEBAPP-DIR/WEB-INF/lib/netty-all-4.1.4.Final.jar] ...
从netty-all-4.1.4.Final.jar中加载的io.netty.util.internal.MathUtil,是没有safeFindNextPositivePowerOfTwo这个方法的(正常情况下,应该从netty-common-4.1.5.Final.jar中加载这个类)。
至此为止,弄清楚了启动卡住的原因:
Netty包加载问题 => Xxx调用channel.writeAndFlush发送注册请求时异常 => 没有回包,future.get()一直卡住 => Tomcat启动线程卡住
还有一个令人费解的现象:为什么有的机器启动正常,有的机器启动不正常呢?
5. 不同机器表现不同
再回头看一下启动有问题的机器上Netty相关jar包的顺序,这里我们使用ls -f命令(只关注和问题相关的jar包):
$ ls -f |grep netty netty-buffer-4.1.5.Final.jar netty-all-4.1.4.Final.jar ... netty-common-4.1.5.Final.jar ...
ls加-f参数的含义可以通过man手册看到:
-f do not sort, enable -aU, disable -ls --color
意思是直接使用系统调用getdents的返回,不再做排序。从man手册可以看到,ls默认排序方法是Sort entries alphabetically if none。
NoSuchMethodError的原因是:从netty-buffer-4.1.5.Final.jar中加载了io.netty.buffer.PoolThreadCache$MemoryRegionCache,这个类是会调用io.netty.util.internal.MathUtil.safeFindNextPositivePowerOfTwo这个方法的;从netty-all-4.1.4.Final.jar加载的io.netty.util.internal.MathUtil没有这个方法。
对比看下启动正确的机器上的Netty相关jar包的顺序:
$ ls -f |grep netty ... netty-all-4.1.4.Final.jar ... netty-common-4.1.5.Final.jar netty-buffer-4.1.5.Final.jar ...
由此可以看出所有Netty相关的Class均从netty-all-4.1.4.Final.jar中加载,不会有不兼容的问题产生。
要么问题来了:为什么在ext4中,拥有相同目录项的目录,ls -f出来的顺序是不一样的呢?
这个问题我暂时也回答不上来,至少我还没有拿到令自己信服的代码级别的解释。
嗯,没有代码的解释不是解释,没有deadline的任务不是任务,没有流程图或分享的源码阅读不是源码阅读,没有报告的性能测试不是性能测试。
这里有一个基于现象的解释,我觉得还比较靠谱:
On modern filesystems where directory data structures are based on a search tree or hash table, the order is practically unpredictable.









