Netty

1. 学习目的

  1. BIO、NIO和AIO的区别?
  2. NIO的组成?
  3. Netty的特点?
  4. Netty的线程模型?
  5. TCP 粘包/拆包的原因及解决方法?
  6. 了解哪几种序列化协议?
  7. 如何选择序列化协议?
  8. Netty的零拷贝实现?
  9. Netty的高性能表现在哪些方面?
  10. NIOEventLoopGroup源码?

2.学习Netty

  1. 为什么学习Netty
    分布式的时代 分布式框架中要用到
    Spring5 去servlet化,底层使用netty
    SpringBoot 内部实现web容器
    Zookeeper 底层通信
    Dubbo 分布式服务框架,多协议支持(RPC) Netty
    为成为架构师筑基
  2. Netty能帮助我们解决什么问题?
    框架:简化开发一系列解决方案的集合
    封装IO操作的框架
    复杂的业务场景中,没有说用一个单独的IO APi,经常遇到的问题:手写线程(Thread),多线程处理、性能问题、单双工,影响业务的开发。
    IO + 多线程来解决问题
    类似的框架:Mina Netty的前身(不是一个人开发的)
  3. 为什么要封装IO操作
    阻塞和非阻塞:
    自己回答:处理端在处理数据的时候,如果被处理对象的数据没有准备好,线程会阻塞在当前线程,譬如socket.accept()方法 ,在等待网络连接的时候,如果没有请求连接,线程会处于阻塞状态,如果是非阻塞模型,当前线程可以去处理其他事物

Input Output
是相对于内存而言
磁盘只是input output的一端,除了磁盘还有网络

IO模型

阻塞非阻塞:参照IO操作 读数据或取数据时候的一种处理机制

BIO阻塞:

NIO:
通道 Buffer 轮询

同步与异步

在处理数据的时候,在同一时间点能同时做多个处理:异步
在同一时间只能做一个处理:同步

  • 多路复用体现:
    ServerSocketChannel
    SocketChannle (从多路复用器中拿到客户端的引用)
    都来自于 (SelectionKey)key.channel

NIO的操作过于繁琐,于是有了Netty,对NIO进行了封装。

IO(BIO)Block IO 同步阻塞IO
NIO Non-Block IO 同步非阻塞IO (可以使用线程池的方式,实现异步)
AIO Async IO 异步非阻塞IO (事件驱动,回调实现异步)

3. NIO

3.1 NIO的核心组件(三件套)

  1. Buffer、Selector、Channel、

3.1.1 Buffer

  1. 缓冲区属性
    容量:capacity:表示该缓冲区可以保存多少数据。
    极限:limit:表示缓冲区的当前终点,不能对缓冲区中超过极限的数据进行读写操作。极限可以修改,有利于缓冲区的重用。
    位置:position:表示缓冲区中下一个读写单元的位置,每次读写缓冲区的数据时,都会改变位置值,为下一次读写数据做准备。
    属性关系为 capacity>=limit>=position>=0
  2. 改变缓冲区3个属性的方法
    clear():把极限限制为容量值,再把位置设为0.
    flip():把极限值设为位置值,再把位置设为0.
    rewind():不改变极限,把位置设为0.
  3. ByteBuffer类没有提供公开的构造方法,但是提供了两个获得ByteBuffer实例的静态工厂方法。
    allocate(int capacity):返回一个ByteBuffer对象
    directAllocate(int capacity):返回一个ByteBuffer对象,称为直接缓冲区
  4. 所有的缓冲区都提供了读写缓冲区的方法
    get():相对读。从缓冲区的当前位置读取一个单元的数据,读完后把位置值加1。
    get(index):决对读。从参数index指定的位置读取一个单元的数据。
    put():相对写。向缓冲区的当前位置写入一个单元的数据,写完后把位置值加1.
    put(int index):绝对写。向参数index指定的位置写入一个单元的数据。
  • buffer操作的流程
    Netty

3.1.2 Selector

3.1.3 Channel

是多路复用的基础
解决的问题:

  1. 请求过多,导致连接线程过多
  2. 处理数据较大,导致线程长时间占用 也会导致阻塞
    selector模型,IO调用不会被阻塞,

