我有一个REST终结点,该终结点基本上只从发出呼叫的计算机上上传文件到我们的一个云VM。
当我从客户端VM用cURL
拨打电话时,大约需要10秒钟才能上传100兆字节的文件。
当我从客户端VM用jaxrs client进行呼叫时,大约需要2m50s来上传100兆字节的文件。
客户代码。我玩过创建自定义SSLSocketFactory的过程,它允许我打开SocketOptions的旋钮,但这不在下面的代码段中。
SslConfiguration sslConfig = SslConfiguration.of(Paths.get(trustStorePath));
ClientConfiguration config = ClientConfigurations.of(
ImmutableList.of(<uri>),
SslSocketFactories.createSslSocketFactory(sslConfig),
SslSocketFactories.createTrustManagers(sslConfig));
MyService service = JaxRsClient.create(
MyService.class,
UserAgent.of(UserAgent.Agent.of("my-user-agent", "1.0.0")),
new HostMetricsRegistry(),
config);
service.fooBar(...);
主机端点(抽象定义)
@POST
@Path("path/foo")
@Consumes(MediaType.WILDCARD)
void fooBar(
@HeaderParam(HttpHeaders.AUTHORIZATION) AuthHeader authHeader,
InputStream fileData);
我的问题是:什么可能导致网络吞吐量如此巨大的差异?我是否可以在Java端打开SocketOptions的任何拨号盘,这可能有助于解决此问题?
任何和所有上下文/帮助将不胜感激!
相关详细信息:
jre11.0.6
TLSv1.2(已与CBC和GCM密码套件一起试用,两者均未更改)
我已经修改了TCP_NODELAY,SO_SNDBUF和SO_RCVBUF(通过SSLSocketFactory)。 TCP_NODELAY的性能提高了约10%,而更改SO_SNDBUF和SO_RCVBUF则没有任何影响。
更新1
我切换到使用普通的Feign客户端(HttpsURLConnection,在后台):
MyService service = Feign.builder()
.client(new Client.Default(new KeepAliveSslSocketFactory(sslContext.getSocketFactory()), null))
.contract(new JAXRSContract())
.encoder(
new InputStreamDelegateEncoder(
new TextDelegateEncoder(
new CborDelegateEncoder(
new ObjectMapper(),
new ConjureFeignJacksonEncoder(objectMapper)))))
.target(MyService.class, <url>);
并在课程开头设置以下代码块:
static {
Security.insertProviderAt(Conscrypt.newProvider(), 1);
}
这两个更改(Feign客户端和Conscrypt提供程序)一起使java调用的性能与
cURL
相当。但是,如果我将Conscrypt提供程序添加到原始JaxRsClient,它仍然很慢。而且没有Conscrypt提供程序的普通Feign客户端仍然很慢。可能还值得注意的是,我已经尝试了GCM和CBC密码套件,它们根本不影响性能(无论设置了哪个客户端或Conscrypt提供程序)。
更新2
因此,我已经将JRE更新为11.0.6,并且通过该更改,我不再需要启用Conscrypt才能使Feign请求更快。我已经捕获了假请求的JFR(快速)和JaxRsClient请求(慢)。
这是Feign上的Socket I / O(高级HttpURLConnection)请求
这是JaxRsClient(位于引擎盖下的OkHttpClient)请求上的Socket I / O
这些是使用Java Mission Control查看的。有趣的是,慢速请求只是套接字上的大量读取(〜200),而快速请求是3次读取和15次写入。就像进行完整性检查一样,我还针对这两个请求在CBC和GCM密码套件之间进行了切换,两者之间没有真正的区别。
最佳答案
因此,对于这个答案我没有更深入的了解,我有点不满意,但是确实如此。
JaxRsClient正在协商HTTP / 2。我不确定到底发生了什么,但是如果未启用GCM密码,则唯一允许的协议应该是HTTP1.1。这是纠正此问题的PR:
https://github.com/palantir/conjure-java-runtime/commit/e52efdc1f66a52c3ee9112ecaae7bb40ac799224
如果未启用GCM密码,则该更改之后,JaxRsClient将不会协商HTTP / 2。在HTTP / 1.1上,它与cURL
和Feign
匹配以提高速度。