Scala 在使用akka http实现web socker服务器时,堆内存正在增长
我使用AKKAHTTP实现web套接字服务器 以下是它的请求处理程序代码:Scala 在使用akka http实现web socker服务器时,堆内存正在增长,scala,akka,akka-stream,akka-http,Scala,Akka,Akka Stream,Akka Http,我使用AKKAHTTP实现web套接字服务器 以下是它的请求处理程序代码: def decodeService: Flow[Message, Message, _] = { Flow[Message].map { case BinaryMessage.Strict(encodeMsg) => try { WebServer.getWorkerActor ! QueueWork(protoMsg(this, encodeMsg
def decodeService: Flow[Message, Message, _] = {
Flow[Message].map {
case BinaryMessage.Strict(encodeMsg) =>
try {
WebServer.getWorkerActor ! QueueWork(protoMsg(this, encodeMsg))
} catch {
case e: Exception => {
println("[ERROR] failed to send BinaryMessage.Strict: " + e)
TextMessage("[ERROR] failed receiving BinaryMessage.Strict")
}
}
TextMessage("[INFO] BinaryMessage.Strict")
case BinaryMessage.Streamed(streamedMsg) => {
implicit val system = ActorSystem("DecoderSystem")
implicit val materializer = ActorMaterializer()
val streamedMsgFuture: Future[Seq[ByteString]] = streamedMsg.runWith(Sink.seq)
streamedMsgFuture.onComplete { completedStream =>
var completeBytestring = new ByteStringBuilder()
//I'm sure there's a better way to do this.. but hey, it's O(n)
completedStream.foreach { x =>
x.foreach { y =>
completeBytestring ++= y
}
}
try {
WebServer.getWorkerActor ! QueueWork(protoMsg(this, completeBytestring.result()))
} catch {
case e: Exception => {
println("[ERROR] failed to send BinaryMessage.Streamed: " + e)
TextMessage("[ERROR] failed receiving BinaryMessage.Streamed")
}
} finally {
completeBytestring.clear()
}
}
TextMessage("[INFO] BinaryMessage.Streamed")
}
case TextMessage.Strict(txt) => TextMessage("Succesfully receive text message")
case _ => TextMessage("Message type unsupported")
}
}
我的web服务器经常每1分钟获取一次数据流。我看到记忆在增长。如果我不处理流式消息,它可以保存。客户机和服务器之间的连接也是持久的
我是否错误地使用了流/接收器/源?如何冲洗水流
谢谢嗯,最明显的问题是,您为收到的每个流式消息创建了一个全新的
ActorSystem
。ActorSystem
就像是参与者的线程池;您希望尽可能少地创建它们,最好只为整个应用程序创建一个。您不仅为每条消息创建它们,而且不关闭它们—在ActorSystem
中配置的所有Dispatcher,它所拥有的所有资源都将永远挂起。当然,如果您收到大量的流式消息,您的内存使用量将会增加
由于您使用的是akka http,因此在调用http().bind*
时,您必须有一个ActorSystem
。您需要在decodeService
方法中访问它。另外,对我来说,计算组合字节流的方式似乎过于复杂。考虑这样写:
def decodeService: Flow[Message, Message, _] = Flow[Message].mapAsync(4) {
case m: BinaryMessage.Strict =>
Future.successful(m)
case BinaryMessage.Streamed(streamMsg) =>
streamMsg.runReduce(_ ++ _).map(BinaryMessage.Strict)
case m =>
Future.successful(m)
}.map {
case BinaryMessage.Strict(encodeMsg) =>
try {
WebServer.getWorkerActor ! QueueWork(protoMsg(this, encodeMsg))
TextMessage("[INFO] BinaryMessage.Strict")
} catch {
case NonFatal(e) =>
println("[ERROR] failed to send BinaryMessage.Strict: " + e)
TextMessage("[ERROR] failed receiving BinaryMessage.Strict")
}
case TextMessage.Strict(txt) => TextMessage("Succesfully receive text message")
case _ => TextMessage("Message type unsupported")
}
在这里,我们首先将所有二进制消息转换为BinaryMessage.Strict
,然后像处理原始代码一样处理它们。请注意,您必须在try
块中写入确认消息,否则即使出现异常,也会返回成功消息。此外,如果您决定根本不处理文本消息,代码可能会变得更简单:
def decodeService: Flow[Message, Message, _] = Flow[Message]
.filterNot(_.isText)
.mapAsync(4) {
case BinaryMessage.Strict(binary) =>
Future.successful(binary)
case BinaryMessage.Stream(binaryStream) =>
binaryStream.runReduce(_ ++ _)
.map { encodeMsg =>
try {
WebServer.getWorkerActor ! QueueWork(protoMsg(this, encodeMsg))
TextMessage("[INFO] BinaryMessage.Strict")
} catch {
case NonFatal(e) =>
println("[ERROR] failed to send BinaryMessage.Strict: " + e)
TextMessage("[ERROR] failed receiving BinaryMessage.Strict")
}
}
我收到以下错误:DescriptionResourcePathLocation类型找不到参数materializer的隐式值:akka.stream.materializer我已遵循您的第二个建议。由于我不处理文本消息,“找不到参数materializer的隐式值”:这就是我所说的,您必须使actor系统和materializer可用于
decodeService
方法。如果使用akka http,则必须同时使用这两种方法,因为必须创建一个物化器才能使用http().bind*
方法。因此,你已经在某处创建了它们;以适当的方式将它们传递给decodeService
方法,您就可以开始了。在您的情况下,我认为最简洁的方法是向decodeService
方法添加(隐式物化器:物化器)
参数。如果然后从akka http routes声明调用此方法,则很可能会在其中的作用域中使用materializer。但是,请恕我直言,因为您的应用程序的结构可能不同,例如,如果您使用一些DI容器,您可能更喜欢使用依赖项注入来传递物化器。