Java 11 HttpClient приводит к бесконечной петле SSL

Я использую новый java.net.http.HttpClient с методом sendAsync. HttpClient находится внутри Singelton и создается один раз следующим образом: HttpClient.newBuilder().build() так что ничего особенного.

Эти запросы могут быть POST или GET, но я не знаю, что вызывает проблемы.

Всего несколько запросов в день, но время от времени один поток использует 100% ядра процессора. И не сразу, а через некоторое время, когда запрос закончится.

Поэтому я сделал дамп потока, когда было даже 2 из этих бесконечных циклов, выделялись следующие 2 потока:

"HttpClient-4-Worker-5" #144 daemon prio=5 os_prio=0 cpu=511298.10ms elapsed=520.71s tid=0x00007f684403e800 nid=0x2d6b runnable  [0x00007f68ac162000]
   java.lang.Thread.State: RUNNABLE
        at jdk.internal.net.http.common.SSLFlowDelegate$Writer.processData([email protected]/SSLFlowDelegate.java:771)
        at jdk.internal.net.http.common.SSLFlowDelegate$Writer$WriterDownstreamPusher.run([email protected]/SSLFlowDelegate.java:645)
        at jdk.internal.net.http.common.SequentialScheduler$CompleteRestartableTask.run([email protected]/SequentialScheduler.java:147)
        at jdk.internal.net.http.common.SequentialScheduler$SchedulableTask.run([email protected]/SequentialScheduler.java:198)
        at jdk.internal.net.http.common.SequentialScheduler.runOrSchedule([email protected]/SequentialScheduler.java:271)
        at jdk.internal.net.http.common.SequentialScheduler.runOrSchedule([email protected]/SequentialScheduler.java:224)
        at jdk.internal.net.http.common.SSLFlowDelegate$Writer.triggerWrite([email protected]/SSLFlowDelegate.java:722)
        at jdk.internal.net.http.common.SSLFlowDelegate.doHandshake([email protected]/SSLFlowDelegate.java:1024)
        at jdk.internal.net.http.common.SSLFlowDelegate.doClosure([email protected]/SSLFlowDelegate.java:1094)
        at jdk.internal.net.http.common.SSLFlowDelegate$Reader.unwrapBuffer([email protected]/SSLFlowDelegate.java:500)
        at jdk.internal.net.http.common.SSLFlowDelegate$Reader.processData([email protected]/SSLFlowDelegate.java:389)
        - locked <0x00000000fba68950> (a java.lang.Object)
        at jdk.internal.net.http.common.SSLFlowDelegate$Reader$ReaderDownstreamPusher.run([email protected]/SSLFlowDelegate.java:263)
        at jdk.internal.net.http.common.SequentialScheduler$SynchronizedRestartableTask.run([email protected]/SequentialScheduler.java:175)
        - locked <0x00000000fbbca3e8> (a java.lang.Object)
        at jdk.internal.net.http.common.SequentialScheduler$CompleteRestartableTask.run([email protected]/SequentialScheduler.java:147)
        at jdk.internal.net.http.common.SequentialScheduler$SchedulableTask.run([email protected]/SequentialScheduler.java:198)
        at java.util.concurrent.ThreadPoolExecutor.runWorker([email protected]/ThreadPoolExecutor.java:1128)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run([email protected]/ThreadPoolExecutor.java:628)
        at java.lang.Thread.run([email protected]/Thread.java:834)

   Locked ownable synchronizers:
        - <0x00000000fc1ff920> (a java.util.concurrent.ThreadPoolExecutor$Worker)





