10

HTTPS入力ストリームがあり、結果をプログラムの別の部分に渡す前に、それぞれに対して 2 つのネットワーク要求を作成したいと考えています。通常のスループットは 1 秒あたり 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つのアプローチを試しました:

  1. イベントが発生したら、チャネルに配置します。goチャネルを引き離す多くのルーチン。derefそれぞれが、HTTP リクエストから promise を ing することにより、goblock を「ブロック」するリクエストを作成します。約束がスレッドでうまく機能するとは思わないため、これは機能しません。
  2. イベントが発生すると、すぐfutureに async promise を「ブロック」する を開始します。これにより、CPU 使用率が非常に高くなります。さらに、何らかの形でネットワーク リソースが枯渇します。
  3. イベントが発生すると、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

失敗の原因はわかりません。保持されているクロージャが多すぎるか、段階的なリソースのリーク、またはスレッドの枯渇が発生している可能性があります。

質問

  1. 1 秒あたり 50 件の HTTP リクエストを作成し、それぞれに 200 ミリ秒かかる場合があります。つまり、常に 100 件のリクエストが処理中である可能性があるということは、過度の負担に思えますか?

  2. スループットを処理し、堅牢な方法でこれを行うにはどうすればよいですか?

編集

char[]YourKit プロファイラーは、約 2GB のs via org.httpkit.client.Handlers via s があることを教えてくれます。java.util.concurrent.FutureTaskこれは、古いハンドラー (つまり、要求) への参照が何らかの形で保持されていることを示唆しています。コールバックを使用しようとする全体的な理由は、これを回避することでした (ただし、何らかの形でクロージャーに巻き込まれる可能性があります)。

4

2 に答える 2

1

メソッド A ( derefgo-block 内で返された HTTP キットの先物を ing する) の代わりに、将来の core.async ハンドラー スレッドをブロックしないようにする方法が考えられます。 httpkit のコールバックと core.async を組み合わせて実行します。

(defn handle-event
 "Return a core.async channel that will contain the result of making both HTTP call A and B."
  [event-data]
  (let [event-a-chan (clojure.core.async/chan)
        event-b-chan (clojure.core.async/chan)
        return-chan (clojure.core.async/chan)]
    (org.httpkit.client/request "https://event-a-call"
                                {:method :get :params {"param1-k" "param1-v"}}
                                (fn [resp]
                                  (clojure.core.async/put! event-a-chan resp)))
    (org.httpkit.client/request "https://event-b-call"
                                {:method :get :params {"param1-k" "param1-v"}}
                                (fn [resp]
                                  (clojure.core.async/put! event-b-chan resp)))
    (clojure.core.async/go
      (clojure.core.async/>! return-chan {:event-a-response (clojure.core.async/<! event-a-chan)
                                          :event-b-response (clojure.core.async/<! event-b-chan)}))
    return-chan))
于 2016-03-17T00:15:25.543 に答える