【发布时间】:2020-05-12 22:41:14
【问题描述】:
我有一个 REST 端点,它基本上只是从调用我们的云 VM 的机器上传一个文件。
当我从客户端 VM 使用 cURL 进行调用时,上传一个 100 兆字节的文件需要大约 10 秒。
当我从客户端 VM 使用 jaxrs client 进行调用时,上传一个 100 兆字节的文件大约需要 2 分 50 秒。
客户端代码。我玩过创建一个自定义 SSLSocketFactory,它允许我打开 SocketOptions 的旋钮,但这不在下面的 sn-p 中。
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 请求更快。我已经捕获了 feign 请求(快)和 JaxRsClient 请求(慢)的 JFR。
这是 Feign (HttpURLConnection under the hood) 请求上的 Socket I/O
这是 JaxRsClient (OkHttpClient under the hood) 请求上的 Socket I/O
这些是使用 Java Mission Control 查看的。有趣的是,慢速请求只是对套接字进行大量读取(~200),而快速请求是 3 次读取和 15 次写入。出于健全性检查,我还在这两个请求中切换了 CBC 和 GCM 密码套件,两者之间没有真正的区别。
【问题讨论】:
-
请编辑您的问题并添加您用于 jaxrs 客户端的代码。一般来说,因应用程序而异的网络速度通常是缓冲区/打包问题。缓冲区越大,发送的数据包越大,传输速度越快。例如,一旦我犯了一个错误并将数据单字节发送到服务器 - 因此每个字节都被包装在一个协议中,增加了 10-100 个字节......
-
客户端代码非常标准,我在上面添加了它(几乎直接来自我提供的 jaxrsclient 链接的文档。我还添加了一些关于我正在使用的环境/协议的更多细节。
-
MyService中返回数据的方法签名是什么?你用StreamingOutput吗? -
@Robert,文件作为
InputStream传递给MyService中的方法。在 feign 客户端 + Conscrypt 提供者的情况下(参见更新 1),改变InputStream的类型根本不会显着影响性能。我还在内存中加载了一个 100mb 的“文件”(不是从磁盘读取),这也不影响性能。 -
请贴出实际的客户端代码。声称它“相当标准”是不够的。
标签: java curl networking https