文档章节

Netty整理

算法之名
 算法之名
发布于 09/12 00:21
字数 3303
阅读 64
收藏 0

什么是阻塞/非阻塞,什么是同/异步

简介:使用最通俗概念讲解 同步异步、堵塞和非堵塞
洗衣机洗衣服

洗衣机洗衣服(无论阻塞式IO还是非阻塞式IO,都是同步IO模型
同步阻塞:你把衣服丢到洗衣机洗,然后看着洗衣机洗完,洗好后再去晾衣服(你就干等,啥都不做,阻塞在那边)

同步非阻塞:你把衣服丢到洗衣机洗,然后会客厅做其他事情,定时去阳台看洗衣机是不是洗完了,洗好后再去晾衣服
(等待期间你可以做其他事情,玩游戏,看视频等等)。但即便如此,依然要时不时地去看一下洗衣机是不是把衣服洗完了,然后才能去晾衣服。

        
异步阻塞: 你把衣服丢到洗衣机洗,然后看着洗衣机洗完,洗好后再去晾衣服(几乎没这个情况,几乎没这个说法,可以忽略,异步不可能阻塞
        
异步非阻塞:你把衣服丢到洗衣机洗,然后会客厅做其他事情,洗衣机洗好后会自动去晾衣服,晾完成后放个音乐告诉你洗好衣服并晾好了,这里你不需要晾衣服。

同步有先后顺序,无论是否阻塞。异步没有先后顺序,各自完成各自的事情。

linux网络编程中的IO模型

网络IO,用户程序(进程,缓存)和内核的交互为基础

IO操作分两步:1、发起IO请求等待数据准备,2、实际IO操作

同步须要主动读写数据,在读写数据的过程中还是会阻塞(发起请求,等待内核准备数据,内核准备完毕,从内核中拿取数据到应用进程)

异步仅仅须要I/O操作完毕的通知。并不主动读写数据,由操作系统内核完毕数据的读写(发起请求,内核准备数据,内核准备完毕,内核把数据放进应用进程,通知应用程序已经放好了)

五种IO的模型:阻塞IO、非阻塞IO、多路复用IO、信号驱动IO和异步IO
前四种都是同步IO,在内核数据copy到用户空间时都是阻塞的

1)阻塞式I/O;全程阻塞,主线程不把数据拿到进程空间,不干别的

2)非阻塞式I/O;主线程在内核数据准备阶段可以干别的,但会时不时去看看数据有没有准备好,该阶段是非阻塞的;当内核把数据准备好后,会把数据复制到进程空间,该阶段是阻塞的。

3)I/O复用(select,poll,epoll...);
                I/O多路复用是阻塞在select,epoll这样的系统调用,没有阻塞在真正的I/O系统调用如recvfrom
                进程受阻于select,等待可能多个套接口中的任一个变为可读(这个指的是第一阶段,数据准备阶段)

                IO多路复用使用两个系统调用(select和recvfrom)
                blocking IO只调用了一个系统调用(recvfrom)
                select/epoll 核心是可以同时处理多个connection,而不是更快,所以连接数不高的话,性能不一定比多线程+阻塞IO好
                多路复用模型中,每一个socket,设置为non-blocking,
                阻塞是被select这个函数block,而不是被socket阻塞的

这里跟阻塞和非阻塞IO到区别是:阻塞和非阻塞IO只会发起一次系统请求让内核准备数据,而IO多路复用会发起很多次系统请求让系统同时准备很多份数据,同时监听哪一个请求到数据,内核已经准备好了,内核准备好后,select指令会发生阻塞。但无论哪种IO到了将数据从内核复制到进程的过程中,都是阻塞的,干不了别打事情,即便在多路复用IO中内核又准备好了一份数据,也无法同时复制数据。

 

4)信号驱动式I/O(SIGIO);主线程发送一个请求,直接返回。内核准备好数据后,会给主线程一个信号,主线程开始复制数据到进程空间。

5)异步I/O(POSIX的aio_系列函数) Future-Listener机制;主线程发送一个请求,内核从准备数据到复制数据到进程空间全部自己处理,主线程不参与,内核处理完通知主线程已经完成。

IO操作分为两步
            1)发起IO请求,等待数据准备(Waiting for the data to be ready)
            2)实际的IO操作,将数据从内核拷贝到进程中(Copying the data from the kernel to the process)


            前四种IO模型都是同步IO操作,区别在于第一阶段,而他们的第二阶段是一样的:在数据从内核复制到应用缓冲区期间(用户空间),进程阻塞于recvfrom调用或者select()函数。 相反,异步I/O模型在这两个阶段都要处理。


            阻塞IO和非阻塞IO的区别在于第一步,发起IO请求是否会被阻塞,如果阻塞直到完成那么就是传统的阻塞IO,如果不阻塞,那么就是非阻塞IO。
            同步IO和异步IO的区别就在于第二个步骤是否阻塞,如果实际的IO读写阻塞请求进程,那么就是同步IO,因此阻塞IO、非阻塞IO、IO复用、信号驱动IO都是同步IO,如果不阻塞,而是操作系统帮你做完IO操作再将结果返回给你,那么就是异步IO。

