Akka HTTP和Netty之间的差异

Kri*_*ris 14 netty akka-http

有人可以解释一下Akka HTTPNetty之间的主要区别吗?Netty还提供其他协议,如FTP.Akka HTTP可以在Scala和Java中使用,并且基于actor模型构建.但除此之外,两者都是异步的.什么时候我会使用Akka HTTP和Netty?两者的典型用例是什么?

Kon*_*lin 6

Akka HTTP Server 是具有高级 DSL 的 HTTP 和 WebSocket 服务器。Netty 是一个低级的“异步事件驱动的网络应用程序框架”,允许实现您需要的任何 TCP/UDP 协议。

所以,除非你需要一些底层网络,否则你不应该使用普通的 Netty。使用 Netty 的 Akka HTTP 的等价物将类似于Netty Reactor,而在它们之上的更高级别可能是诸如 Spring WebFlux 之类的东西。

另一方面,Akka-HTTP 基于 Akka Actors,这是一个建议特定应用程序模型的框架。此外,Akka 依赖于 Scala,如果您已经了解 Scala,或者您在调试应用程序时尚未准备好学习 Scala,这可能会影响您的决定。

  • Akka 依赖 Scala 的说法具有误导性。它为 Java 用户提供了完整的 API(和并行文档),您只需将 Maven 依赖项添加到 groupId:com.typesafe.akka artifactId:akka-actor_2.12 就可以了。 (2认同)
  • @MurrayToddWilliams 它公开了 Java API,但它是在 Scala 中实现的,并且依赖于 Scala 库。因此,如果您需要使用 Akka 调试某些东西,您会遇到 Scala。如果您的项目中有其他依赖于 Scala 的库,您必须确保它们依赖于相同的 Scala 版本。 (2认同)
  • 很公平。我只是指出 Akka 被设计为可供 Java 程序员使用(我认为 Lightbend 已经付出了一些努力,使其不仅仅是二流的努力),尽管它依赖于 Scala 库,但它并不依赖于 Scala 的库。编译器、构建系统等。但你所说的是正确的。 (2认同)

Ram*_*gil 5

我认为这是主要的可对比领域:

编码风格

让我们以netty的废弃服务器示例为例,这是最简单的示例,因为它是文档中的第一个。

因为akka-http这相对简单:

object WebServer {
  def main(args: Array[String]) {

    implicit val system = ActorSystem("my-system")
    implicit val materializer = ActorMaterializer()

    val route =
      extractRequestEntity { entity =>
        onComplete(entity.discardBytes(materializer)) { _ =>
          case _ => complete(StatusCodes.Ok)
        }
      }

    val bindingFuture = Http().bindAndHandle(route, "localhost", 8080)
}
Run Code Online (Sandbox Code Playgroud)

对于netty来说,这更为冗长:

public class DiscardServerHandler extends ChannelInboundHandlerAdapter { // (1)

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) { // (2)
        // Discard the received data silently.
        ((ByteBuf) msg).release(); // (3)
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { // (4)
        // Close the connection when an exception is raised.
        cause.printStackTrace();
        ctx.close();
    }
}

public class DiscardServer {

    private int port;

    public DiscardServer(int port) {
        this.port = port;
    }

    public void run() throws Exception {
        EventLoopGroup bossGroup = new NioEventLoopGroup(); // (1)
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap b = new ServerBootstrap(); // (2)
            b.group(bossGroup, workerGroup)
             .channel(NioServerSocketChannel.class) // (3)
             .childHandler(new ChannelInitializer<SocketChannel>() { // (4)
                 @Override
                 public void initChannel(SocketChannel ch) throws Exception {
                     ch.pipeline().addLast(new DiscardServerHandler());
                 }
             })
             .option(ChannelOption.SO_BACKLOG, 128)          // (5)
             .childOption(ChannelOption.SO_KEEPALIVE, true); // (6)

            // Bind and start to accept incoming connections.
            ChannelFuture f = b.bind(port).sync(); // (7)

            // Wait until the server socket is closed.
            // In this example, this does not happen, but you can do that to gracefully
            // shut down your server.
            f.channel().closeFuture().sync();
        } finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }

    public static void main(String[] args) throws Exception {
        new DiscardServer(8080).run();
    }
}
Run Code Online (Sandbox Code Playgroud)

指令

我认为,akka-http的最大优势之一就是Directives,它为复杂的请求处理逻辑提供了DSL。例如,假设我们想用一条消息来响应GETPUT请求,而用另一条消息来响应所有其他请求方法。使用指令非常简单:

val route = 
  (get | put) {
    complete("You sent a GET or PUT")
  } ~ 
  complete("Shame shame")
Run Code Online (Sandbox Code Playgroud)

如果要从请求路径获取订单商品和数量:

val route = 
  path("order" / Segment / IntNumber) { (item, qty) =>
    complete(s"Your order: item: $item quantity: $qty")
  }
Run Code Online (Sandbox Code Playgroud)

Netty中不存在此功能。

流媒体

我要指出的最后一项是关于流媒体。akka-http基于akka-stream。因此,akka-http可以很好地处理请求实体的流式传输性质。以netty的“ 查看接收的数据”示例为例,akka看起来像

//a stream with a Source, intermediate processing steps, and a Sink
val entityToConsole : (RequestEntity) => Future[Done] =
  (_ : RequestEntity)
    .getDataBytes()
    .map(_.utf8String)
    .to(Sink.foreach[String](println))
    .run()

val route = 
  extractRequestEntity { entity =>
    onComplete(entityToConsole(entity)) { _ =>
      case Success(_) => complete(200, "all data written to console")
      case Failure(_) => complete(404, "problem writing to console)
    }
  }
Run Code Online (Sandbox Code Playgroud)

Netty必须使用字节缓冲区和while循环来处理相同的问题:

@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
    ByteBuf in = (ByteBuf) msg;
    try {
        while (in.isReadable()) { // (1)
            System.out.print((char) in.readByte());
            System.out.flush();
        }
    } finally {
        ReferenceCountUtil.release(msg); // (2)
    }
}
Run Code Online (Sandbox Code Playgroud)