3.2何为多路复用

3.3Netty支持的功能与特性

Netty

Netty封装了NIO,Reactor模型,声明BOSSS线程,worker线程,可以修改BOSS线程和worker线程的数量

  1. 编码过程
    //Netty服务 //NIO //BIO
    ServerBootstrap ServerSocketChannel ServerSocket

主线程处理类,这样的写法,底层使用反射

子线程处理类 ,Handler

无锁化串行编程

编码器

解码器

业务处理逻辑

针对主线程的最大配置数

针对子线程的配置,保持长连接

//SocketChannel的封装
ChannelHandlerContext

  • 总结
    Netty就是一个同时支持多协议的网络通信框架
    官网:
Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients.
Netty是一个异步事件驱动的网络应用框架,用于快速开发可维护的高性能协议服务器和客户端。

协议编解码
2. Netty支持的协议
官网图

Netty的高性能

比传统IO性能提升了8倍多。

  • 传统RPC调用性能差的三宗罪
  1. 阻塞IO不具备弹性伸缩能力(一个请求,一个应答),高并发导致宕机
  2. Java序列化编码、解码的性能问题,直接是字节流的读写
  3. 传统IO线程模型过多占用CPU资源
  • 高性能的三个主题:
    IO模型 传输
    数据协议 协议 (协议越简单,通信效率越高)
    线程模型 线程 (编解码的处理)
  • 异步非阻塞通信
    NioEventLoop聚合了多路复用器Selector,可以同时并发处理成百上千个客户端Channel,由于读写操作都是非阻塞的,可以充分提升IO线程的运行效率,避免由于频繁阻塞IO阻塞导致的线程挂起。
  • 零拷贝(直接缓冲区)
  1. 接收和发送ByteBuffer使用堆外内存直接内存进行socket读写。
  2. 提供了组合Buffer对象,可以聚合多个ByteBuffer对象。
  3. transfreTo()直接将文件缓冲区的数据发送到目标Channel,避免循环导致内存拷贝的问题。
  • 内存池
    三个维度
  1. Pooled与unPooled(池化与非池化)
  2. UnSage和非UnSafe(底层读写与应用程序读写)
  3. Heap与Direct(堆内存与堆外内存)
    netty有pooled buffer 和 unpooled buffer
    pooled 先初始化一定大小的空间 ,读写效率 ,内存分配 堆外内存读写高,但是内存管理比较麻烦。
  • 高效的Reactor线程模型
  1. Reactor单线程模型
    netty的接收连接,分发调度、读写都由一个线程完成。
  2. Reactor多线程模型
    反应接待线程、反应线程池(处理读写,编解码)
  3. 主从Reactor多线程模型
    接收线程 主线程池(调度不同模块业务的资源) 派发不同的业务逻辑线程
    从线程
  • 无锁化的串行设计理念
    Pipeline(管道) pipeline的添加是有顺序的。
    pipeline的工作模式:责任链模式,双向链表 两种类型的handle
    Inbound OutBound 负责数据处理的触发和回调 什么时候触发,什么时候回调
    pipeline可以巧妙的解决权限问题,有一个好用的东西,事件传播,异常和消息可以一层层往上传。

MessageToMessageEncoder extends ChannelOutboundHandlerAdapter 是一个OutBound,OutBound说明数据需要一个回调处理了。

  • 高效的并发编程 Netty的高效并发编程主要体现在如下几点:
  1. volatile的大量、正确使用
  2. CAS和原子类的广泛使用
  3. 线程安全容器的使用
  4. 通过读写锁提升并发性能
  • 高性能的序列化框架
    影响序列化性能的关键因素总结如下:
  1. 序列化后的码流大小(影响网络带宽的占用)
  2. 序列化&反序列化的性能(CPU资源占用)
  3. 是否支持跨语言(异构系统的对接和开发语言切换)
  • 灵活的TCP参数配置能力

Netty核心之服务端Channel源码分析

服务端Channel的创建
bind()[用户代码入口]
initAndRegister()[初始化并注册]
newChannel()[创建服务端channel]
init()[初始化服务端Channel]

Netty

上一篇:css readonly和disabled的区别


下一篇:css的优先级和权重问题 以及!important优先级