У меня есть поток входов, и я хочу сделать 2 HTTPS
сетевых запросов для каждого, прежде чем передавать результат в другую часть программы. Типичная пропускная способность составляет 50 в секунду.Как создать большое количество одновременных запросов HTTPS в Clojure (/ Java)
for each input:
HTTP request A
HTTP request B
pass event on with (A.body and B.body)
Я использую клиент http-kit
, который асинхронно по умолчанию. Он возвращает обещание и может также принимать обратный вызов. Http-kit использует Java NIO (см. here и here)
Скорость поступающих запросов в сочетании со временем подачи запроса достаточно высока, чтобы это нужно было выполнить асинхронно.
Я пробовал 3 подхода:
- Когда событие приходит, положить его на канале. Несколько процедур
go
, вытягивающих канал. Каждый из них делает запросы, которые «блокируют» goblock наderef
, обещают запросы HTTP. Это не работает, потому что я не думаю, что это обещание хорошо работает с потоками. - Когда приходит событие, немедленно запустите
future
, который «блокирует» по асинхронным обещаниям. Это дает очень хорошее использование центрального процессора. Плюс голод сетевых ресурсов как-то. - Когда приходит событие, немедленно вызовите запрос
http-kit
для запроса A, передавая обратный вызов, который делает запрос B, передавая обратный вызов, который передает событие. Это приводит к ошибке из памяти после нескольких часов.
Все они работают и обрабатывают емкость на некоторое время. В конечном итоге все они разбиваются. Последний краш, примерно через 12 часов:
Mar 10, 2016 2:05:59 AM com.mchange.v2.async.ThreadPoolAsynchronousRunner$DeadlockDetector run
WARNING: com[email protected]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[email protected]1bc8a7f5 -- APPARENT DEADLOCK!!! Complete Status:
Managed Threads: 3
Active Threads: 1
Active Tasks:
com[email protected]65d8b232 (com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#0)
Pending Tasks:
[email protected]0d
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 запросов в полете в любое время, звук, как чрезмерное бремя?
Как это сделать таким образом, чтобы обеспечить пропускную способность и надежность?
EDIT
YourKit профайлер говорит мне, что у меня есть около 2 Гб char[]
с помощью org.httpkit.client.Handler
с помощью java.util.concurrent.FutureTask
с которой наводит на мысль, что ссылки на старые обработчики (т.е. запросы) сохраняются лишь каким-то образом. Целая причина для использования обратных вызовов заключалась в том, чтобы избежать этого (хотя они могут как-то быть уловлены в закрытии)
OutOfMemoryError указывает на то, что проблема связана с памятью ... но мы не можем не видеть ваш код или написать полное решение с нуля. Я хотел бы держать на голове бесконечную последовательность или не очищать ресурсы, такие как соединения. –
Я задавался вопросом, могут ли быть сохранены буферы, но насколько я могу судить, сбор мусора должен обрабатывать освобождение памяти/внешних буферов, например, NIO. Что происходит в нисходящем потоке, это в значительной степени просто вставка базы данных и вставка на канал. – Joe
Я думал о размещении кода, но он довольно запутан, и потребуется около дня, чтобы узнать, не реплицировал ли проблему проблему в упрощенной версии. – Joe