我有一个输入流,我想HTTPS
在将结果传递到程序的另一部分之前为每个请求发出 2 个网络请求。典型的吞吐量是每秒 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
例程拉出通道。deref
每个请求都通过从 HTTP 请求中获取承诺来“阻止”goblock 。这是行不通的,因为我认为诺言不能很好地与线程配合使用。 - 当一个事件进来时,立即启动一个
future
'blocks' 异步承诺。这会导致非常高的 CPU 使用率。加上不知何故网络资源匮乏。 - 当有事件进来时,
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 分析器告诉我,我有大约 2GB 的char[]
s via org.httpkit.client.Handler
s via java.util.concurrent.FutureTask
s,这表明对旧处理程序(即请求)的引用以某种方式被保留。尝试使用回调的全部原因是为了避免这种情况(尽管它们可能会以某种方式陷入闭包)