高性能网络服务器编程:为什么linux下epoll是最好,Netty要比NIO.2好?

news/2024/7/9 15:57:43 标签: epoll, netty, java

  基本的IO编程过程(包括网络IO和文件IO)是,打开文件描述符(windows是handler,java是stream或channel),多路捕获(Multiplexe,即select和poll和epoll)IO可读写的状态,而后可以读写的文件描述符进行IO读写,由于IO设备速度和CPU内存比速度会慢,为了更好的利用CPU和内存,会开多线程,每个线程读写一个文件描述符。

  但C10K问题,让我们意识到在超大数量的网络连接下,机器设备和网络速度不再是瓶颈,瓶颈在于操作系统和IO应用程序的沟通协作的方式

      举个例子,一万个socket连接过来,传统的IO编程模型要开万个线程来应对,还要注意,socket会关闭打开,一万个线程要不断的关闭线程重建线程,资源都浪费在这上面了,我们算建立一个线程耗1M内存,1万个线程机器至少要10G内存,这在IA-32的机器架构下基本是不可能的(要开PAE),现在x64架构才有可能舒服点,要知道,这仅仅是粗略算的内存消耗。别的资源呢?

     所以,高性能的网络编程(即IO编程),第一,需要松绑IO连接和应用程序线程的对应关系,这就是非阻塞(nonblocking)、异步(asynchronous)的要求的由来(构造一个线程池,epoll监控到有数的fd,把fd传入线程池,由这些worker thread来读写io)。第二,需要高性能的OS对IO设备可读写(数据来了)的通知方式:从level-triggered notification到edge-triggered notification,关于这个通知方式,我们稍后谈。

    需要注意异步,不等于AIO(asynchronous IO),linux的AIO和java的AIO都是实现异步的一种方式,都是,这个我们也接下来会谈到。

    针对前面说的这两点,我们看看select和poll的问题

  imageimage

 

    这两个函数都在每次调用的时候要求我们把需要监控(看看有没有数据)的文件描述符,通过数组传递进入内核,内核每次都要扫描这些文件描述符,去理解它们,建立一个文件描述符和IO对应的数组(实际内核工作会有好点的实现方式,但可以这么理解先),以便IO来的时候,通知这些文件描述符,进而通知到进程里等待的这些select、poll。当有一万个文件描述符要监控的时候呢(一万个网络连接)?这个工作效率是很低的,资源要求却很高。

  我们看epoll

  image

  image

  image

    epoll很巧妙,分为三个函数,第一个函数创建一个session类似的东西,第二函数告诉内核维持这个session,并把属于session内的fd传给内核,第三个函数epoll_wait是真正的监控多个文件描述符函数,只需要告诉内核,我在等待哪个session,而session内的fd,内核早就分析过了,不再在每次epoll调用的时候分析,这就节省了内核大部分工作。这样每次调用epoll,内核不再重新扫描fd数组,因为我们维持了session。

    说道这里,只有一个字,开源,赞,众人拾柴火焰高,赞。

    epoll的效率还不仅仅体现在这里,在内核通知方式上,也改进了,我们先看select和poll的通知方式,也就是level-triggered notification,内核在被DMA中断,捕获到IO设备来数据后,本来只需要查找这个数据属于哪个文件描述符,进而通知线程里等待的函数即可,但是,select和poll要求内核在通知阶段还要继续再扫描一次刚才所建立的内核fd和io对应的那个数组,因为应用程序可能没有真正去读上次通知有数据后的那些fd,应用程序上次没读,内核在这次select和poll调用的时候就得继续通知,这个os和应用程序的沟通方式效率是低下的。只是方便编程而已(可以不去读那个网络io,方正下次会继续通知)。

    于是epoll设计了另外一种通知方式:edge-triggered notification,在这个模式下,io设备来了数据,就只通知这些io设备对应的fd,上次通知过的fd不再通知,内核不再扫描一大堆fd了。

    基于以上分析,我们可以看到epoll是专门针对大网络并发连接下的os和应用沟通协作上的一个设计,在linux下编网络服务器,必然要采用这个,nginx、php的国产异步框架swool、varnish,都是采用这个。

    注意还要打开epoll的edge-triggered notification。而java的NIO和NIO.2都只是用了epoll,没有打开edge-triggered notification,所以不如JBoss的Netty。

    接下来我们谈谈AIO的问题,AIO希望的是,你select,poll,epoll都需要用一个函数去监控一大堆fd,那么我AIO不需要了,你把fd告诉内核,你应用程序无需等待,内核会通过信号等软中断告诉应用程序,数据来了,你直接读了,所以,用了AIO可以废弃select,poll,epoll

    但linux的AIO的实现方式是内核和应用共享一片内存区域,应用通过检测这个内存区域(避免调用nonblocking的read、write函数来测试是否来数据,因为即便调用nonblocking的read和write由于进程要切换用户态和内核态,仍旧效率不高)来得知fd是否有数据,可是检测内存区域毕竟不是实时的,你需要在线程里构造一个监控内存的循环,设置sleep,总的效率不如epoll这样的实时通知。所以,AIO是渣,适合低并发的IO操作。所以java7引入的NIO.2引入的AIO对高并发的网络IO设计程序来说,也是,只有Netty的epoll+edge-triggered notification最牛,能在linux让应用和OS取得最高效率的沟通。

 

  注:非阻塞IO和异步IO基本是一个意思,只是描述同一个东西的不同方面。

  http://en.wikipedia.org/wiki/Asynchronous_I/O

  In computer science, asynchronous I/O, or non-blocking I/O is a form of input/output processing that permits other processing to continue before thetransmission has finished.

