问题描述
我们的推送后端使用 GCM API 向 Android 设备发送通知。
端点:https://fcm.googleapis.com/fcm/send
HTTP 客户端:Java 11 Http Client(使用 HTTP/2 设置):
var httpClient = HttpClient.newBuilder()
.version(HttpClient.Version.HTTP_2)
// ...
.build();
问题
有时我们会从 GCM 获得 GOAWAY
帧。但是 java http client hides 这些帧的错误代码和有效载荷(只是抛出一些通用异常)。所以我们不知道是什么导致了 GOAWAY
。
问题
- 这是 GCM API 的预期行为吗?
- 可能是什么原因造成的?
- 如何调试?
解决方法
很难确定 GCM 为何发送 GOAWAY
- 只有 GCM 团队才能真正回答这个问题。但是,它的一些常见原因是:
- 您的客户端所连接的服务器正在停机以进行维护。在此之前,它进入一个耗尽模式,允许完成正在进行的请求,同时阻止新的请求。这是通过发送
GOAWAY
通知客户端不应在该连接上启动新请求来实现的。 - 服务器希望客户端迁移到不同的连接以实现负载平衡
这意味着发送 GOAWAY
的服务器不是错误,它只是在云设置中可以预料的事情。
HTTP/2 规范提供了一些关于如何处理 GOAWAY
的更多信息:https://tools.ietf.org/html/rfc7540#section-6.8
关于处理它:理想情况下,您的 HTTP/2 客户端可能已经在内部完全做到了:
- 如果它在没有请求处于活动状态时收到
GOAWAY
帧,它应该为下一个请求创建一个新连接 - 如果它在发送请求时接收到
GOAWAY
帧,并且该GOAWAY
帧表明请求尚未处理,则可以创建新客户端并重试请求。即使它是非幂等请求(如POST
),这也能正常工作,因为我们知道服务器尚未处理该请求。
如果 JDK11 客户端没有自动执行此操作,那么您在这里真正能做的就是在应用层重试。
根据is there any way to handle HTTP/2 Goaway received IOException in HttpClient java?,似乎客户端可能会抛出一个IOException
,其消息包含GOAWAY received
。这可能是重试的好信号。