为什么不直接关闭连接,而是将连接放入一个新的列表中?

huangapple go评论97阅读模式
英文:

net/http: Why not close the conn directly instead of put the conn into a new list?

问题

我最近阅读了Golang的源代码,并发现了一个不合理的地方。

if t.MaxIdleConns != 0 && t.idleLRU.len() > t.MaxIdleConns { 
    oldest := t.idleLRU.removeOldest() 
    oldest.close(errTooManyIdle) 
    t.removeIdleConnLocked(oldest) 
} 

代码链接在这里:https://github.com/golang/go/blob/96c8cc7fea94dca8c9e23d9653157e960f2ff472/src/net/http/transport.go#L984-L988

问题:
idleConn的长度大于t.MaxIdleConns时,为什么不直接关闭连接,而是将连接放入一个新的列表中,并同时移除列表中最旧的连接。按照我的理解,关闭多余的连接应该很简单,并且这样做是正确的。

英文:

I read golang's source code recently, and find a place that doesn't make sence.

if t.MaxIdleConns != 0 && t.idleLRU.len() > t.MaxIdleConns { 
 	oldest := t.idleLRU.removeOldest() 
 	oldest.close(errTooManyIdle) 
 	t.removeIdleConnLocked(oldest) 
 } 

the code is here : https://github.com/golang/go/blob/96c8cc7fea94dca8c9e23d9653157e960f2ff472/src/net/http/transport.go#L984-L988

question:
when idleConn's length > t.MaxIdleConns, why not close the conn directly instead of put the conn into a new list. at the same time, remove the oldest conn in the list. As I understand it, it's simple to close the redundant connection, and it turns out to be corrent.

答案1

得分: 1

我猜测的原因是,服务器(远程服务器)并不一定有义务保持空闲连接的开启状态,即使它决定这样做,也不一定会保持连接的开启时间与客户端请求的时间一样长。
另一个可能的问题是,空闲的TCP会话可能会被中间网络节点主动终止(例如,NAT设备通常必须为它们路由的每个TCP会话维护某种状态,因此它们“有兴趣”摆脱它们认为已经失效的会话);TCP keepalive 可能有所帮助,但它们应该被启用——这并不总是情况——并且它们的“ping”应该足够频繁,以便中间节点认为该会话仍然活动,而这也并不总是情况。

这些问题很容易导致会话在一段时间内被服务器或中间网络节点关闭。
此外,基本上 net/http 没有简单的方法来知道特定的空闲连接在最后一次HTTP会话执行之后的时间范围内是否已经关闭并且无法使用,直到 net/http 选择该连接执行另一个会话。

如果你继续阅读代码,你会发现 net/http 尝试使用一个空闲连接,如果发现它已经失效,它会选择下一个连接,并重复这个过程,直到找到一个可用的连接或被迫建立一个新的连接。

因此,最近的连接更有可能准备好用于执行另一个HTTP会话。

再加上另一条相关的推理:服务器可能对同时活动的连接数有限制——总数限制、每个(源)主机限制或两者兼有——在生产环境中通常会有这样的限制。按照这种逻辑,如果连接成功,这可能意味着客户端认为仍然活动但空闲的旧连接已经被服务器关闭,因此服务器能够在保持其配置的活动连接数限制内创建一个新的连接。当然,这样的逻辑只是一种猜测,但并非毫无根据。

英文:

I'd speculate that the reason is that the server (the remote) is not by any means oblidged to keep an idle connection open, and even if it decides to do so, it's not oblidged to keep it open for as long as the client requested.
Another possible problem is that idling TCP sessions can be proactively terminated by indermediate network nodes (for instance, NAT devices usually have to maintain certain state for each TCP session they route and so they are "interested" in getting rid of the sessions they deem to be dead); TCP keepalives may help but they should be enabled—which is not always the case,—and their "pings" should be frequent enough for an intermediate node to consider such session alive, which, again, is also not always the case.

These issues may easily lead for a session idling for some time to be closed either by the server or by an intermediate network node.
Add to that the fact that basically net/http has no simple means to know that a particular idle connection has really been closed and became unusable in the time frame since the last HTTP session has been performed on it and until net/http pulled that connection for carrying out another session.

If you'll read the code a bit further, you'll find out that net/http tries to use an idle connection and if it finds it's dead, it'll pick the next one, and will repeat that until one works or it will be forced to establish a new connection.

Hence a more recent connection simply has greater chance of being ready to serve another HTTP session.

Add to that another line of reasoning, somewhat related to the presented above: the server might have a limit on the number of simultaneously active connections—total, or per (source) host, or both,—and in production setups it usually has. By this logic, if a connection to it succeeds, it may mean that some old connection beleived by the client to be alive albeit idle, had already be closed by the server—so it were able to create a new connection while staying within its configured limits of the number of active connections. Of source, such logic is just a speculation, but not exactly unfounded.

huangapple
  • 本文由 发表于 2022年4月25日 18:11:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/71997860.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定