关于Redis出现“java.io.IOException: 远程主机强迫关闭了一个现有的连接”的一次排查

背景

最近在使用springboot(Windows下)连接redis(云服务器)开发时发现一些问题:连接成功的情况下,在一段时间未交互数据后,再次通过连接与Redis传输数据回出现异常java.io.IOException: 远程主机强迫关闭了一个现有的连接。
于是我上网找了一些博客主要是两种:

  • 可能是客户端连接太多了,开启timeout设置或tcp-keepalive
  • 将配置的的tcp-keepalive设置为60(可能之前是300)

这两个设置是什么意思呢

  • timeout,单位是秒,如果客户端连接空闲时间达到这个时间,就释放掉这个连接
  • tcp-keepalive,单位是秒,空闲时间达到这个时间就发送一个tcp-keepalive心跳包,用于检测客户端(在这里就是我的springboot程序)是否在线

探索

为了弄清楚原因,我开始对Linux用tcpdump抓包,在Windows下用wireshark抓包分析,发现一些问题

  • 我的设置是tcp-keepalive 300,在到达300s后,Linux的tcpdump抓到redis发送了心跳包,但是并未得到客户端回应,Windows的wireshark也没有抓到有收到redis的心跳包

  • 此后,redis每100秒重发一次心跳包,直到600秒发送rst,释放了tcp连接,而Windows还是无感知,连接状态是establish,因此,第10分钟(600秒)后,客户端用原来的连接与Linux的redis通信,不会得到ack回应,于是不断重发,直到超出阈值,springboot出现远程主机关闭连接的异常,然后重新进行三次握手重建连接

  • 并非要到10分钟连接才会失效,据我的测试,在240s后,Windows的springboot尝试通过连接与Linux的redis通信,但是发送不会得到ack,于是重发,直到超过阈值释放,重新三次握手。
    此时,springboot不会出现刚刚那个异常,但是是打印如下日志:
    在这里插入图片描述

    此时,Linux端还保留原来的连接,直到10分钟后(就像上面那样)。

  • 如果使用本地Windows的redis服务器,即使tcp-keepalive是300,redis在300s发送的心跳包就能被wireshark抓到,并且得到回应,保持连接,也就是表现正常。

由上面几点分析,可以认为两端的tcp通信受到阻碍。240s后,无论是Linux通过tcp连接给本地Windows发(tcp-keepalive),还是Windows给Linux发,都是无法得到回应。并且是Linux和本地的开发机之间才会出现,在一段时间不通信后,tcp连接就失效了。

推测原因

为了检验这个是底层tcp出现了问题,于是使用golang写了个小程序,连接后不发心跳包,等到250s后发送消息。
测试结果结果是:同样出现了发送数据未得到ack,重试几次后释放,tcpdump也没抓到对应数据。也就是我这边发的数据那边根本就没收到。
由于这个时间比较固定,在我的环境中,240秒后连接就失效了,我推测是某些地方设置了过期时间,再由同一个本地环境中的redis和springboot表现正常,我的推测是这可能是NAT(网络地址转换协议)的会话过期导致的
这个协议的作用是在本地多个设备使用同一个公网IP的情况下,通过一些配置路由到对应的子网设备。

解决

在我这里,只要把tcp-keepalive设置为240秒以下就好了

结束

推测的原因没有亲自去证实,希望有大佬能够证实或指出错误。

  • 10
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 这是Redis出现异常的错误信息,其中嵌套的异常是io.lettuce.core.RedisException,而具体的错误原因是java.io.IOException,表示远程主机强制关闭一个现有连接。 ### 回答2: Redis是一款高性能的key-value内存数据库,它是非常流行的分布式缓存解决方案。在使用Redis的过程中,有时候会遇到"redis exception; nested exception is io.lettuce.core.redisexception: java.io.ioexception: 远程主机强迫关闭一个现有连接"的异常。 这个异常通常是由于Redis服务器在处理请求的过程中遇到一些问题,造成连接被强制关闭,导致客户端无法访问Redis服务器。这种情况一般是由于网络问题或者Redis服务器异常引起的。 解决这个问题的方法有多种,首先可以检查网络连接是否正常,确保网络状况良好可以有效的避免这个问题的出现。其次,可以尝试重启Redis服务器,以确保Redis服务器的正常运行。如果还是无法解决问题,可以尝试升级Redis服务器的版本,或者更换Redis服务器的硬件设备。 另外,在程序开发过程中,也需要注意一些Redis客户端的最佳实践,比如尽量使用连接池来管理Redis连接,不要频繁打开和关闭Redis连接,以避免连接被强制关闭的可能性。同时,还需要注意代码中异常处理的问题,及时捕获和处理Redis客户端抛出的异常信息,从而避免出现未知的异常导致程序崩溃。 总之,以上是针对"redis exception; nested exception is io.lettuce.core.redisexception: java.io.ioexception: 远程主机强迫关闭一个现有连接"这个问题的一些解决方法和注意事项,希望对大家有所帮助! ### 回答3: 这是redis出现了异常,在与Lettuce连接时发生了网络错误,导致无法完成连接或传输数据。在此情况下,可能有多种原因,例如网络故障、服务端关闭连接、路由器过滤等。 要解决这个问题,首先要确定出现该异常的确切原因。一般情况下,这种异常会在使用某些redis操作(如设置键值对、获取值等)时出现,而在其他操作(如获取key列表、删除key)时却不会出现,这就暗示我们可能是在进行某些耗费时间的操作时受到影响。 接着,我们需要对这些操作进行跟踪,并尽可能减少它们对redis带来的负担,例如可以将大量操作拆分成多个小的、耗时较短的操作,尽量避免使用大量数据的操作,或者限制操作频率,避免过量的请求。 此外,我们还可以增加redis服务的配置参数,例如在redis.conf中加入timeout、tcp-keepalive等参数,可以提高redis的稳定性,减少因为网络故障和连接超时导致的异常。如果以上方法仍然无法解决异常,我们可以考虑升级redis版本或切换到新的redis客户端,以更好的适应网络变化和趋势。 总之,对于这种异常,需要仔细排查问题的根源,并尽可能优化redis的配置和使用方式,以确保系统的稳定和可靠性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值