独立使用play WS从服务器读取多个主体时,我得到一个OOM:
java.lang.OutOfMemoryError: Java heap space
at java.lang.StringCoding$StringEncoder.encode(StringCoding.java:300)
at java.lang.StringCoding.encode(StringCoding.java:344)
at java.lang.String.getBytes(String.java:918)
at akka.util.CompactByteString$.apply(ByteString.scala:872)
at akka.util.ByteString$.apply(ByteString.scala:51)
at play.api.mvc.Codec$.$anonfun$javaSupported$1(Results.scala:346)
at play.api.mvc.Codec$$$Lambda$846/1241362979.apply(Unknown Source)
at play.api.http.DefaultWriteables.$anonfun$wString$1(Writeable.scala:171)
at play.api.http.DefaultWriteables$$Lambda$849/1109231015.apply(Unknown Source)
at play.api.http.Writeable.toEntity(Writeable.scala:25)
at play.api.mvc.Results$Status.apply(Results.scala:429)
...
您可以通过以下示例重制它:
val bigString: String = (1 to 1000000).mkString("")
val serverConfig = ServerConfig(port = Some(findFreeTcpRandomPort()))
val server = AkkaHttpServer.fromRouterWithComponents(serverConfig) { components =>
import Results._
import components.{defaultActionBuilder => Action}
{
case GET(p"/big") => Action {
Ok(bigString)
}
}
}
val url = s"http://localhost:${server.httpPort.get}/big"
implicit val system: ActorSystem = ActorSystem()
implicit val mat: ActorMaterializer = ActorMaterializer()
val ws = StandaloneAhcWSClient()
try {
val f = Future.traverse((1 to 1000).toList) { _ =>
ws.url(url).get().map(_ => ())
}
Await.result(f, 1 hour)
} finally {
ws.close()
server.stop()
system.terminate()
}
使用库:
"com.typesafe.play" %% "play-ahc-ws-standalone" % "2.0.3"
"com.typesafe.play" %% "play-akka-http-server" % "2.6.21"
似乎ws客户端正在累积响应而不清除它们。 如果我为每个请求创建并关闭一个新客户端,那么它将起作用。
有什么主意我该如何避免?
答案 0 :(得分:0)
您正在并行运行太多请求,尤其是当响应的每个主体的长度至少为5888896
时。
为证明问题不在ws客户端上,我将请求分为100个块,并且仅在前一个块完成后才开始下一个100个块。
val url = s"http://localhost:${server.httpPort.get}/big"
implicit val system: ActorSystem = ActorSystem()
implicit val mat: ActorMaterializer = ActorMaterializer()
val ws = StandaloneAhcWSClient()
try {
run100Requests()
run100Requests()
run100Requests()
run100Requests()
run100Requests()
run100Requests()
run100Requests()
run100Requests()
run100Requests()
run100Requests()
} finally {
ws.close()
server.stop()
system.terminate()
}
def run100Requests(): Unit = {
val f = Future.traverse((1 to 100).toList) { _ =>
ws.url(url).get().map(_ => ())
}
Await.result(f, 1 hour)
}
这样做时,我不再收到OOM错误。
因此,我认为您应该对进行中的请求数量引入一些限制。 (显然不要使用Await.result)
最好的方法可能是对输入列表进行分块并为每个块发送请求。