背景:厂商反馈说中间件的客户端在被调用过程中不报错也不继续往下执行。
代码:分析得出的问题代码如下,在新建SDKClient实例时,将调用第二段代码构造器,但发现第二段代码中连第一个System.out.println都不打印。
SDKClient client = new SDKClient();
public SDKClient() {
System.out.println("before---LoadBalancer.getSingleInstance()");
balancer = LoadBalancer.getSingleInstance();
System.out.println("after---LoadBalancer.getSingleInstance()");
this.sdkHandler = new SDKClientHandler();
System.out.println("before---new FileCache()");
this.fileCache = new FileCache();
System.out.println("after---new FileCache()");
sdkHandler.setFileCache(fileCache);
}
分析过程:刚开始以为是客户端获取Zookeeper连接造成的,但是在服务端看zookeeper.out发现连接根本没有到服务端,让厂商在他们项目所在的机器上执行命令:wget [Zookeeper服务端主机号:Zookeeper服务端端口号] 发现连接能成功到Zookeeper服务端。 另:发现了隐藏的bug==》countDownLatch.await(),当Zookeeper客户端连不上服务端时,将造成无限等待,修改方向==》countDownLatch.await(30, TimeUnit.SECONDS);
public class AbstractZooKeeper implements Watcher {
private static final int SESSION_TIME = 31000;
protected ZooKeeper zooKeeper;
protected CountDownLatch countDownLatch;
public void connect(String host) {
try {
countDownLatch = new CountDownLatch(1);
zooKeeper = new ZooKeeper(host,SESSION_TIME,this);
countDownLatch.await();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void process(WatchedEvent event) {
if (event.getState() == KeeperState.SyncConnected) {
countDownLatch.countDown();
}
}
public void close() {
try {
zooKeeper.close();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
最终分析排查:自行打了个jar包到厂商服务器上运行,发现能成功脸上Zookeeper并获得数据。怀疑过类加载器的问题,但仔细想想不太可能,因为如果类加载器有问题,那么在程序启动时就应该报错了。观察厂商打包的方式发现是用mvn package 命令(本人此时20180717对maven不熟,没有在现场察觉到这可能是个问题),在网上查阅资料发现mvn package 是以缓存方式生成class到target然后打包,并在某篇文章上看到某同行也因为ROOT下缓存造成程序卡住不执行也不报错。虽然不太一样,但感觉mvn缓存很可能就是造成程序不报错也不往下执行的原因,遂让厂商执行下mvn clean再执行mvn package,最终,这个问题解决了...... 果然,“遇到问题先杀缓存”是有道理的
启发:当某个错误很离奇时,往往是某个细节造成的