"HttpClient-4-Worker-2" #82 daemon prio=5 os_prio=0 cpu=4266156.67ms elapsed=4311.42s tid=0x00007f6844007000 nid=0x29ee runnable  [0x00007f686fffd000]
   java.lang.Thread.State: RUNNABLE
        at jdk.internal.net.http.common.SSLFlowDelegate$Writer.processData([email protected]/SSLFlowDelegate.java:771)
        at jdk.internal.net.http.common.SSLFlowDelegate$Writer$WriterDownstreamPusher.run([email protected]/SSLFlowDelegate.java:645)
        at jdk.internal.net.http.common.SequentialScheduler$CompleteRestartableTask.run([email protected]/SequentialScheduler.java:147)
        at jdk.internal.net.http.common.SequentialScheduler$SchedulableTask.run([email protected]/SequentialScheduler.java:198)
        at jdk.internal.net.http.common.SequentialScheduler.runOrSchedule([email protected]/SequentialScheduler.java:271)
        at jdk.internal.net.http.common.SequentialScheduler.runOrSchedule([email protected]/SequentialScheduler.java:224)
        at jdk.internal.net.http.common.SSLFlowDelegate$Writer.triggerWrite([email protected]/SSLFlowDelegate.java:722)
        at jdk.internal.net.http.common.SSLFlowDelegate.doHandshake([email protected]/SSLFlowDelegate.java:1024)
        at jdk.internal.net.http.common.SSLFlowDelegate.doClosure([email protected]/SSLFlowDelegate.java:1094)
        at jdk.internal.net.http.common.SSLFlowDelegate$Reader.unwrapBuffer([email protected]/SSLFlowDelegate.java:500)
        at jdk.internal.net.http.common.SSLFlowDelegate$Reader.processData([email protected]/SSLFlowDelegate.java:389)
        - locked <0x00000000f97668d0> (a java.lang.Object)
        at jdk.internal.net.http.common.SSLFlowDelegate$Reader$ReaderDownstreamPusher.run([email protected]/SSLFlowDelegate.java:263)
        at jdk.internal.net.http.common.SequentialScheduler$SynchronizedRestartableTask.run([email protected]/SequentialScheduler.java:175)
        - locked <0x00000000f97668f0> (a java.lang.Object)
        at jdk.internal.net.http.common.SequentialScheduler$CompleteRestartableTask.run([email protected]/SequentialScheduler.java:147)
        at jdk.internal.net.http.common.SequentialScheduler$SchedulableTask.run([email protected]/SequentialScheduler.java:198)
        at java.util.concurrent.ThreadPoolExecutor.runWorker([email protected]/ThreadPoolExecutor.java:1128)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run([email protected]/ThreadPoolExecutor.java:628)
        at java.lang.Thread.run([email protected]/Thread.java:834)

   Locked ownable synchronizers:
        - <0x00000000f9894cc0> (a java.util.concurrent.ThreadPoolExecutor$Worker)

То же наблюдение, но в другом контейнере, где была затронута только одна нить.

