zoukankan      html  css  js  c++  java
  • 初识Netty:背景、现状与趋势

    Netty概述

    Netty由Trustin Lee (韩国,Line公司) 2004年开发。

    Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients.

    本质:网络应用程序框架
    实现:异步、事件驱动
    特性:高性能、可维护、快速开发
    用途:开发服务器和客户端

    Netty的结构图
    图片来源:https://netty.io
    其结构主要分三个部分:

    • 最底层的核心层:零拷贝的功能丰富的Byte Buffer、通用的通信层API、可扩展的事件模型
    • 支持的传输层服务:TCP-Socket&UDP-Datagram、HTTP Tunnel、In-VM Pipe
    • 支持的协议:HTTP(应用层协议)、WebSocket、Protobuf( 编解码方式)等

    Netty之Hello World

    Netty的Hello world代码相对来说要复杂一些,但客户端和服务端都包含了NioEventLoopGroup,Pipeline等相同的脚手架代码。

    在pom中引入netty的依赖

    <dependency>
        <groupId>io.netty</groupId>
        <artifactId>netty-all</artifactId>
        <version>4.1.50.Final</version>
    </dependency>
    

    创建Netty的Hello World。下面的示例程序使用netty的构建了一个基本的客户端-服务端的模型,由NioEventLoopGroup、ServerBootstrap、ChannelInitializer等组件构成。

    服务端代码:

    /**
    构建netty Server端启动的bootstrap.
    */
    public class EchoServer {
        public static void main(String[] args) throws InterruptedException {
            // 接收客户端连接
            EventLoopGroup bossGroup = new NioEventLoopGroup();
            // 处理客户端连接
            EventLoopGroup workerGroup = new NioEventLoopGroup();
    
            try {
                ServerBootstrap serverBootstrap = new ServerBootstrap();
                serverBootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
                .handler(new LoggingHandler(LogLevel.INFO))
                .childHandler(new EchoServerInitializer());
    
                ChannelFuture channelFuture = serverBootstrap.bind(8030).sync();
                channelFuture.channel().closeFuture().sync();
            } finally {
                bossGroup.shutdownGracefully(); 
                workerGroup.shutdownGracefully();
            }
        }
    }
    
    /**
    初始化server端的socket channel pipiline。
    */
    public class EchoServerInitializer extends ChannelInitializer<SocketChannel> {
        @Override
        protected void initChannel(SocketChannel socketChannel) throws Exception {
            ChannelPipeline pipeline = socketChannel.pipeline();
            pipeline.addLast(new LoggingHandler(LogLevel.INFO));
            pipeline.addLast(new EchoServerHandler());
        }
    }
    
    /**
    Server handler
    */
    public class EchoServerHandler extends ChannelInboundHandlerAdapter {
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            // 接收到客户端消息后,将消息原样输出给客户端
            ctx.write(msg);
        }
        
        @Override
            public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
            ctx.flush();
        }
        
        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
            cause.printStackTrace();
            ctx.close();
        }
    }
    

    客户端代码

    public class EchoClient {
        public static void main(String[] args) throws InterruptedException {
            // configure the client.
            EventLoopGroup group = new NioEventLoopGroup();
            
            try{
                Bootstrap bootstrap = new Bootstrap();
                bootstrap.group(group)
                .channel(NioSocketChannel.class)
                .option(ChannelOption.TCP_NODELAY,true)
                .handler(new EchoClientInitializer());
                
                // start the client.
                ChannelFuture channelFuture = bootstrap.connect("127.0.0.1",8030).sync();
                
                // wait util the connection is closed.
                channelFuture.channel().closeFuture().sync();
            }
            finally {
                // shut down the event loop to terminate all threads.
                group.shutdownGracefully();
            }
        }
    }
    
    public class EchoClientInitializer extends ChannelInitializer<SocketChannel> {
        @Override
        protected void initChannel(SocketChannel socketChannel) throws Exception {
            ChannelPipeline pipeline = socketChannel.pipeline();
            pipeline.addLast(new LoggingHandler(LogLevel.INFO));
            pipeline.addLast(new EchoClientHandler());
        }
    }
    
    public class EchoClientHandler extends ChannelInboundHandlerAdapter {
        private final ByteBuf firstMessage;
        
        public EchoClientHandler() {
            firstMessage = Unpooled.wrappedBuffer("I am echo message".getBytes());
        }
        
        @Override
        public void channelActive(ChannelHandlerContext ctx) throws Exception {
            ctx.writeAndFlush(firstMessage);
        }
        
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            ctx.write(msg);
        }
        
        @Override
        public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
            TimeUnit.SECONDS.sleep(3);
            ctx.flush();
        }
        
        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
            cause.printStackTrace();
            ctx.close();
        }
    }
    

    不直接使用JDK NIO

    Netty相比于Java Nio

    做的更多:

    • 支持常用应用层协议(如http),无需再过多考虑编解码的实现;
    • 解决TCP层传输问题:粘包、半包现象
    • 支持流量整形(流量控制,黑白名单等)
    • 完善的断连、Idle等异常处理

    做的更好:

    • 规避JDK NIO bug
    • epoll bug:异常唤醒空转导致CPU 100%
    • IP_TOS参数(IP包的优先级和QoS选项)使用时抛出异常
    • API更友好更强大
    • JDK的NIO一些API不够友好,功能薄弱。如ByteBuffer -> Netty's ByteBuf
    • 除NIO外,也提供了其它一些增强:ThreadLocal -> Netty's FastThreadLocal
    • 隔离变化、屏蔽细节
    • 隔离JDK NIO的实现变化:nio -> nio2(aio) -> ...
    • 屏蔽JDK NIO的实现细节

    选择Netty的原因

    业界流行的网络通信框架,但是Java网络编程,只选择Netty。

    • Apache Mina
      netty对MINA进行重构,并解决了已知问题
    • Sun Grizzly
      用的少、文档少、更新少
    • Apple Swift NIO、ACE
      其它语言,不考虑
    • Cindy
      生命周期不长
    • Tomcat、Jetty
      还没有独立出来

    Netty发展史

    从归属组织上看发展

    • JBoss
      在4.0之前属于JBoss,在包命名管理上可以看出
    • Netty
      4.0之后在Netty社区进行管理

    从版本演变上看发展

    • 2004年6月Netty2发布
      声称Java社区中第一个基于事件驱动的易用网络框架
    • 2008年10月Netty3发布
    • 2013年7月Netty4发布
    • 2013年12月发布5.0.0.Alpha1
    • 2015年1月废弃5.0.0
      复杂(使用ForkJoinPool)
      没有证明有明显性能优势
      维护不过来

    Netty社区
    https://github.com/netty/netty

    分支

    • 4.1 master,支持Android(最优版本选择)
    • 4.0 相较于之前版本主要变更有:线程模型优化、包结构、命名(更新缓慢)

    一些典型项目

    • 数据库:Cassandra
    • 大数据处理:Spark、Hadoop
    • 消息队列:RocketMQ
    • 检索:Elasticsearch
    • 框架:gRPC、Apache Dubbo、Spring5
    • 分布式协调器:Zookeeper
    • 工具类:async-http-client
    • 其它参考:https://netty.io/wiki/adopters.html

    趋势

    • 更多流行协议的支持
      目前已经支持dns、http、https、redis、xml等主流协议
    • 紧跟JDK新功能步伐
    • 更多易用、人性化功能
    • IP地址黑白名单、流量整形等
    • 使用Netty的应用越来越多
  • 相关阅读:
    Docker Swarm与Kubernetes对比分析如何选择?
    dockerMesos配置项是怎么解析的?案例详解
    Python爬虫如何提取百度搜索到的内容?案例教你
    python之urllib2是如何运用的?正确方法教你
    Python之解BS4库如何安装与使用?正确方法教你
    Python爬虫之Selenium环境如何正确配置?本文详细讲解
    Python爬虫之GET和POST请求然后正确运用详解
    Python怎么识别文字?正确 的方法详解
    Python爬虫如何获取页面内所有URL链接?本文详解
    在Java中,为什么十六进制数0xFF取反之后对应的十进制数是-256呢?
  • 原文地址:https://www.cnblogs.com/CodePastry/p/13251505.html
Copyright © 2011-2022 走看看