一、BIO模型:同步阻塞IO处理 在程序的开发之中Java里面最小的处理单元就是线程,也就是说每一个线程可以进行IO的处理,在处理之中,该线程无法进行任何的其他操作。 多线程是不可能无限制进行创造的,所以需要去考虑堆线程进行有效的个数控制。如果产生的线程过多,那么直接的问题在于,处理性能降低 ,响应的速度变慢。 需要去区分操作系统的内核线程,以及用户线程的区别,所以最好与内核线程有直接联系,需要使用到固定线程池。 【BIO】现在烧水,意味着你现在需要一直盯着水壶去看,一直看它已经烧为止,在这之中你什么都干不了。
二、NIO模型:同步非阻塞IO处理 在传统的Java环境里面,最初的程序需要依赖于JVM虚拟机技术。最早的时候由于虚拟机的性能很差,所以很少有人去关注通讯的速度问题,大部分的问题都出现在了CPU处理上。 但是随着硬件的性能提升,实际上CPU的处理速度加强了。所以从JDK 1.4开始就引入NIO的开发包,可以带来底层数据的传输性能。 在NIO之中采用了一个Reactor事件模型,注册的汇集点Selector 【NIO】烧水,不会一直傻站着看,你采用轮询的方式来观察水是否烧开。
三、AIO模型:异步非阻塞IO、是在JDK 1.7的时候才推出的模型。 是利用了本地操作系统的IO操作处理模式,当有IO操作产生之后,会启动有一个单独的线程,它将所有的IO操作全部交由系统完成,只需要知道返回结果即可。 主要的模式是基于操作回调的方式来完成处理的,如果以烧水为例:在烧水的过程之中你不需要去关注这个水的状态,在烧水完成后才进行通知。
Netty 编程
那么 Netty 到底是何方神圣? 用一句简单的话来说就是:Netty 封装了 JDK 的 NIO,让你用得更爽,你不用再写一大堆复杂的代码了。 用官方正式的话来说就是:Netty 是一个异步事件驱动的网络应用框架,用于快速开发可维护的高性能服务器和客户端。 下面是我总结的使用 Netty 不使用 JDK 原生 NIO 的原因:
1、 使用 JDK 自带的 NIO 需要了解太多的概念,编程复杂,一不小心 bug 横飞;
2、 Netty 底层 IO 模型随意切换,而这一切只需要做微小的改动,改改参数,Netty可以直接从 NIO 模型变身为 IO 模型;
3、Netty 自带的拆包解包,异常检测等机制让你从 NIO 的繁重细节中脱离出来,让你只需要关心业务逻辑;
4、Netty 底层对线程,selector 做了很多细小的优化,精心设计的 reactor 线程模型做到非常高效的并发处理;
5、自带各种协议栈让你处理任何一种通用协议都几乎不用亲自动手;
6、 Netty 社区活跃,遇到问题容易解决;
7、Netty 已经历各大 RPC 框架(如Dubbo),消息中间件,分布式通信中间件线上的广泛验证,健壮性无比强大。
Netty可以实现HTTP处理机制,但是Tomcat本身也是基于NIO的实现。
如果在实现Netty的过程之中只是进行这些简单的NIO包装处理实际上是没有任何优势的。Netty的出现是为了解决传输问题,最为重要的情况就是粘包与拆包。 1、如果现在数据稍微有点大(又不是很大的时候),那么如果要进行多条数据的发送(缓冲区有大小限制); 2、粘包和拆包的问题解决方案有如下几种: A、设置消息的边界内容,例如:每一个消息使用"\n"结尾操作; B、使用特定消息头,在真实信息之前传入一个长度的信息。 C、使用定长信息;
3、Netty解决拆包与粘包问题的关键在于使用了分割器的模式来进行数据的拆分。
4、Netty默认分隔符是系统提供的分隔符常亮,需要考虑分隔符的定义问题。
5、序列化管理操作:Java原生实现(性能比较差)、JSON(Restful)、MessagePack、Marshalling、AVRO、....
netty本身直接支持有原生的 Java序列化操作,直接配置已有的程序类即可 MessagePack:类似于JSON,但是要比JSON传输的更加小巧同时速度也快。它定义一个自己的压缩算法,例如:boolean只有true和false,但是有了MP就可以通过0和1描述了; Marshalling:使用JBoss实现的序列化处理操作,是基于传统的Java序列化的形式的一种升级。 JSON:是一种标准做法,但是JSON需要清楚的问题是传输体积要大,但是传输的信息明确,本次使用FastJSON操作