"HttpClient-3-Worker-2" #120 daemon prio=5 os_prio=0 cpu=1100568.51ms elapsed=1113.79s tid=0x00007eff3003b800 nid=0x479 runnable  [0x00007eff83bf8000]
   java.lang.Thread.State: RUNNABLE
        at sun.security.ssl.SSLEngineImpl.wrap([email protected]/SSLEngineImpl.java:136)
        - eliminated <0x00000000f9796e08> (a sun.security.ssl.SSLEngineImpl)
        at sun.security.ssl.SSLEngineImpl.wrap([email protected]/SSLEngineImpl.java:116)
        - locked <0x00000000f9796e08> (a sun.security.ssl.SSLEngineImpl)
        at javax.net.ssl.SSLEngine.wrap([email protected]/SSLEngine.java:519)
        at jdk.internal.net.http.common.SSLFlowDelegate$Writer.wrapBuffers([email protected]/SSLFlowDelegate.java:821)
        at jdk.internal.net.http.common.SSLFlowDelegate$Writer.processData([email protected]/SSLFlowDelegate.java:736)
        at jdk.internal.net.http.common.SSLFlowDelegate$Writer$WriterDownstreamPusher.run([email protected]/SSLFlowDelegate.java:645)
        at jdk.internal.net.http.common.SequentialScheduler$CompleteRestartableTask.run([email protected]/SequentialScheduler.java:147)
        at jdk.internal.net.http.common.SequentialScheduler$SchedulableTask.run([email protected]/SequentialScheduler.java:198)
        at jdk.internal.net.http.common.SequentialScheduler.runOrSchedule([email protected]/SequentialScheduler.java:271)
        at jdk.internal.net.http.common.SequentialScheduler.runOrSchedule([email protected]/SequentialScheduler.java:224)
        at jdk.internal.net.http.common.SSLFlowDelegate$Writer.triggerWrite([email protected]/SSLFlowDelegate.java:722)
        at jdk.internal.net.http.common.SSLFlowDelegate.doHandshake([email protected]/SSLFlowDelegate.java:1024)
        at jdk.internal.net.http.common.SSLFlowDelegate.doClosure([email protected]/SSLFlowDelegate.java:1094)
        at jdk.internal.net.http.common.SSLFlowDelegate$Reader.unwrapBuffer([email protected]/SSLFlowDelegate.java:500)
        at jdk.internal.net.http.common.SSLFlowDelegate$Reader.processData([email protected]/SSLFlowDelegate.java:389)
        - locked <0x00000000f9797010> (a java.lang.Object)
        at jdk.internal.net.http.common.SSLFlowDelegate$Reader$ReaderDownstreamPusher.run([email protected]/SSLFlowDelegate.java:263)
        at jdk.internal.net.http.common.SequentialScheduler$SynchronizedRestartableTask.run([email protected]/SequentialScheduler.java:175)
        - locked <0x00000000f9797030> (a java.lang.Object)
        at jdk.internal.net.http.common.SequentialScheduler$CompleteRestartableTask.run([email protected]/SequentialScheduler.java:147)
        at jdk.internal.net.http.common.SequentialScheduler$SchedulableTask.run([email protected]/SequentialScheduler.java:198)
        at java.util.concurrent.ThreadPoolExecutor.runWorker([email protected]/ThreadPoolExecutor.java:1128)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run([email protected]/ThreadPoolExecutor.java:628)
        at java.lang.Thread.run([email protected]/Thread.java:834)

Пример кода, который я использую

httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofString())
                                .thenApply(logResponse());

Java версия

openjdk version "11.0.2" 2019-01-15
OpenJDK Runtime Environment (build 11.0.2+9-Debian-3)
OpenJDK 64-Bit Server VM (build 11.0.2+9-Debian-3, mixed mode, sharing)

Проблема также возникает, когда вы предпочитаете HTTP 2

Обновления

Я неправильно использую HttpClient? Может ли это быть проблема сервера? Может быть, это ошибка https://bugs.openjdk.java.net/browse/JDK-8207009?

  • Клиент подключается к сервису cloudflare
  • Когда возникает проблема, нет открытого соединения с cloudflare через netstat видимым
  • Я могу прикрепить проблему к http2 + tlsv1.3 (используя образ докера nginx: nginx:1.15-alpine с включенным tls1.3, конечно)

Ответ 1

Как сказал @jspcal перед отключением TLS 1.3.

tl;dr: отключить tlsv1.3 через расширение/перезапись

<java_home>/conf/security/java.security свойство jdk.tls.disabledAlgorithms

Поскольку мое приложение работает в док-контейнере, я изменил базовый образ, чтобы отключить tls1.3

FROM openjdk:11-jre
...

RUN sed -i "/jdk.tls.disabledAlgorithms=/ s/=.*/=TLSv1.3, SSLv3, RC4, MD5withRSA, DH keySize < 1024, EC keySize < 224, DES40_CBC, RC4_40, 3DES_EDE_CBC/" $(readlink -f /usr/bin/java | sed "s:bin/java::")/conf/security/java.security

Насколько я знаю, нет способа установить это (безопасность) свойство через системное свойство! Смотрите также sun.security.util.DisabledAlgorithmConstraints#PROPERTY_TLS_DISABLED_ALGS, который фактически готов свойство.

Обновление: ошибка все еще присутствует в 11.0.2

Ответ 2

Попробуйте отключить TLSv1.3 или SSLv3 чтобы посмотреть, поможет ли это.

Установите системное свойство в командной строке: -Djdk.tls.disabledAlgorithms=TLSv1.3

Или определите свойство в <java_home>/conf/security/java.security

Если вы считаете, что это ошибка реализации, вы можете захотеть открыть проблему.