
# 使用Elasticsearch的HLRC（High Level Rest Client）时，报错I/O Reactor STOPPED
#### 问题现象
使用Elasticsearch的HLRC（High Level Rest Client）时，偶现报错I/O Reactor STOPPED。排查Elasticsearch日志，未有报错。
图1I/O Reactor STOPPED报错   
![](https://support.huaweicloud.com/trouble-css/figure/zh-cn_image_0000001981581469.png "点击放大")
#### I/O Reactor STOPPED是什么问题？
首先根据调用栈可以定位到报错来自CloseableHttpAsyncClientBase中的90行。
图2报错位置   
![](https://support.huaweicloud.com/trouble-css/figure/zh-cn_image_0000001981581461.png "点击放大")
ensureRunning()方法是在每次请求执行开始的时候调用，用来确认Client状态是否为ACTIVE，如果不是ACTIVE，则会报错。然后观察CloseableHttpAsyncClientBase中的status何时会变成STOPPED，发现有且仅有两处会set为STOPPED，如下图所示。
图3第一处STOPPED   
![](https://support.huaweicloud.com/trouble-css/figure/zh-cn_image_0000001981581473.png "点击放大")
图4第二处STOPPED   
![](https://support.huaweicloud.com/trouble-css/figure/zh-cn_image_0000001950381884.png "点击放大")
- 由于客户不会手动关闭客户端之后再调用接口，所以有且仅有第一处会导致status切换为STOPPED状态。
- 对于第一处STOPPED，reactorThread线程是用来在io events发生时调度io events，当内部抛出异常时，最终会将status改为STOPPED状态。然后在bulkAsync请求的回调中抛出异常验证status的状态切换，如下图所示。 ![](https://support.huaweicloud.com/trouble-css/figure/zh-cn_image_0000001981581477.png "点击放大")
  
- 当请求失败，status会切换为STOPPED且I/O Reactor将关闭，并使HLRC实例卡住。后续使用该HLRC实例调用任何请求都会失败。此处手动抛出异常是为了复现问题，生产环境中很难分辨是什么原因导致I/O Reactor关闭。
 
#### 原因分析
导致出现I/O Reactor STOPPED的原因，大致可以分为以下3类：
1. 回调中抛出异常导致。
2. 客户端并发太高导致。 在日志中发现异常后，查看Elasticsearch集群监控指标，如CPU使用率、网络连接数等。
   当用户集群配置为5台16U128G的i3.4xlarge.8节点时，且每天上午5点左右会做大量bulk操作，写入大概100G-200G的数据，根据集群监控指标的CPU使用率、网络流入流出速率来看对Elasticsearch节点造成不了压力，网络连接数较高，其它节点情况也相同。但是，有的节点网络连接数高达近9000，5个节点瞬间有将近5万连接数，用户的代码大致是用同一个Rest Client多个线程并发且调用HLRC的bulkAsync接口。客户端一个节点，单是ES的连接就消耗了4-5万个连接数，这种情况很容易造成客户端节点句柄数耗尽，或者连接数耗尽。
   
3. Elasticsearch的Rest Client导致。建议Elasticsearch完善Rest Client，添加Exception Handler。 Apache（HLRC和LLRC都使用了Apache HTTPComponents Async Client）手册中提到，在与会话通道交互过程中有些I/O异常是可以预料的，这些异常可能会导致单个session终止，但不会影响I/O Reactor和其他session。但某些情况下，当I/O Reactor本身遇到内部问题时，例如底层NIO的一些类中的I/O异常或者没被handle的一些Runtime Exception。这些异常是致命的，会使I/O Reactor关闭。Apache官方建议重写IOReactorExceptionHandler接口。
   图5重写IOReactorExceptionHandler接口   
   ![](https://support.huaweicloud.com/trouble-css/figure/zh-cn_image_0000001981581465.png "点击放大")
   但是尝试了重写ExceptionHandler并放到HLRC的配置中，并通过在回调中抛出异常来模拟异常场景，最后发现这种回调的异常并不会被IOReactorExceptionHandler捕获，运行脚本后也没有异常抛出，所以此处IOReactorExceptionHandler的实现并不好验证。通过Elasticsearch社区issue中其他开发者的验证，添加了IOReactorExceptionHandler后跑很久也不会有问题。所以建议添加IOReactorExceptionHandler，但是注意不要忽略所有异常。
   Elasticsearch Rest Client需要有一个Exception Handler，而不是让用户通过设置IOReactorExceptionHandler来处理异常，且这种方式也不会解决所有的异常。
   
 
#### 处理建议
1. 客户端连接池大小建议根据业务实际情况调整。
2. 客户端并发数建议根据业务实际情况调整，或者配置多个节点、分摊压力。
3. 建议配置IOReactorExceptionHandler，可以用来处理一些异常。
4. 调用HLRC时catch exception，并判断cause是否为I/O Reactor STOPPED，然后通过重启客户端恢复连接。
 