转载于:https://www.cnblogs.com/tianhangzhang/p/5374034.html


http://www.niftyadmin.cn/n/1379394.html

相关文章

oracle触发器输出信息,插入后oracle触发器打印

我刚开始学习触发器。我想在插入测试后给用户一个通知插入成功。插入后oracle触发器打印这是我的代码。create table test (id number, name varchar2(30));create trigger tr_testafter insert on testfor each rowbegindbms_output.put_line(insert successfully);end;/inser…

JVM学习笔记——初识JVM

简述 "Write Once,Run Anywhere"(一次编译,到处运行)是sun宣传Java语言所提出的口号。Java语言跨平台的特性与Java虚拟机的存在密不可分。Java源代码通过编译生成.class文件字节码后再被JVM解释转化为目标机器代码,到处运行的关键与…

Test_Java_集合练习(约瑟夫环/幸运数字)

需求:使用Java程序求解约瑟夫环的问题 约瑟夫环(约瑟夫问题)是一个数学的应用问题:已知n个人(以编号1,2,3…n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m…

2016年,移动开发领域有哪些最佳实践值得参考?

2007年1月9日,苹果推出第一代iPhone。时光飞逝,9年已经过去。随着智能手机的不断发展,移动互联网迅猛发展,日益深入人们的生活,购物、打车、订餐、导航、理财,都可以通过手机轻松处理,我们已经很…

php mysql 安全防范,PHP Mysql 注入的简单实现例子与简单防范

在我看来,引发 SQL 注入攻击的主要原因,是因为以下两点原因:1. php 配置文件 php.ini 中的 magic_quotes_gpc 选项没有打开,被置为 off2. 开发者没有对数据类型进行检查和转义不过事实上,第二点最为重要。我认为, 对用…

灰度图像的sobel边缘检测算法

之前上一篇文章写了如何将图片进行灰度化处理,这篇文章参考CB的文章简单的介绍一下如何进行sobel边缘化处理。 边缘 : 周围像素灰度急剧变化的那些像素的集合,它是图像最基本的特征 公式 : 这里Gx和Gy分别代表横向及纵向边缘检测…

嵌入式 Linux下curl库API简单介绍

1:CURLcode curl_global_init(long flags); 这个函数全局需要调用一次(多次调用也可以,不过没有必要), 所以这也是把Curlplus设计成单体类的原因,curl_global_init函数在其他libcurl函数调用前至少调用一次…

表格加颜色php代码,PHP联系表格字体颜色粘到黑色

无论我尝试奇怪地尝试我的表单,并且感谢您使用嵌入字体着色的一个php文件和一个用外部样式表拒绝从黑色更改字体颜色的页面。PHP联系表格字体颜色粘到黑色其他一切工作purfectly但改变接触形式字体颜色contactform.phprequire_once("./include/fgcontactform.p…