【Java网络编程】:Netty原理总结

前言

最近在研究Flink源码时,才第一次听到Netty这个框架,因为Flink的内部数据通信和传输是基于Netty来实现的。后来查了下,Spark内部的数据传输也是基于Netty。所以不得不对Netty做番认识。主要是方便以后定位问题。

1. Netty简单介绍

Netty是一个NIO客户端-服务器框架,它支持快速、简单地开发网络应用程序,如协议服务器和客户机。它大大简化了网络编程,如TCP和UDP套接字服务器。

“快速和简单”并不意味着生成的应用程序将受到可维护性或性能问题的影响。Netty经过精心设计,并积累了许多协议(如ftp、smtp、http)的实施经验,以及各种二进制和基于文本的遗留协议。因此,Netty成功地找到了一种方法,可以在不妥协的情况下实现轻松的开发、性能、稳定性和灵活性。

附上一张Netty官网的架构图:
在这里插入图片描述

主要特点

设计

  • 各种传输类型的统一API-阻塞和非阻塞套接字
  • 基于一个灵活的可扩展事件模型,该模型允许清晰的关注点分离
  • 高度可定制的线程模型-单线程、一个或多个线程池(如SEDA)
  • 真正的无连接数据报套接字支持(从3.1开始)

易用

  • 很好的javadoc,官网demo
  • 没有其他的依赖

性能

  • 高吞吐,低延迟
  • 更少的资源消耗
  • 减少非必需的内存拷贝

安全性

  • 完整的SSL/TLS和StartTLS支持

2. Reactor模型

Netty是典型的Reactor模型结构,所以有必要先了解下Reactor模型。Reactor模型就是将消息放到了一个队列中,通过异步线程池对其进行消费。

Reactor中的组件:

  • Reactor: Reactor是IO事件的派发者。
  • Acceptor: Acceptor接受client连接,建立对应client的Handler,并向Reactor注册此Handler。
  • Handler: 和一个client通讯的实体,按这样的过程实现业务的处理。一般在基本的Handler基础上还会有更进一步的层次划分,用来抽象诸如decode,process和encoder这些过程。比如对Web Server而言,decode通常是HTTP请求的解析,process的过程会进一步涉及到Listener和Servlet的调用。业务逻辑的处理在Reactor模式里被分散的IO事件所打破,所以Handler需要有适当的机制在所需的信息还不全(读到一半)的时候保存上下文,并在下一次IO事件到来的时候(另一半可读了)能继续中断的处理。为了简化设计,Handler通常被设计成状态机,按GoF的state pattern来实现。

2.1. Reactor单线程模型

在这里插入图片描述

这个模型和上面的NIO流程很类似,只是将消息相关处理独立到了Handler中去了!

虽然上面说到NIO一个线程就可以支持所有的IO处理。但是瓶颈也是显而易见的!我们看一个客户端的情况,如果这个客户端多次进行请求,如果在Handler中的处理速度较慢,那么后续的客户端请求都会被积压,导致响应变慢!所以引入了Reactor多线程模型!

2.2. Reactor多线程模型

在这里插入图片描述
Reactor多线程模型就是将Handler中的IO操作和非IO操作分开,操作IO的线程称为IO线程,非IO操作的线程称为工作线程!这样的话,客户端的请求会直接被丢到线程池中,客户端发送请求就不会堵塞!

但是当用户进一步增加的时候,Reactor会出现瓶颈!因为Reactor既要处理IO操作请求,又要响应连接请求!为了分担Reactor的负担,所以引入了主从Reactor模型!

2.3. 主从Reactor模型

在这里插入图片描述

主Reactor用于响应连接请求,从Reactor用于处理IO操作请求!

3. NioEventLoopGroup 与 Reactor 线程模型的对应

Netty的线程模型并发固定不变,通过在启动辅助类中创建不同的EventLoopGroup实例并进行适当的参数配置,就可以支持上述三种Reactor线程模型。

3.1. Netty实现单线程模型

服务端代码如下:

/**
     * Netty单线程模型服务端代码示例
     * @param port
     */
    public void bind(int port) {
   
        EventLoopGroup reactorGroup = new NioEventLoopGroup();
        try {
   
            ServerBootstrap b = new ServerBootstrap();
            b.group(reactorGroup, reactorGroup)
                .channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<SocketChannel>() {
   
                    @Override
                    protected void initChannel(SocketChannel ch) throws Exception {
   
                        ch.pipeline().addLast("http-codec", new HttpServerCodec());
                        ch.pipeline().addLast("aggregator", new HttpObjectAggregator(65536));
                        ch.pipeline().addLast("http-chunked", new ChunkedWriteHandler());
                        //后面代码省略
                    }
                });
        
            Channel ch = b.bind
  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值