TCP NoHttpResponseException

NoHttpResponseException

发生的场景

 keep-alive可以 省去了很多不必要的握手/挥手操作,但由于连接长期保活,如果一直没有 http 请求的话,这条连接也就长期闲着了,会占用系统资源,有时反而会比复用连接带来更大的性能消耗。所以我们一般会为 keep-alive 设置一个 timeout, 这样如果连接在设置的 timeout 时间内一直处于空闲状态(未发生任何数据传输),经过 timeout 时间后,连接就会释放,就能节省系统开销。

看起来给 keep-alive 加 timeout 是完美了,但是又引入了新的问题

如果服务端关闭连接,发送 FIN 包(注:在设置的 timeout 时间内服务端如果一直未收到客户端的请求,服务端会主动发起带 FIN 标志的请求以断开连接释放资源),在这个 FIN 包发送但是还未到达客户端期间,客户端如果继续复用这个 TCP 连接发送 HTTP 请求报文的话,服务端会因为在四次挥手期间不接收报文而发送 RST 报文给客户端,客户端收到 RST 报文就会提示异常 (即 NoHttpResponseException)

 

怎么解决办法,有两种策略

  1. 重试,收到异常后,重试一两次,由于重试后客户端会用有效的连接去请求,所以可以避免这种情况,不过一次要注意重试次数,避免引起雪崩!

  2. 设置一个定时线程,定时清理上述的闲置连接,可以将这个定时时间设置为 keep alive timeout 时间的一半以保证超时前回收。

evictExpiredConnections 就是用的上述第二种策略

主要代码逻辑   另外启动了线程去将失效的链接关闭 

public IdleConnectionEvictor(
        final HttpClientConnectionManager connectionManager,
        final ThreadFactory threadFactory,
        final long sleepTime, final TimeUnit sleepTimeUnit,
        final long maxIdleTime, final TimeUnit maxIdleTimeUnit) {
    this.connectionManager = Args.notNull(connectionManager, "Connection manager");
    this.threadFactory = threadFactory != null ? threadFactory : new DefaultThreadFactory();
    this.sleepTimeMs = sleepTimeUnit != null ? sleepTimeUnit.toMillis(sleepTime) : sleepTime;
    this.maxIdleTimeMs = maxIdleTimeUnit != null ? maxIdleTimeUnit.toMillis(maxIdleTime) : maxIdleTime;
    this.thread = this.threadFactory.newThread(new Runnable() {
        @Override
        public void run() {
            try {
                while (!Thread.currentThread().isInterrupted()) {
                    Thread.sleep(sleepTimeMs);
                    connectionManager.closeExpiredConnections();
                    if (maxIdleTimeMs > 0) {
                        connectionManager.closeIdleConnections(maxIdleTimeMs, TimeUnit.MILLISECONDS);
                    }
                }
            } catch (Exception ex) {
                exception = ex;
            }

        }
    });
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值