Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/sql-server-2008/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala 在使用akka http实现web socker服务器时,堆内存正在增长_Scala_Akka_Akka Stream_Akka Http - Fatal编程技术网

Scala 在使用akka http实现web socker服务器时,堆内存正在增长

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

我使用AKKAHTTP实现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")
    }
  }
我的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容器,您可能更喜欢使用依赖项注入来传递物化器。