【问题标题】:Creating an idle timeout in Go?在 Go 中创建空闲超时?
【发布时间】:2015-03-29 20:23:40
【问题描述】:

我将 CloudFlare 用于我的一个高容量网站,它位于我的堆栈前面。

问题是 CloudFlare 除了创建新连接外,还会打开空闲连接,这不是我可以更改的设置。

当我让 Varnish 或 Nginx 坐在前面监听端口 80 时,它们具有开箱即用的配置来挂断空闲连接。

这很好,直到我不得不将用 Go 编写的代理添加到我的堆栈的前面。它使用net/http 标准库。

我不是 Go 向导,但根据人们告诉我的内容,只有读写超时设置,而不是挂起空闲连接。

现在我的服务器将被连接填满并死掉,除非我设置了一组读写超时,但问题是我的后端有时需要很长时间,这会导致好的请求在不应该被切断时被切断.

使用 Go http 处理空闲连接的正确方法是什么?

编辑 1: 更清楚地说,我正在使用 httputil.NewSingleHostReverseProxy 构造一个代理,它公开了传输选项,但仅适用于上游。我遇到的问题是下游问题,它们需要在使用 ReverseProxy 作为处理程序的 http.Server 对象上设置。 http.Server 不公开传输。

编辑 2:我更喜欢空闲超时而不是读取超时,因为后者适用于活动上传者。

谢谢

【问题讨论】:

    标签: http go connection


    【解决方案1】:

    在 Go http 服务器中挂断空闲连接的正确方法是设置read timeout

    无需设置写入超时即可挂断空闲客户端。如果它会切断响应,请不要设置或调整此值。

    如果您的上传时间较长,则使用a connection state callback 实现单独的空闲和读取超时:

    server.ConnState = func(c net.Conn, cs http.ConnState) {
        switch cs {
        case http.StateIdle, http.StateNew:
            c.SetReadDeadline(time.Now() + idleTimeout)
        case http.StateActive:
            c.SetReadDeadline(time.Now() + activeTimeout)
        }
    }
    

    【讨论】:

    • 这解决了上游问题,但我们也希望不切断活跃的上传者。
    • 太有趣了。谢谢!让我调查一下。
    • 我这样写是否正确设置了超时? c.SetReadDeadline(time.Now().Add(time.Duration(config.DownstreamIdleTimeoutMs) * time.Millisecond)) 其中config.DownstreamIdleTimeoutMsint,比如2500
    • 作为后续,现在我分别设置它们,我可以从http.Server 中删除ReadTimeout: serverIdleTimeout, 对吗?
    • 是的,你可以去掉服务器超时。
    【解决方案2】:

    请参阅net/http.Transport 文档。 Transport 类型有一些选项用于处理处于保持活动状态的空闲 HTTP 连接。通过阅读您的问题,似乎与您的问题最相关的选项是 MaxIdleConnsPerHost 字段:

    MaxIdleConnsPerHost,如果非零,控制最大空闲(保持活动)以保持每个主机。如果为零,则使用 DefaultMaxIdleConnsPerHost。

    阅读代码,默认为每台主机2个。

    Transport 类型还有一个方法来关闭所有空闲连接:CloseIdleConnections。

    CloseIdleConnections 关闭之前从先前请求连接但现在处于“保持活动”状态的空闲连接。它不会中断当前正在使用的任何连接。

    您可以在任何 http 客户端上指定传输:

    tr := &http.Transport{
        TLSClientConfig:    &tls.Config{RootCAs: pool},
        DisableCompression: true,
        MaxIdleConnsPerHost: 1,
    }
    client := &http.Client{Transport: tr}
    resp, err := client.Get("https://example.com")
    

    另一件值得注意的事情:文档建议您保留一个在所有请求中重复使用的 http 客户端对象(即,像全局变量一样)。

    客户端和传输对于多个 goroutine 并发使用是安全的,并且为了提高效率,应该只创建一次并重复使用。

    如果您在代理实现中创建了许多 http 客户端对象,它可能会解释空闲连接的无限增长(不过,只是猜测您可能是如何实现的)。

    编辑:多读一点,net/httputil 包有一些用于反向代理的便利类型。请参阅ReverseProxy type。该结构还允许您提供自己的 Transport 对象,允许您通过此帮助器类型控制代理的空闲客户端行为。

    【讨论】:

    • 我正在使用 httputil.NewSingleHostReverseProxy 构造一个代理,它公开传输选项,但仅适用于上游。我遇到的问题是下游问题,需要在使用 ReverseProxy 作为处理程序的 http.Server 对象上设置它们。 http.Server 不公开传输。
    猜你喜欢
    • 2022-09-23
    • 2011-01-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多