У меня есть поток входных данных, и я хочу сделать 2 HTTPS
сетевых запроса для каждого, прежде чем передавать результат в другую часть программы. Типичная пропускная способность составляет 50 в секунду.
for each input:
HTTP request A
HTTP request B
pass event on with (A.body and B.body)
Я использую клиент http-kit
, который по умолчанию является асинхронным. Он возвращает обещание, а также может принимать обратный вызов. Http-kit использует Java NIO (см. >здесь и здесь)
Скорость поступающих запросов в сочетании со временем выполнения запроса достаточно высока, поэтому это необходимо делать асинхронно.
Я пробовал 3 подхода:
- Когда приходит событие, поместите его на канал. Ряд
go
подпрограмм отключает канал. Каждый из них делает запросы, которые «блокируют» goblock,deref
ing промисы из HTTP-запросов. Это не работает, потому что я не думаю, что обещание хорошо работает с потоками. - Когда приходит событие, немедленно запустите
future
, который «блокирует» асинхронные промисы. Это приводит к очень высокой загрузке ЦП. Плюс голодание сетевых ресурсов как-то. - Когда приходит событие, немедленно запускайте запрос
http-kit
для запроса A, передавая обратный вызов, который делает запрос B, передавая обратный вызов, который передает событие. Это приводит к ошибке нехватки памяти через несколько часов.
Все они работают и справляются с нагрузкой некоторое время. Все они в конце концов терпят крах. Самый последний сбой, примерно через 12 часов:
Mar 10, 2016 2:05:59 AM com.mchange.v2.async.ThreadPoolAsynchronousRunner$DeadlockDetector run
WARNING: com.mchange.v2.async.ThreadPoolAsynchronousRunner$DeadlockDetector@1bc8a7f5 -- APPARENT DEADLOCK!!! Creating emergency threads for unassigned pending
tasks!
Mar 10, 2016 3:38:38 AM com.mchange.v2.async.ThreadPoolAsynchronousRunner$DeadlockDetector run
WARNING: com.mchange.v2.async.ThreadPoolAsynchronousRunner$DeadlockDetector@1bc8a7f5 -- APPARENT DEADLOCK!!! Complete Status:
Managed Threads: 3
Active Threads: 1
Active Tasks:
com.mchange.v2.resourcepool.BasicResourcePool$1DestroyResourceTask@65d8b232 (com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#0)
Pending Tasks:
com.mchange.v2.resourcepool.BasicResourcePool$AcquireTask@359acb0d
Pool thread stack traces:
Thread[com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#0,5,main]
com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunner.java:560)
Thread[com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#1,5,main]
java.lang.Object.wait(Native Method)
com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunner.java:534)
Thread[com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#2,5,main]
java.lang.Object.wait(Native Method)
com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunner.java:534)
Thu Mar 10 04:38:34 UTC 2016 [client-loop] ERROR - select exception, should not happen
java.lang.OutOfMemoryError: Java heap space
at java.io.ByteArrayOutputStream.<init>(ByteArrayOutputStream.java:77)
at sun.security.ssl.OutputRecord.<init>(OutputRecord.java:76)
at sun.security.ssl.EngineOutputRecord.<init>(EngineOutputRecord.java:65)
at sun.security.ssl.HandshakeOutStream.<init>(HandshakeOutStream.java:63)
at sun.security.ssl.Handshaker.activate(Handshaker.java:514)
at sun.security.ssl.SSLEngineImpl.kickstartHandshake(SSLEngineImpl.java:717)
at sun.security.ssl.SSLEngineImpl.beginHandshake(SSLEngineImpl.java:743)
at org.httpkit.client.HttpClient.finishConnect(HttpClient.java:310)
at org.httpkit.client.HttpClient.run(HttpClient.java:375)
at java.lang.Thread.run(Thread.java:745)
Mar 10, 2016 4:56:34 AM baleen.events invoke
SEVERE: Thread error: Java heap space
java.lang.OutOfMemoryError: Java heap space
Mar 10, 2016 5:00:43 AM baleen.events invoke
SEVERE: Thread error: Java heap space
java.lang.OutOfMemoryError: Java heap space
Mar 10, 2016 4:58:25 AM baleen.events invoke
SEVERE: Thread error: Java heap space
java.lang.OutOfMemoryError: Java heap space
Я не знаю, в чем причина неудачи. Это может быть связано со слишком большим количеством замыканий, постепенной утечкой ресурсов или голоданием потока.
Вопросы
Выполнение 50 HTTP-запросов в секунду, каждый из которых может занимать 200 мс, а это означает, что в любой момент времени может выполняться 100 запросов, звучит как чрезмерное бремя?
Как мне сделать это таким образом, чтобы обрабатывать пропускную способность и быть надежным?
ИЗМЕНИТЬ
Профилировщик YourKit сообщает мне, что у меня есть около 2 ГБ char[]
s через org.httpkit.client.Handler
s через java.util.concurrent.FutureTask
s, что говорит о том, что ссылки на старые обработчики (то есть запросы) каким-то образом сохраняются. Вся причина попытки использовать обратные вызовы заключалась в том, чтобы избежать этого (хотя они могли каким-то образом попасть в замыкания)
with-open
вокруг них, чтобы убедиться, что они закрыты после того, как вы закончите с ними. - person Timothy Pratley   schedule 10.03.2016FutureTask
единственными путями к корням GC? Если да, то что хранит ссылки на этиFutureTask
? И вообще: пробовали ли вы http-kit.org/client.html#combined а>? Является ли утечка памяти единственной причиной, по которой такое решение не работает для вас? - person Piotrek Bzdyl   schedule 10.03.2016