解决zookeeper导致tomcat停止时报异常的问题

问题由来

今天运行工程时,发现停止tomcat时,发现控制台会报一些错误。

十二月 09, 2016 9:25:14 上午 org.apache.coyote.AbstractProtocol stop
信息: Stopping ProtocolHandler ["http-apr-8080"]
十二月 09, 2016 9:25:14 上午 org.apache.catalina.loader.WebappClassLoaderBase loadClass
信息: Illegal access: this web application instance has been stopped already.  Could not load org.apache.zookeeper.server.ZooTrace.  The eventual following stack trace is caused by an error thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access, and has no functional impact.
java.lang.IllegalStateException
	at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1747)
	at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1705)
	at org.apache.zookeeper.ClientCnxn$SendThread.run(ClientCnxn.java:1128)

十二月 09, 2016 9:25:14 上午 org.apache.catalina.loader.WebappClassLoaderBase loadClass
信息: Illegal access: this web application instance has been stopped already.  Could not load org.apache.log4j.spi.ThrowableInformation.  The eventual following stack trace is caused by an error thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access, and has no functional impact.
java.lang.IllegalStateException
	at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1747)
	at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1705)
	at org.apache.log4j.spi.LoggingEvent.<init>(LoggingEvent.java:165)
	at org.apache.log4j.Category.forcedLog(Category.java:391)
	at org.apache.log4j.Category.log(Category.java:856)
	at org.slf4j.impl.Log4jLoggerAdapter.error(Log4jLoggerAdapter.java:576)
	at org.apache.zookeeper.ClientCnxn$1.uncaughtException(ClientCnxn.java:414)
	at java.lang.Thread.dispatchUncaughtException(Thread.java:1986)

分析原因

框架时使用CuratorFramework连接zookeeper的,在spring bean销毁时也正确的关闭了zookeeper连接。

1

curatorFramework.close();

但跟踪代码发现curatorFramework关闭时会调用org.apache.curator.CuratorZookeeperClient#close,之后会org.apache.curator.ConnectionState#close,再之后会调到org.apache.curator.HandleHolder#closeAndClear,再之后会调到org.apache.curator.HandleHolder#internalClose,再之后会调到org.apache.zookeeper.ZooKeeper#close,再之后会调到org.apache.zookeeper.ClientCnxn#close,再之后再调到org.apache.zookeeper.ClientCnxn#disconnect,再之后会调到org.apache.zookeeper.ClientCnxn.SendThread#close。

org/apache/zookeeper/ClientCnxn.java:1311

void close() {
    state = States.CLOSED;
    clientCnxnSocke.wakeupCnxn();
}

这样仅仅只是修改了SendThread线程内部的变量,并没有等SendThread完全退出。 这样就存在spring bean销毁了,但SendThread线程还活着的场景。spring容器退出后,tomcat将该web应用标识为stopped,该web应用的classloader也不再可用。这时SendThread线程执行时要从该web应用的classloader里加载类时,就会报上面的错。

解决方案

这个问题本质上应该是zookeeper-3.4.8.jar的bug, 关闭zookeeper时,并没有等待SendThread线程完全退出。但项目中不太好直接修改zookeeper的源码,因此从封装的框架层面解决此问题。

public synchronized void destroy() {
    try {
        if (nodepath != null) {
            curatorFramework.delete().forPath(nodepath);
            LOGGER.info("ZK Close,Path:{}", nodepath);
        }


    } catch (Exception e) {
        LOGGER.error("Couldn't Delete Registry Node", e);
    }

    try {
        curatorFramework.close();
        //等待zookeeper的相关线程完全退出
        synchronized (curatorFramework){
            curatorFramework.wait(500L);
        }
    } catch (Exception e){
        LOGGER.error("Close Registry Error", e);
    }
}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏木宛城主

两天完成一个小型工程报价系统(三层架构)

花了两天,整理了一下三层架构,顺便练了一个小型三层架构——工程报价系统。 功能很简单,完成基本的增删改查 搭建项目三层结构 ? 界面的设计以及美化 ...

36690
来自专栏张高兴的博客

张高兴的 Windows 10 IoT 开发笔记:串口红外编解码模块 YS-IRTM

15030
来自专栏.NET开发那点事

.NET开源高性能Socket通信中间件Helios介绍及演示

  Helios是一套高性能的Socket通信中间件,使用C#编写。Helios的开发受到Netty的启发,使用非阻塞的事件驱动模型架构来实现高并发高吞吐量。H...

25120
来自专栏函数式编程语言及工具

Akka(29): Http:Server-Side-Api,Low-Level-Api

 Akka-http针对Connection的两头都提供了方便编程的Api,分别是Server-Side-Api和Client-Side-Api。通过这两个Ap...

21980
来自专栏菩提树下的杨过

msmq发送速度的测试

在一些并发量比较高的"中小型"应用中,如果短期内有大量的数据插入,利用msmq中转是一个不错的选择(petshop就是这么干的),想知道msmq一秒钟内到底能...

26890
来自专栏魏琼东

本人为巨杉数据库(开源NoSQL)写的C#驱动,支持Linq,全部开源,已提交github

     这些年在做AgileEAS.NET SOA 中间件平台的推广、技术咨询服务过程之中,特别是针对我们最熟悉的医疗行业应用之中,针对大数据分析,大并发性能...

11900
来自专栏ASP.NET MVC5 后台权限管理系统

构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(8)-MVC与EasyUI DataGrid 分页

前言 为了符合后面更新后的重构系统,文章于2016-11-1日重写 EasyUI Datagrid在加载的时候会提交一些分页的信息到后台,我们需要根据这些信...

37370
来自专栏c#开发者

MVC 5 Scaffolder + EntityFramework+UnitOfWork Pattern 代码生成工具集成Visual Studio 2013

MVC 5 Scaffolder + EntityFramework+UnitOfWork Pattern 代码生成工具 经过一个多星期的努力总算完成了单表,多...

470130
来自专栏飞扬的花生

Html5上传插件封装

      前段时间将flash的上传控件替换成使用纯js实现的,在此记录 1.创建标签 <div class="camera-area" style="dis...

43180
来自专栏丑胖侠

《Drools7.0.0.Final规则引擎教程》第4章 4.3 日历

日历 日历可以单独应用于规则中,也可以和timer结合使用在规则中使用。通过属性calendars来定义日历。如果是多个日历,则不同日历之间用逗号进行分割。 在...

297100

扫码关注云+社区

领取腾讯云代金券