阻塞非阻塞说的是线程的状态
同步和异步说的是消息的通知机制

同步需要主动读写数据,异步是不需要主动读写数据
同步IO和异步IO是针对用户应用程序和内核的交互

IO多路复用技术select、poll、epoll

什么是IO多路复用:
            I/O多路复用,I/O是指网络I/O, 多路指多个TCP连接(即socket或者channel),复用指复用一个或几个线程。
            简单来说:就是使用一个或者几个线程处理多个TCP连接
            最大优势是减少系统开销小,不必创建过多的进程/线程,也不必维护这些进程/线程.(如果线程过多,则线程的开销较大,线程切换消耗资源,浪费时间)

select:同步机制
            基本原理:
                监视文件3类描述符: writefds、readfds、和exceptfds(Linux会将所有的资源视为文件系统fd)
                调用后select函数会阻塞住,等有数据 可读、可写、出异常 或者 超时 就会返回
                select函数正常返回后,通过遍历fdset整个数组才能发现哪些句柄发生了事件,来找到就绪的描述符fd,然后进行对应的IO操作
                几乎在所有的平台上支持,跨平台支持性好

            缺点:
                1)select采用轮询的方式扫描文件描述符,全部扫描,随着文件描述符FD数量增多而性能下降
                2)每次调用 select(),需要把 fd 集合从用户态拷贝到内核态,并进行遍历(消息传递都是从内核到用户空间)
                2)最大的缺陷就是单个进程打开的FD有限制,默认是1024   (可修改宏定义,但是效率仍然慢)  
                   类似于Java的 static final  int MAX_FD = 1024

poll:同步机制
            基本流程:
                select() 和 poll() 系统调用的大体一样,处理多个描述符也是使用轮询的方式,根据描述符的状态进行处理
                一样需要把 fd 集合从用户态拷贝到内核态,并进行遍历。

                最大区别是: poll没有最大文件描述符限制(使用链表的方式存储fd)

epoll:异步机制,nginx底层实现机制
            基本原理:
                在2.6内核中提出的,对比select和poll,epoll更加灵活,没有描述符限制,用户态拷贝到内核态只需要一次
                使用事件通知,通过epoll_ctl注册fd,一旦该fd就绪,内核就会采用callback的回调机制来激活对应的fd

            优点:
                1)没fd这个限制,所支持的FD上限是操作系统的最大文件句柄数,1G内存大概支持10万个句柄
                2)效率提高,使用回调通知而不是轮询的方式,不会随着FD数目的增加效率下降

                3)通过callback机制通知,内核和用户空间mmap同一块内存实现

            Linux内核核心函数
                1)epoll_create()  在Linux内核里面申请一个文件系统 B+树,返回epoll对象,也是一个fd
                2)epoll_ctl()   操作epoll对象,在这个对象里面修改添加删除对应的链接fd, 绑定一个callback函数
                3)epoll_wait()  判断并完成对应的IO操作

            缺点:
                编程模型比select/poll 复杂


            例子:100万个连接,里面有1万个连接是活跃,在 select、poll、epoll分别是怎样的表现
                
                select:不修改宏定义,则需要 1000个进程(每个进程是分别去轮询遍历)才可以支持 100万连接,单机无法承受
                poll:100万个连接,遍历都响应不过来了,还有空间的拷贝消耗大量的资源
                epoll:使用callback机制,不需要遍历,不需要拷贝,直接完成,单机可以直接支持,性能应该在用户的开发代码上。

但如果100万个连接有大部分是活跃的,比如90万个活跃的,poll和epoll的区别不大,单机都无法承受。

在讲解Netty之前,需要先说明一下什么是Reactor设计模式

设计模式——Reactor模式(反应器设计模式),是一种基于事件驱动的设计模式,在事件驱动的应用中,将 一个或多个客户的服务请求分离(demultiplex)和调度(dispatch)给应用程序。在事件驱动的应用中,同步 地、有序地处理同时接收的多个服务请求 一般出现在高并发系统中,比如NettyRedis

优点 1)响应快,不会因为单个同步而阻塞,虽然Reactor本身依然是同步的; 2)编程相对简单,最大程度 的避免复杂的多线程及同步问题,并且避免了多线程/进程的切换开销; 3)可扩展性,可以方便的通过增加 Reactor实例个数来充分利用CPU资源;

缺点 1)相比传统的简单模型,Reactor增加了一定的复杂性,因而有一定的门槛,并且不易于调试。 2) Reactor模式需要系统底层的的支持,比如Java中的Selector支持,操作系统的select系统调用支持

