JaxRsClient (OkHttpClient) намного медленнее, чем Feign (HttpURLConnection) или cURL - PullRequest
0 голосов
/ 27 января 2020

У меня есть конечная точка REST, которая в основном просто загружает файл с компьютера, выполняющего вызов, на одну из наших облачных виртуальных машин.

Когда с клиентской виртуальной машины я выполняю вызов с cURL, она Загрузка файла размером 100 мегабайт занимает ~ 10 с.

Когда с клиентской виртуальной машины я выполняю вызов с клиентом jaxrs , загрузка файла размером 100 мегабайт занимает ~ 2 мкс.

Код клиента. Я играл с созданием собственной 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);

Мой (ые) вопрос (ы) заключается в следующем: что может вызвать такое огромное несоответствие пропускной способности сети? Есть ли какие-либо наборы, которые я могу включить для SocketOptions на стороне Java, которые могут помочь решить эту проблему?

Любой контекст и помощь будут приветствоваться!

Соответствующие сведения:

  • jre11.0.6
  • TLSv1.2 (пробовал с обоими наборами шифров CB C и GCM, без изменений ни для одного из них)
  • Я возился с TCP_NODELAY, SO_SNDBUF и SO_RCVBUF (через SSLSocketFactory). TCP_NODELAY дал ~ 10% улучшения производительности, в то время как изменение SO_SNDBUF и SO_RCVBUF ни на что не повлияло.

UPDATE 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, он все равно будет медленным. И ванильный клиент Feign без провайдера Conscrypt также все еще работает медленно.

Стоит также отметить, что я пробовал комплекты шифров GCM и CB C, и они не влияют на производительность все (независимо от того, какой клиент или поставщик Conscrypt установлены).

ОБНОВЛЕНИЕ 2

Итак, я обновил JRE до 11.0.6, и с этим изменением мне больше не нужно включать Conscrypt для быстрого выполнения запроса Feign. Я захватил JFR симметричного запроса (быстрый) и запроса JaxRsClient (медленный).

Это сокет ввода-вывода для запроса Feign (HttpURLConnection под капотом) This is the socket I/O on the Feign (HttpURLConnection) request

Это сокет ввода-вывода на запросе JaxRsClient (OkHttpClient под капотом) This is the socket I/O on the JaxRsClient (OkHttpClient) request

Они были просмотрены с помощью Java Миссия Контроль. Интересно то, что медленный запрос - это всего лишь тонна операций чтения в сокете (~ 200), а быстрый запрос - 3 операции чтения и 15 операций записи. В качестве проверки работоспособности я также переключился между наборами шифров CB C и GCM в обоих этих запросах, без реальной разницы между ними.

1 Ответ

0 голосов
/ 30 января 2020

Итак, я немного недоволен, что у меня нет большей глубины в этом ответе, но вот он.

JaxRsClient согласовывал HTTP / 2. Я не уверен, что происходило под капотом, но если шифры GCM не были включены, единственным разрешенным протоколом должен был быть HTTP1.1. Вот PR, который исправил проблему:

https://github.com/palantir/conjure-java-runtime/commit/e52efdc1f66a52c3ee9112ecaae7bb40ac799224

После этого изменения JaxRsClient не будет согласовывать HTTP / 2, если шифры GCM НЕ включены. В HTTP / 1.1 он соответствовал cURL и Feign по скорости.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...