JAVA NIO 随笔
网络基本认知:现在网络的通信基本都是TCP的,都是点对点的数据传输。基于IP数据包的传输,在传输的过程中,操作系统会给每个socket分配自己的缓冲区,所以每个socket都是会占用系统资源的,如果网络的连接非常大的话,也会占用比较大的内存空间的。每个缓存区会有标识标记当前的接收或者发送的数据情况,TCP/IP根据接收方的rwnd和网络返回的延迟情况来决定发送数据的快慢。数据包依赖于底层一层一层的包装。
JAVA的NIO:说起JAVA的NIO就必须要说多路复用,我的理解多路复用是相对于阻塞性IO而言的,阻塞行IO每个连接都依赖于一个线程,而多路复用可以用一个或者几个线程来管理客户端的连接,在NIO中都用react的模型来管理连接。NIO的实现由包括有select模型,poll模型,epoll模型等方式,对于JVM而言把这部分都进行了统一的封装,select和poll的模型都差不多,都需要内核遍历整个fd数组来查找是否有网络事件发生,但是不同的是poll模式不需要每次select时都传入需要遍历的整个fd到内核空间,epoll的模式和poll只需要初始化时一次拷贝,下次如果有网络的变化内核会通知哪些fd有变化,这样就节约了数据的拷贝,当有网络事件发生时,底层驱动默认会把变化的fd按照红黑树模式,挂到注册监听的fd上,内核遍历只需要取变化的fd列表就可以了,所以支持比较大的网络连接数量,epoll还分为水平触发和边缘触发,水平触发的话就是有fd的变化会一直通应用,而边缘触发的话就通知一次,如果应用没有处理这次下次就没有事件了,所以相对处理起来要麻烦一些。对于我了解的redis用的是水平触发,因为redis一般不会创建很多的连接,它一般是对内部系统用的,有个几千的连接足以,而nginx就是边缘触发,因为nginx要对外接收用户的连接,所以它用的是边缘触发,能处理大的连接,一台机器有可能有10w的连接的数量。