通俗理解:KTV例子 前台接待,服务人员带领去开机器 Reactor模式基于事件驱动,适合处理海量的I/O事件,属于同步非阻塞IO(NIO)

Reactor单线程模型(比较少用)

内容: 1)作为NIO服务端,接收客户端的TCP连接;作为NIO客户端,向服务端发起TCP连接; 2) 服务端读请求数据并响应;客户端写请求并读取响应
使用场景
: 对应小业务则适合,编码简单;对于高负载、大并发的应用场景不适合,一个NIO线程处理 太多请求,则负载过高,并且可能响应变慢,导致大量请求超时,而且万一线程挂了,则不可用了 ,NIO的说明可以参考传统IO与NIO比较

Reactor多线程模型

内容:一个Acceptor线程;一组NIO线程,一般是实用自带的线程池,包含一个任务队列和多个可用的线程 去处理接入连接和处理IO
使用场景:满足大多数场景 ,但是当Acceptor需要做复杂操作的时候,比如认证等耗时操作的时候,在高并发情况下则也会有性能问题,大量的请求被堆积到Acceptor,而无法分发到Worker线程池。

Reactor主从线程模型
内容:
1) Acceptor不在是一个线程,而是一组NIO线程;IO线程也是一组NIO线程,这样就是两个线程池去处理接入连接和处理IO

使用场景:满足目前的大部分场景,也是Netty推荐使用的线程模型

BossGroup
WorkGroup

© 著作权归作者所有

算法之名
粉丝 48
博文 177
码字总数 265624
作品 0
广州
私信 提问
Dubbo 升级扩展 --Dubbo-G

Dubbo-G 详细介绍 Dubbo是一个被国内很多互联网公司广泛使用的开源分布式服务框架,即使从国际视野来看应该也是一个非常全面的SOA基础框架。作为一个重要的技术研究课题,在联想电商我们根据...

技术专家
2017/05/26
8.4K
23
源码之下无秘密 ── 做最好的 Netty 源码分析教程

背景 在工作中, 虽然我经常使用到 Netty 库, 但是很多时候对 Netty 的一些概念还是处于知其然, 不知其所以然的状态, 因此就萌生了学习 Netty 源码的想法. 刚开始看源码的时候, 自然是比较痛苦...

永顺
2017/11/29
0
0
《深入探索Netty原理及源码分析》文集小结

写在2017年末尾,翻看文集的第一篇文章已经是三个月前的事了,也没想过这文集会写那么久,这么慢。。。 Netty文集中的文章主要都是我学习过程的笔记,写博客的主要目的是为了通过输出来倒逼输...

tomas家的小拨浪鼓
2017/12/30
0
0
为什么选择Netty作为基础通信组件?

以下内容根据网上资料和自己整理总结而成 一、什么是Netty? Netty是一个高性能 事件驱动、异步非堵塞的IO(NIO)Java开源框架,Jboss提供,用于建立TCP等底层的连接,基于Netty可以建立高性能...

ZhakyMing
2016/10/19
5.8K
24
Netty 初步使用

1、简介 Java1.4提供了NIO使开发者可以使用Java编写高性能的服务端程序,但使用原生的NIO API就像Linux C中网络编程一样,还是需要做IO处理、协议处理等低层次工作。所以,就像C服务端程序大...

鉴客
2011/01/11
3.9K
3

没有更多内容

加载失败,请刷新页面

加载更多

小知识:讲述Linux命令别名与资源文件的区别

别名 别名是命令的快捷方式。为那些需要经常执行,但需要很长时间输入的长命令创建快捷方式很有用。语法是: alias ppp='ping www.baidu.com' 它们并不总是用来缩短长命令。重要的是,你将它...

老孟的Linux私房菜
49分钟前
3
0
《JAVA核心知识》学习笔记(6. Spring 原理)-5

它是一个全面的、企业应用开发一站式的解决方案,贯穿表现层、业务层、持久层。但是 Spring 仍然可以和其他的框架无缝整合。 6.1.1. Spring 特点 6.1.1.1. 轻量级 6.1.1.2. 控制反转 6.1.1....

Shingfi
50分钟前
5
0
Excel导入数据库数据+Excel导入网页数据【实时追踪】

1.Excel导入数据库数据:数据选项卡------>导入数据 2.Excel导入网页数据【实时追踪】:

东方墨天
58分钟前
5
1
正则表达式如何匹配一个单词存在一次或零次并且不占捕获组位置

正则表达式如何匹配一个单词存在一次或零次并且不占捕获组位置 今天要用正则表达式实现匹配一个词出现一次或者不出现的情况,但是又不仅仅是这么简单的需求。先详细说下我这种情况吧,也许有...

Airship
今天
6
0
第八讲:asp.net C# web 读取文件

本讲主要讲解如何在asp.net页面上传文件。 首先,前台页面: 其次,后台页面: 结果: 1、前台效果: 2、后台结果:

刘日辉
今天
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部