Netty培训文档

一、IO的基本概念

1.阻塞与非阻塞

阻塞与非阻塞是描述进程在访问某个资源时,数据是否准备就绪的的一种处理方式。当数据没有准备就绪时:
阻塞:线程持续等待资源中数据准备完成,直到返回响应结果。
非阻塞:线程直接返回结果,不会持续等待 资源准备数据结束 后才响应结果。

2.同步与异步

同步与异步是指访问数据的机制。
同步:一般指主动请求并等待IO操作完成的方式。
异步:指主动请求数据后便可以继续处理其它任务,随后等待IO操作完毕的通知。

3.IO模型

五大IO模型

  1. 阻塞IO模型(传统IO模型)
  2. 非阻塞IO模型
  3. 多路复用IO模型
  4. 信号驱动IO模型
  5. 异步IO模型

参考地址:https://blog.csdn.net/ocean_fan/article/details/79622956

BIO

BIO ,全称 Block-IO ,是一种阻塞 + 同步的通信模式。
是一个比较传统的通信方式,模式简单,使用方便。但并发处理能力低,通信耗时,依赖网速。

NIO

NIO ,全称 New IO ,也叫 Non-Block IO
是一种非阻塞 + 同步的通信模式。

AIO

AIO ,全称 Asynchronous IO ,也叫 NIO2 ,是一种非阻塞 + 异步的通信模式。在 NIO 的基础上,引入了新的异步通道的概念,并提供了异步文件通道和异步套接字通道的实现。

IO比较

比较项BIONIOAIO
是否阻塞阻塞非阻塞非阻塞
同步异步同步同步异步
性能一般
吞吐量

但是在绝大多数我们日常业务场景,NIO 和 AIO 的性能差距实际没这么大。在 Netty5 中,基于 AIO 改造和支持,最后发现,性能并没有想象中这么强悍,所以 Netty5 被废弃,而是继续保持 Netty4 为主版本,使用 NIO 为主。

二、NIO三大组件

1.Channel

Channel是一个双向通道,与传统IO操作只允许单向的读写不同的是,NIO的Channel允许在一个通道上进行读和写的操作

2.Buffer

它是一个缓冲区,实际上是一个容器,一个连续数组。Channel提供从文件、网络读取数据的渠道,但是读写的数据都必须经过Buffer。

3.Selector(多路复用器)

Selector与Channel是相互配合使用的,将Channel注册在Selector上之后,才可以正确的使用Selector,但此时Channel必须为非阻塞模式。Selector可以监听Channel的四种状态(Connect、Accept、Read、Write),当监听到某一Channel的某个状态时,才允许对Channel进行相应的操作。
几个状态:

■ Connect:某个Channel成功连接到另一个服务器称为“连接就绪”;

■ Accept:一个ServerSocketChannel准备好接收新进入的连接,称为“接收就绪”;

■ Read:一个有数据可读的通道可以说是“读就绪”;

■ Write:等待写数据的通道可以说是“写就绪”。

4. NIO流程

Created with Raphaël 2.2.0 开始 ServerSocketChannel 监听端口 Channel注册到Selector 监听Selector事件 处理事件

三、netty

netty简介

Netty是一个Java的开源框架。提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序。
Netty是一个NIO客户端,服务端框架。允许快速简单的开发网络应用程序。例如:服务端和客户端之间的协议,它简化了网络编程规范。

NIO和netty

NIO开发的问题

1、跨平台和兼容性问题:NIO依赖于操作系统,在Linux和Windows平台上表现的结果有所不同。
2、扩展ByteBuffer:ByteBuffer允许包装一个byte[]来获得一个实例,可以尽量减少内存拷贝。但是它不能被扩展,ByteBuffer的构造函数是私有的。
3、epoll BUG:可能会导致无效的状态和100%CPU利用率

Netty的优点:
1、API使用简单,开发门槛低;
2、功能强大,预置了多种编解码功能,支持多种主流协议;
3、定制功能强,可以通过ChannelHandler对通信框架进行灵活的扩展;
4、性能高,通过与其他业界主流的NIO框架对比,Netty综合性能最优;
5、成熟、稳定,Netty修复了已经发现的NIO所有BUG;
6、社区活跃;
7、经历了很多商用项目的考验。

Netty粘包和拆包

netty使用的是tcp协议,非http。

TCP是一个“流”协议,所谓流,就是没有界限的一串数据。可以想象为河流中的水,并没有分界线。TCP底层并不了解上层业务数据的具体含义,它会根据TCP缓冲区的实际情况进行包的划分,所以在业务上认为,一个完整的包可能会被TCP拆分成多个包进行发送,也有可能把多个小的包封装成一个大的数据包发送,这就是所谓的TCP粘包和拆包问题。

在这里插入图片描述

解决方案:

➢ 消息定长,例如每个报文的大小为固定长度200字节,如果不够,空位补空格;

➢ 在包尾增加回车换行符进行分割,例如FTP协议;

➢ 将消息分为消息头和消息体,消息头中包含消息总长度(或消息体总长度)的字段;

