Может кто-то объяснит основные различия между Akka HTTP и Netty? Netty предлагает другие протоколы, такие как FTP. Akka HTTP можно использовать в Scala и Java и основывается на модели актера. Но кроме этого оба они асинхронны. Когда я буду использовать Akka HTTP и когда Netty? Каковы типичные варианты использования для обоих?
Различия между Akka HTTP и Netty
Ответ 1
Вот что я вижу в качестве основных контрастных областей:
Стиль кодирования
Возьмем 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)
}
Для 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();
}
}
директивы
Одна из самых сильных сторон akka-http, на мой взгляд, Directives, которые предоставляют DSL для сложной логики обработки запросов. Предположим, например, что мы хотели ответить одним сообщением для запросов GET
и PUT
и другим сообщением для всех других методов запроса. Это очень просто с помощью директив:
val route =
(get | put) {
complete("You sent a GET or PUT")
} ~
complete("Shame shame")
Если вы хотите получить позицию заказа и количество из пути запроса:
val route =
path("order" / Segment / IntNumber) { (item, qty) =>
complete(s"Your order: item: $item quantity: $qty")
}
Эта функция не существует внутри netty.
Streaming
Один последний элемент, который я бы заметил, - это потоковая передача. 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)
}
}
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)
}
}