IO,即输入(Input)输出(Output)的简写,是描述计算机软硬件对二进制数据的传输、读写等操做的统称。
按照软硬件可分为:java
按照处理的方式可分为:数据库
按照数据类型可分为:编程
随着软硬件技术的飞速发展,IO性能也有了很大的发展,但IO仍是影响现代计算机系统性能最重要的因素之一后端
IOPS,IO系统每秒所执行IO操做的次数,是一个重要的用来衡量系统IO能力的一个参数。对于单个磁盘组成的IO系统来讲,计算它的IOPS不是一件很难的事情,只要咱们知道了系统完成一次IO所须要的时间的话咱们就能推算出系统IOPS来。
磁盘IOPS的计算:数组
IO Time = 寻址时间 + 60s/转速/2 + IO块大小/传输速率 IOPS = 1/IO Time = 1/(寻址时间 + 60s/转速/2 + IO块大小/传输速率)
不一样转速的磁盘IO:缓存
IO响应时间也被称为IO延时(IO Latency),IO响应时间就是从操做系统内核发出的一个读或者写的IO命令到操做系统内核接收到IO回应的时间,注意不要和单个IO时间混淆了,单个IO时间仅仅指的是IO操做在磁盘内部处理的时间,而IO响应时间还要包括IO操做在IO等待队列中所花费的等待时间。
吞吐量是指单位时间内传输的数据量的总和.
一个系统吞吐量一般由QPS(TPS)、并发数两个因素决定,每套系统这两个值都有一个相对极限值,在应用场景访问压力下,只要某一项达到系统最高值,系统的吞吐量就上不去了,若是压力继续增大,系统的吞吐量反而会降低,缘由是系统超负荷工做,上下文切换、内存等等其它消耗致使系统性能降低。服务器
QPS(TPS)=并发数/平均响应时间
IO是包括Java在内全部编程语言最重要的特性和模块之一,由于不论是读写文件,分配回收内存和网络通讯都离不开IO。 同时IO也是计算机系统最主要的性能瓶颈和问题之一,特别是在分布式系统中IO问题更显得突出。
Java最开始只支持BIO,到了JDK1.4开始支持NIO,在JDK7中支持NIO2.0(AIO)网络
JavaIO按照数据类型分为:多线程
BIO即Blocking IO,同步而且阻塞。
在BIO中,用户线程发起一个IO操做之后,必须等待IO操做的完成,只有当真正的IO完成之后,用户线程才能继续操做。架构
如上图,用户发起一个请求到服务器,服务器接收后分配一个处理线程来进行处理,同时用户线程阻塞以等待处理线程处理完成后,返回数据到用户线程,用户线程继续往下执行。
BIO模型的问题:
为了解决BIO模型中线程一对一的问题,经过伪异步IO进行处理。
如上图,服务器接收到用户线程的请求后,经过后端的线程池分配线程进行处理。因为线程池的大小能够设置,所以能够限制服务端的资源使用。
伪异步IO实际上只是对一对一线程模型进行改进,没有解决同步阻塞的问题
NIO即Non-Blocking IO,是经过非阻塞的方式实现IO的技术,Java在1.4后提供该技术的支持。
在Java NIO中,全部的数据操做都时在缓冲区中完成的。在读取数据时,它直接读缓冲区的数据;写入数据时,也是将数据写入缓存去。
缓冲区其实是一个数组,包括:
一个 Buffer 主要由 position、limit、capacity 三个变量来控制读写的过程。这三个变量在读和写时分别表明的含义以下:
在写模式下,Buffer的limit表示你最多能往Buffer里写多少数据。当切换Buffer到读模式时, limit表示你最多能读到多少数据。所以,当切换Buffer到读模式时,limit会被设置成写模式下的position值。换句话说,你能读到以前写入的全部数据.
Channel是一个全双工的双向通道,能够经过它读取和写入数据。Channel老是从Buffer读取数据或者向Buffer写入数据.
Java Channel包括:
Selector类是NIO的核心类,Selector可以检测多个注册的通道上是否有事件发生,若是有事件发生,便获取事件而后针对每一个事件进行相应的响应处理。这样一来,只是用一个单线程就能够管理多个通道,也就是管理多个链接。这样使得只有在链接真正有读写事件发生时,才会调用函数来进行读写,就大大地减小了系统开销,而且没必要为每一个链接都建立一个线程,不用去维护多个线程,而且避免了多线程之间的上下文切换致使的开销。
从图中能够看出,当有读或写等任何注册的事件发生时,能够从Selector中得到相应的SelectionKey,同时从 SelectionKey中能够找到发生的事件和该事件所发生的具体的SelectableChannel,以得到客户端发送过来的数据。
使用NIO中非阻塞I/O编写服务器处理程序,大致上能够分为下面三个步骤:
1. 打开ServerSocketChannel,用于监听客户端链接 2. 绑定监听端口,设置链接为非阻塞模式 3. 建立Reactor线程,建立多路复用器并启动线程 4. 将SeverSocketChannel注册Reactor线程的多路复用器Selector上,监听ACCEPT事件 5. 多路复用器在线程run方法的无限循环体内轮询准备就绪的Key 6. 多路复用器监听到有新的客户端接入,处理新的接入请求,完成TCP三次握手,创建物理链路 7. 设置客户端链路为非阻塞模式 8. 将新接入的客户端链接到Reactor线程的多路复用器上,监听读操做,用来读取客户端发送的网络消息 9. 异步读取客户端请求消息到缓冲区 10. 对Buffer进行编辑码,将解码成功的消息封装成Task,投递到业务线程池,进行业务逻辑编排 11. 将POJO对象编码为Buffer,调用channel的异步write接口,将消息异步发送给客户端
1. 打开SocketChannel,绑定本地地址和端口 2. 设置SocketChannel为非阻塞模式,设置TCP参数 3. 异步链接服务端 4. 判断是否链接成功,若是链接成功,则直接注册读状态位到多路复用器中,若是没有链接成功返回false 5. 向Reactor线程的多路复用器注册OP_CONNECT状态位 6. 建立Reactor线程,建立多路复用器而且启动线程 7. 多路复用器在线程run方法的无限循环体内轮询准备就绪的Key 8. 接收connect事件进行处理 9. 判断链接结果,若是链接成功,注册读事件到多路复用器 10. 注册读事件到多路复用器 11. 异步读客户端请求消息到缓冲区 12. 对Buffer进行编解码,将解码成功的消息封装成Task,投递到业务线程池,进行业务逻辑编排 13. 将POJO对象编码为Buffer,调用channel的异步write接口,将消息异步发送给客户端
在JAVA NIO中用户线程会主动的询问数据是否准备完成,不是真正的异步
Java AIO即Java NIO2.0,是在JDK1.7中引入的新概念,并提供了异步文件通道和异步套接字通道的实现。 NIO2.0的异步套接字通道是真正的异步非阻塞IO,它对应UNIX网络编程中的事件驱动IO,它不须要经过多路复用器(Selector)对注册的通道进行轮询操做便可实现异步读写,从而简化了NIO的编程模型。
BIO
同步阻塞IO,性能低,编程较容器,适用于链接数目比较小且固定的架构
NIO
同步非阻塞IO,性能高,编程较复杂,适用于链接数目多且链接比较短(轻操做)的架构
AIO
异步非阻塞IO,性能高,编程较复杂,使用于链接数目多且链接比较长(重操做)的架构
序列化 (Serialization)将对象的状态信息转换为能够存储或传输的形式的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区。之后,能够经过从存储区中读取或反序列化对象的状态,从新建立该对象。 序列化使其余代码能够查看或修改那些不序列化便没法访问的对象实例数据。
什么状况下须要序列化:
Java序列化是指把Java对象转换为字节序列的过程;而Java反序列化是指把字节序列恢复为Java对象的过程。
实现Serializable接口的Java类表示能够被Java默认序列化或者其余第三方序列化工具序列化,但有些第三方序列化工具序列化类时不须要该标识。
若是没有设置这个值,你在序列化一个对象以后,改动了该类的字段或者方法名之类的,那若是你再反序列化想取出以前的那个对象时就可能会抛出异常,由于你改动了类中间的信息,serialVersionUID是根据类名、接口名、成员方法及属性等来生成一个64位的哈希字段,当修改后的类去反序列化的时候发现该类的serialVersionUID值和以前保存在问价中的serialVersionUID值不一致,因此就会抛出异常。而显示的设置serialVersionUID值就能够保证版本的兼容性,若是你在类中写上了这个值,就算类变更了,它反序列化的时候也能和文件中的原值匹配上。而新增的值则会设置成null,删除的值则不会显示。
序列化只能保存对象的非静态成员交量,不能保存任何的成员方法和静态的成员变量,并且序列化保存的只是变量的值,对于变量的任何修饰符都不能保存。
对于某些类型的对象,其状态是瞬时的,这样的对象是没法保存其状态的。例如一个Thread对象或一个FileInputStream对象 ,对于这些字段,咱们必须用transient关键字标明,不然编译器将报措。
当一个对象的实例变量引用其余对象,序列化该对象时也把引用对象进行序列化。
Netty 序列化
Netty经过ObjectEncoder和ObjectDecoder对对象进行序列化编解码以便在网络中传输数据
Dubbo 序列化
Dubbo序列化是阿里在Dubbo框架中用于对象序列化的技术
Hessian 序列化
Hessian是一种跨语言的高效二进制序列化方式