AWS/ALB、http/2 和 GOAWAY

Posted

技术标签:

【中文标题】AWS/ALB、http/2 和 GOAWAY【英文标题】:AWS/ALB, http/2, and GOAWAY 【发布时间】:2017-05-26 08:45:46 【问题描述】:

我们最近从 ELB 切换到 ELB2/ALB,有时我们的 go http/2 客户端会看到来自应用程序负载均衡器的 GOAWAY 消息,我无法解释。目标组服务器仅支持 http/1.1,我们的负载均衡器应始终至少有一个健康的服务器轮换。

在 ALB 中注册新实例时,我可以可靠地重现 GOAWAY。当目标处于“初始”状态时,ALB 返回 GOAWAY。此外,即使 ALB 以 GOAWAY 响应,请求也成功地将其发送到目标组中注册的其他实例。因此,给定实例 web0 和 web1,如果我取消注册 web0 并重新注册该目标,如果我在 web0 处于“初始”状态时发出请求,我可以可靠地重现 GOAWAY。但是我们的日志显示 web1 成功处理了请求。

我们的客户端是一个使用 http.DefaultClient 的 Go 程序。我可以使用 Go 1.7 和 1.8beta2 重现这种行为。

当这种情况发生时,我们的客户端会记录有关 HTTP/2 响应的更多详细信息:

http2: server sent GOAWAY and closed the connection; LastStreamID=1, ErrCode=NO_ERROR, debug=""

我想更好地了解这里发生了什么。 go http2 包或我们的代码是否应该通过重试请求来自动处理 GOAWAY?我对 http2 不够熟悉,不知道是否需要 GOAWAY,这意味着我们的 Go 客户端不应将其作为错误条件处理,或者这是否表明 ALB 出现问题。

【问题讨论】:

您可能想添加一个问题或以某种方式进一步解释问题所在。 @thomasdarvik - 完成,谢谢 GOAWAY框架在客户端的表现是什么?客户是在积极地做一些被打断的事情,还是只是被记录下来? @JimB - 目前我们的 go HTTP 客户端代码等效地处理所有错误,它们被记录为错误并且请求被中止。这段代码早于我们从 ELB 转移到 ALB 之前,当使用 ELB(和 http/1.1)时,所有协议错误都是实际错误。客户端在请求之间以 1s 循环遍历相同的 Web 请求。每个请求大约需要 5 秒。 @BrianF:我认为 GOAWAY 是由客户端更透明地处理的东西,例如 Connection: close,但 ALB 也可能做错了事。无论如何,您需要处理它,我认为您仍然可以像处理任何其他协议或网络错误一样处理它。如果您在拨号或连接失败时重试,我会在这种情况下做同样的事情。 【参考方案1】:

关于GOAWAY

GOAWAY 框架包含三个信息,可以帮助您解决问题:

 +-+-------------------------------------------------------------+
 |R|                  Last-Stream-ID (31)                        |
 +-+-------------------------------------------------------------+
 |                      Error Code (32)                          |
 +---------------------------------------------------------------+
 |                  Additional Debug Data (*)                    |
 +---------------------------------------------------------------+
Last-stream-ID 是正确处理的最后一个 ID。这可能有助于理解发生了什么:RFC 有一些关于如何实现正常关机的建议:首先发送带有 Last-Stream-IDNO_ERRORGOAWAY 帧,让客户端知道关机即将到来,然后一段时间后,发送另一个GOAWAY 帧,并将Last-Stream-ID 设置为实际最后处理的ID。这样客户就知道传递了什么。这是相关的摘录,来自RFC7540, 6.8 GOAWAY

试图正常关闭连接的服务器 应该发送带有最后一个流标识符的初始 GOAWAY 帧 设置为 2^31-1 和 NO_ERROR 代码。这向客户发出信号 关闭迫在眉睫,发起进一步的请求是 禁止。在为任何进行中的流创建留出时间之后 (至少一个往返时间),服务器可以发送另一个GOAWAY 具有更新的最后一个流标识符的帧。这确保了一个 可以干净地关闭连接而不会丢失请求。

错误代码和附加调试数据(字符串)将包含解释发生情况的附加信息。 RFC 7540, 7. Error Codes 有可能的错误代码列表。然后根据服务器实现,您可能有一个字符串来缩小错误范围。 For example in H2O, the server sends found an upper-case letter in header name 在标题名称中发现大写字母时。

这个特别的GOAWAY

http2: server sent GOAWAY and closed the connection; LastStreamID=1, ErrCode=NO_ERROR, debug=""

由于服务器正在发送NO_ERROR,您的客户端应该简单地尝试重新连接,而不是将消息视为错误。

至于为什么 ALB 发送 GOAWAYs...我不确定,您能否提供更多详细信息?

【讨论】:

我已经编辑了我的问题以包含更多显示 Last-Stream-ID 和调试信息的日志信息。 编辑了问题以解决附加信息,谢谢!【参考方案2】:

@frederik-deweerdt 的答案应该被接受为答案,特别是关于应用程序负载均衡器,这里是 AWS 论坛帖子中类似问题的答案,https://forums.aws.amazon.com/thread.jspa?messageID=771883&#771883

您的客户端收到的 HTTP/2 GOAWAY 响应是由 Application Load Balancer 正常关闭的连接。应用程序负载均衡器通常允许空闲连接持续到配置的空闲超时,默认为 60 秒。但是,有一些条件可以触发空闲连接的关闭。在 HTTP/1.1 连接上,允许完成未完成的请求,然后 TCP 连接被正常断开。在 HTTP/2 连接上,负载均衡器通过发送 HTTP/2 GOAWAY 来优雅地关闭这些连接。根据 RFC 7540 “GOAWAY 允许端点优雅地停止接受新流,同时仍完成对先前建立的流的处理”。客户端应通过完成正在进行的请求、关闭连接并在需要时重新连接来响应。 Application Load Balancer 将在访问日志中记录每个请求的 HTTP 状态,而不是连接状态关闭信号。

应检查因收到 HTTP/2 GOAWAY 而遇到错误的客户端,以确保它们完全符合 HTTP/2 RFC。

您可以在 RFC 7540 的第 6.8 节中阅读有关 HTTP/2 GOAWAY 方法的更多信息。 https://www.rfc-editor.org/rfc/rfc7540#section-6.8

如果您对弹性负载均衡器的这种行为或其他行为有任何其他问题,请告诉我们。

【讨论】:

嗨,乔恩,我也记录了该论坛主题。值得注意的是,本期的有趣内容直接来自 Go 开发者github.com/golang/go/issues/18639。我不是 http2 专家,但您应该阅读该问题以了解更多详细信息。

以上是关于AWS/ALB、http/2 和 GOAWAY的主要内容,如果未能解决你的问题,请参考以下文章

如何使 AWS ALB 将请求源发送到 lambda

AWS ALB 运行状况检查通过 HTTP 但未通过 Websocket

如果我在 Cloudfront 上启用了 SSL,AWS ALB 是不是需要 SSL?

AWS ALB使用cognito认证时遇到redirect_mismatch错误

如何从私有 AWS ALB 公开 API 端点

如何使用 kubernetes_ingress terraform 资源创建 AWS ALB?