我正在使用akka-http来实现Web套接字服务器。
以下是它的请求处理程序代码:
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")
}
}
我的网络服务器每1分钟频繁获取一次数据流。我看到记忆力在增长。如果我不处理流式消息,它能够保持。客户端和服务器之间的连接也是持久的。
我是否错误地使用了Flows / Sink / Source?如何刷新流?
由于
答案 0 :(得分:3)
嗯,最明显的问题是,您为收到的每条流信息创建了一个全新的ActorSystem
。 ActorSystem
就像是演员的线程池;你想尽可能少地创建它们,理想情况下只有一个用于整个应用程序。不仅你为每条消息创建它们,你也不会关闭它们 - 所有在ActorSystem
中配置的调度程序,它所拥有的所有资源将永远保持不变。当然,如果您收到大量流式消息,您的内存使用量将会增长。
由于您使用的是akka-http,因此您必须在其中调用ActorSystem
Http().bind*
。您需要在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")
}
}