➢ 更复杂的应用层协议;

常见的几个编解码器:

1、 LineBasedFrameDecoder:以换行符为结束标志的编解码,支持携带结束符或者不携带结束符两种解码方式,同时支持配置单行的最大长度。

2、 DelimiterBasedFrameDecoder:实现自定义分隔符作为消息的结束标志,完成解码。

3、 FixedLengthFrameDecoder:是固定长度解码器

Netty性能优化序列化Protobuf

protobuf介绍

protobuf介绍:https://blog.csdn.net/jiaweiok123/article/details/87809831

protobuf使用

1.下载

protobuf下载地址:https://github.com/protocolbuffers/protobuf/releases/tag/v3.4.0

在这里插入图片描述

2.配置环境变量

在这里插入图片描述

输入protoc --version查看是否安装成功

3.编写proto文件
syntax = "proto3"; // PB协议版本

package com.zhaolaobao.netty.protobuf.pojo;// 包名 (生成java类第一行的package)


option java_package = "com.zhaolaobao.netty.protobuf.pojo"; // 实际生成的java类的路径,必须和package保持一致,否则java类报错

option java_outer_classname="Test"; // 生成类的类名,注意:下划线的命名会在编译的时候被自动改为驼峰命名

//生成的内部类的类名,注意不能与java_outer_classname相同
message Test2 {
    int32 id = 1; // int 类型
    string name = 2; // string 类型
    string email = 3;

}
4.编写脚本并执行
protoc -I=./ --java_out=D:/workspace/zhaolaobao-saas/zhaolaobao-netty/src/main/java Test.proto

-l后面跟着proto文件的路径
–java-out跟着生成的java文件的路径(和proto文件的package组合成文件路径地址)

netty高性能

1.同步非阻塞通信模型

2.高效的Reactor线程模型

常用的Reactor线程模型有三种,分别如下:

  1. Reactor单线程模型;

在这里插入图片描述

  1. Reactor多线程模型;

在这里插入图片描述

  1. 主从Reactor多线程模型;

在这里插入图片描述

3.无锁化的串行设计

在这里插入图片描述
在大多数场景下,并行多线程处理可以提升系统的并发性能。但是,如果对于共享资源的并发访问处理不当,会带来严重的锁竞争,这最终会导致性能的下降。为了尽可能地避免锁竞争带来的性能损耗,可以通过串行化设计,既消息的处理尽可能在同一个线程内完成,期间不进行线程切换,这样就避免了多线程竞争和同步锁。

为了尽可能提升性能,Netty采用了串行无锁化设计,在IO线程内部进行串行操作,避免多线程竞争导致的性能下降。表面上看,串行化设计似乎CPU利用率不高,并发程度不够。但是,通过调整NIO线程池的线程参数,可以同时启动多个串行化的线程并行运行,这种局部无锁化的串行线程设计相比一个队列——多个工作线程模型性能更优。

4.高效的并发编程

Netty中高效并发编程主要体现:

  1. volatile的大量、正确使用;使用volatile来代替 synchronized关键字,提升并发访问的性能。
    NioEventLoop.ioRatio
  2. CAS和原子类的广泛使用;
    ChannelOutboundBuffer.TOTAL_PENDING_SIZE_UPDATER AtomicLongFieldUpdater类型
  3. 线程安全容器的使用;
    NioEventLoop.newTaskQueue()
  4. 通过读写锁提升并发性能。

5.高性能的序列化框架

影响序列化性能的关键因素总结如下:

  1. 序列化后的码流大小(网络宽带的占用);
  2. 序列化与反序列化的性能(CPU资源占用);
  3. 是否支持跨语言(异构系统的对接和开发语言切换)。

Netty默认提供了对GoogleProtobuf的支持,通过扩展Netty的编解码接口,用户可以实现其他的高性能序列化框架。

其实就是因为Java序列化的性能太差,催生了很多各种高性能的开源序列化技术和框架(性能差只是其中一个原因,还有跨语言等因素)

6.零拷贝

零拷贝,只是减少了拷贝的次数。Netty的“零拷贝”主要体现在三个方面:

  1. Netty的接收和发送ByteBuffer采用DIRECT BUFFERS,使用堆外直接内存进行Socket读写,不需要进行字节缓冲区的二次拷贝。
  2. 第二种“零拷贝”的实现CompositeByteBuf,它对外将多个ByteBuf封装成一个ByteBuf,对外提供统一封装后的ByteBuf接口。
  3. 第三种“零拷贝”就是文件传输,Netty文件传输类DefaultFileRegion通过transferTo方法将文件发送到目标Channel中。

7.内存池

  1. 堆外内存回收
  2. 不用频繁分配内存

8.灵活的tcp参数配置

  1. SO_RCVBUF和SO_SNDBUF:通常建议值为128KB或者256KB;
  2. TCP_NODELAY:NAGLE算法通过将缓冲区内的小封包自动相连,组成较大的封包,阻止大量小封包的发送阻塞网络,从而提高网络应用效率。但是对于时延敏感的应用场景需要关闭该优化算法;
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值