欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

由RP编程联想到一个Apache Async Http Client的问题

程序员文章站 2022-07-14 16:17:13
...

最近RP编程很火,笔者也借机脑补了一下,借此跟之前工作时遇到的一个问题发生了关联···

 

The Four Reactive Principles

  • Responsive
  • Resilient
  • Scalable
  • Message Driven

 

其中便是第二点Resilient(弹性的、有复原力的),当看到这个原则时,立刻想起来不久前一个用户遇到的一个BUG便跟这个Resilient有关,并导致用户必须重启服务才能解决,到底是啥有趣的BUG呢,请容笔者细细道来。

 

某日,一业务开发同学(客户啊)邮件过来直接就问:我的服务发生OOM后经过一次FGC恢复了,但是我的I/O Rector has been shutdown之后就一直没法恢复了是怎么回事呀?是不是你们又搞出来一个BUG呀?收到邮件后仔细看了看,发现报错是从一个RxCachedThreadScheduler-36线程抛出来的信息,大意就是说无法处理请求了(异步请求),啥?RxJava?我们还没用到这玩意儿呢!看了看异常栈之后才顿然发现,其实跟这玩意没关系(注:这个是tomcat自身的一个守护线程,采用观察者模式,一旦IO thread 发生crush后会记录日志通知用户,此处省略一万字···)

 

仔细看了看代码之后发现,我们在处理async http request的时候用了apache async client包,正是这个包在处理代码时一旦进入STOPED状态后,将无法再次重新进入ACTIVE状态,除非重启进程或者重新new一个client对象,这就让笔者非常纠结了,具体可参见:httpasyncclient-4.1.2.jar 包中CloseableHttpAsyncClientBase.java这个类,纵观此类,2处可导致该client进入STOPED状态:

第一处:

this.reactorThread = threadFactory.newTread(new Runnable() {

     

     @Override

     public void run() {

          try {

                    final IOEventDispatch ioEventDispatch = new InternalIODispatch(handler);

                    connmgr.execute(ioEventDispatch);

          } catch (final Exception ex) {

               log.error("I/O reactor terminated abnormally", ex);

          } finally {

               status.set(Status.STOPED)

          }

第二处:

@Override

public void close() {

     if (this.status.compareAndSet(Status.ACTIVE, Status.STOPED)) {

          if (this.reactorThread != null) {

               try {

                    this.connmgr.shutdown();

               } catch (IOException ex) {

                    this.log.error("I/O error shutting down connection manager", ex);

               } 

               try {

                    this.reactorThread.join();

               } catch (final InterruptedException ex) {

                    Thread.currentThread().interrupt();

               }

          }

     }

}

OK,看到这2个地方,应该大家都明白了,第一个地方红色代码处,一旦发生了OOM,new操作会失败抛异常并导致Stauts为STOPED,诡异的是没有找到任何代码再将此状态置回为ACTIVE,那么导致的结果就是这个reactorThread一旦catch住了一个异常(为啥要Catch Exception,尼玛···)这个async client就直接无法再被使用了,更加诡吊的是这个作者在start()方法里写的竟然是:

if (this.status.compareAndSet(Status.INACTIVE, Status.ACTIVE)) {

     startThread ...

}

这是完全不给STOPED后再start起来的机会呀!俺们在外面封装了该client,遇到异常我们吃不到,启动也启动不了,这后路断的够绝!

 

看来是时候给这位大佬提点意见了,不为别的,只为Resilient ... ... 

转载于:https://my.oschina.net/u/3796442/blog/1633849