超时与重试浅析

本文深入探讨了网络通信中的超时设置,从Socket连接超时到各种网络请求超时,包括数据库、缓存、RPC和HTTP客户端等。此外,还分析了重试机制在不同场景下的应用,如RPC、MQ和网关重试,强调了合理设置超时和重试对系统高可用性的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

超时可以说是除了空指针我们最熟悉的异常了,从系统的接入层,到服务层,再到数据库层等等都能看到超时的身影;超时很多情况下同时伴随着重试,因为某些情况下比如网络抖动问题等,重试是可以成功的;当然重试往往也会指定重试次数上限,因为如果程序确实存在问题,重试多少次都无济于事,那其实也是对资源的浪费。

为什么要设置超时

对于开发人员来说我们平时最常见的就是设置超时时间,比如数据库超时设置、缓存超时设置、中间件客户端超时设置、HttpClient超时设置、可能还有业务超时;为什么要设置超时时间,因为如果不设置超时时间,可能因为某个请求无法即时响应导致整个链路处于长时间等待状态,这种请求如果过多,直接导致整个系统瘫痪,抛出超时异常其实也是及时止损;纵观各种超时时间设置,可以看到其实大多数都是围绕网络超时,而网络超时不得不提Socket超时设置。

Socket超时

Socket是作为网络通信最基础的类,要进行通信基本分为两步:

  • 建立连接:在进行读写消息之前必须首先建立连接;连接阶段会有连接超时设置ConnectTimeout;
  • 读写操作:读写也就是双方正式交换数据,此阶段会有读写超时设置ReadTimeOut;

连接超时

Socket提供的connect方法提供了连接超时设置:

public void connect(SocketAddress endpoint) throws IOException
public void connect(SocketAddress endpoint, int timeout) throws IOException

不设置timeout默认是0,理论上应该是没有时间限制,经测试默认还是有一个时间限制大概21秒左右;

在建立连接的时候可能会抛出多种异常,常见的比如:

  • ProtocolException:基础协议中存在错误,例如TCP错误;

    java.net.ProtocolException: Protocol error
    
  • ConnectException:远程拒绝连接(例如,没有进程正在侦听远程地址/端口);

    java.net.ConnectException: Connection refused
    
  • SocketTimeoutException:套接字读取(read)或接受(accept)发生超时;

    java.net.SocketTimeoutException: connect timed out
    java.net.SocketTimeoutException: Read timed out
    
  • UnknownHostException:指示无法确定主机的IP地址;

    java.net.UnknownHostException: localhost1
    
  • NoRouteToHostException:连接到远程地址和端口时出错。通常,由于防火墙的介入,或者中间路由器关闭,无法访问远程主机;

    java.net.NoRouteToHostException: Host unreachable
    java.net.NoRouteToHostException: Address not available
    
  • SocketException:创建或访问套接字时出错;

    java.net.SocketException: Socket closed
    java.net.SocketException: connect failed
    

这里我们重点要讨论的是SocketTimeoutException,同时Connection refused也经常出现,这里做一个简单的对比

Connect timed out

本地可以直接使用一个不存在的ip尝试连接:

SocketAddress endpoint = new InetSocketAddress("111.1.1.1", 8080);
socket.connect(endpoint, 2000);

尝试连接报如下错误:

java.net.SocketTimeoutException: connect timed out
	at java.net.DualStackPlainSocketImpl.waitForConnect(Native Method)
	at java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:85)
	at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
	at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
	at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
	at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:172)
	at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
	at java.net.Socket.connect(Socket.java:589)
Connection refused

本地测试可以使用127.x.x.x来进行模拟,尝试连接报如下错误:

java.net.ConnectException: Connection refused: connect
	at java.net.DualStackPlainSocketImpl.waitForConnect(Native Method)
	at java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:85)
	at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
	at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
	at java.net.AbstractPlainSocketImpl.connect(
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值