在做大数据的时候刚开始把所有数据都存入hbase中,结果导致hbase每天都有很多数据 而且key设置的是ip虽然散列了,但是随着数据量的增加,用spark查询是越来越慢,因为新学习当时没有了解到Hbase的具体存储模式。在知道之后,就考虑写文件的方式。这个只是暂时想出来的方案。后来改成写Hadoop文件。
我们经常用的IO 大部分都是BIO,但是在我们提高性能的方式上都是AIO,NIO.他们有什么区别呢?我们今天就来看看。
明白两个概念
- 阻塞与非阻塞: 阻塞就是当满足条件后,程序会等待该方式或者方法执行完毕后才返回,才能继续进行。非阻塞就是不管io操作是否完成都会继续执行,而不需要等待、这样能快速的完成任务。
- 同步与非同步:同步任务,是需要等待任务的完成。才能获得该操作,异步则是操作后继续执行,不必等待结果的返回。通常使用事件或者回调机制来实现任务的之间的关系。
BIO
在jdk1.4版本之前我们大部分都是采用的BIO,这是一种同步阻塞的的io方式,比如我们经常用到的ServerSocket,就是处于等待的阻塞的。只要有请求过来才执行。该方式造成的就是性能上损耗很大。
- 比如我在写文件的时候,如果有很多数据要写比如需要每秒写入100M/S,可能该方式就不适合了,因为阻塞的会一直等待上次的执行完毕之后才能继续执行,不能充分的发挥磁盘的IO性能。所以平常读写文件对于性能没有太大的要求,可以用该方式去使用
- 对于高性能的读写该方式就不行了。读写会造成很多的等待。就算开多线程,同样的事情还是会出现。
NIO
NIO在操作上主要是用来解决我们上面说的并发问题,如果有多个访问过来在BIO只能是等待的上一个链接请求结束后才能操作。
在NIO中主要有以下几个内容需要注意的 :
- Buffer ,在NIO 中的高效容器,原始数据类型都有相应的Buffer实现。缓冲区,其中capacity表示缓冲区的大小,在实现的时候指定,读写限制(limit)表示缓冲区在进行读写操作时的最大允许位置;读写位置(position)表示当前进行读写操作时的位置;缓冲区的很多操作(clear、flip、rewind)都是操作limit和position的值来实现重复读写。
- Channel表示为一个已经建立好的支持I/O操作的实体的链接,在此链接上进行数据的读写操作,使用缓冲区实现读写
- Selector(多路复用器):通过一个选择器来同时对多个套接字通道进行监听,当其中套接字通道有可用的事件的时候,通道改成可用状态,选择器就可以实现可用的状态。主要是阻塞在select操作中,前面说的通道可用也是Channel。这样实现的单线程对多个Channel进行高效的管理。
- 具体实现可以去网上看代码。这里不写代码了
- 但是NIO还是同步阻塞的。没有实现异步的操作
- 流程是 客户端访问 ——>Channel —>Selector ——> keys ——状态改变——>server
AIO
其实AIO是在NIO的基础上更近了一步,解决了NIO的同步情况。在这种情况下对IO的操作都是异步的。不需要进行等待。就能提高性能。通过调用回调函数来实现对异步操作结果的获取。
总结
Java对BIO、NIO、AIO的支持:
JavaBIO : 同步并阻塞,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,当然可以通过线程池机制改善。
Java NIO : 同步非阻塞,服务器实现模式为一个请求一个线程,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。
Java AIO(NIO.2) : 异步非阻塞,服务器实现模式为一个有效请求一个线程,客户端的I/O请求都是由OS先完成了再通知服务器应用去启动线程进行处理,
BIO、NIO、AIO适用场景分析:
BIO方式适用于连接数目比较小且固定的架构,这种方式对服务器资源要求比较高,并发局限于应用中,JDK1.4以前的唯一选择,但程序直观简单易理解。
NIO方式适用于连接数目多且连接比较短(轻操作)的架构,比如聊天服务器,并发局限于应用中,编程比较复杂,JDK1.4开始支持。
AIO方式使用于连接数目多且连接比较长(重操作)的架构,比如相册服务器,充分调用OS参与并发操作,编程比较复杂,JDK7开始支持。