ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

网卡的零拷贝理解

2019-02-24 17:49:41  阅读:284  来源: 互联网

标签:网卡 理解 内核 进程 拷贝 CPU Jack


转自:http://blog.csdn.net/freas_1990/article/details/9173713

Jack:最近听说了网络处理的“零拷贝”技术,觉得非常神奇,在网上查阅了很多资料。不过,并不是太明白——知其然,而不知其所以然。你能通俗地解释一下吗?

我:这是一个相对比较复杂的话题,说起来话就多了。本质上来说,其实就是80386的分页管理变异而已。

Jack:分页管理?这个跨度有点大,穿越了。

我:你觉得穿越,是因为你基础不过关。基础不过关,看技术就像看天书。如果你“本源技术”学得很好,那些看是玄妙的技巧,一眼就可以看破

Jack:为什么说“零拷贝”技术的本质是80386的分页管理变异的呢?

我:我们先说一说,零拷贝技术的本质是什么吧。当一个网络数据包通过网卡进入内核,然后再进入用户空间的时候,至少会经过2次data copy。不要小看两次data copy——互联网行业的网络服务器的CPU资源80%都消耗在这2次数据copy上去了,基本上别的事情都做不了。而事实上,这样的数据拷贝完全是没有必要的——这个数据包从网卡到内核再到用户空间,这个拷贝的过程仅仅起到了“传输”的作用,而数据包内容没有任何变化。零拷贝技术正是解决这两次拷贝。它能让两次拷贝完全消除,一次都不拷贝。

Jack:消除这两次拷贝的关键点在哪里呢?

我:这里需要分开讨论。第一次数据拷贝发生在“网卡到内核”。网卡到内核这种说法算是比较边缘性的。专业一点的说法是,外部设备到主存储器的数据传输。这个概念听着熟悉吧?

Jack:是的。这让我想起了外部设备到主存的三种数据传输方式——轮询、中断、DMA。其中轮询太龊了,基本上没有实用价值,而DMA适合在数据传输比较大的情况下使用,而且需要该外部设备支持。一般情况下,中断的方式用得比较多。

我:是的。中断是操作系统的神经中枢。不过,如果要实现零拷贝技术,这个网卡一定要采用DMA技术。

Jack:为什么呢?即便采用了DMA技术,数据任然要从网卡拷贝到主存,并不能算作“零拷贝”。

我:是的。使用DMA技术,仍然需要把数据从网卡拷贝到主存——但是,拷贝的过程中,CPU是完全不需要参与的。既然CPU不参与,就不会有任何CPU资源消耗,data copy带来的损耗就可以避免开了,所以这一层的data copy就被cut了

Jack:明白了。那内核到用户空间的数据拷贝是怎么消除的呢?

我:我先不回答这一个问题。我先问一个问题,数据如何从内核拷贝到用户空间呢?

Jack:从CPU层面来说,内核与用户空间处于不同的段(segment),段间数据拷贝,必须要有一个起中转作用的段寄存器参与才行。

我:是的。386CPU有fs寄存器充当这样的角色。

Jack:但是,如何才能实现段间数据共享呢?

我:从CPU的内存管理的角度来说,这是不可能实现的。Intel的设计就是段与段间分隔开来,每个段有自己的存储空间、属性等。

Jack:那从CPU的内存管理的角度来说,“零拷贝”岂不是完全不能实现?

我:是的。不仅不能实现,“零拷贝”的思想与操作系统内核的设计思想、CPU的设计思想是完全背道而驰的,属于妖孽那一类。

Jack:不要卖关子了。直接说吧,Linux内核是如何做到“零拷贝”的呢?

我:消除从Linux内核到用户空间的数据拷贝的关键点在于80386的虚拟内存机制——这是CPU层面的技术,并不是操作系统层面的技术。从Linux内核的设计角度来讲,它天生就认为从网卡到内核到用户空间的2次数据拷贝是必须的,拷贝了两次才是完整的(尽管做了无用功、在网络流量比较大的情况下性能低下,但是站在Linux内核的角度,它就要这么做)。而“零拷贝”技术正是打破了操作系统的设计理念,妖孽了一把,从CPU层面打破Linux内核与用户空间的阻隔,使其内存共享

Jack:CPU的这种功能具体是什么呢?

我:就是80386的虚拟内存管理与分页机制的组合。虚拟内存可以通过页目录、页表映射到物理内存地址,也可以直接映射到物理磁盘上(的文件)去。关键点就在这里了。既然虚拟内存可以映射到文件上去,而文件又是多个进程共享的(不用区分内核与用户进程),内核的某一块内存区域映射到一个文件,而用户进程(server进程)又关联到这一个文件,那么这个用户进程(server进程)就可以直接操作Linux内核的某块内存区域了。如果内核中的这块内存区域再被设定为网卡DMA映射的内存区,“零拷贝”也就实现了。

Jack:Linux为这种操作系统设计了API吗?

我:有的。mmap()就是做这个事儿的。而实际上,Unix进程间通信的“共享内存”方式,其本质原理,也是这个。

Jack:明白了,作为一个操作系统内核,其设计理念势必把内核与用户进程区分开来,而各个用户进程的内存区域也必然是互相隔离的。这样,才是真正的进程的概念。进程间需要通信,最“正当”的方式是在内核区域构建相应的数据结构,某进程需要通信就通过系统调用进入内核区域,修改代码,然后通知到需要通信的进程。被通知的进程通过系统调用进入内核空间,通信完成。如果进程间需要进行数据传输,只能先通过A进程传输到内核,然后再从内核传输到B进程,期间必然发生至少2次数据拷贝

我:是的。

Jack:但是。“共享内存”mmap本质上借用了80386的虚拟内存管理模式,打破了操作系统的设计思想。而mmap其实是共享内存的一般使用模式

我:是的。能说出“而mmap其实是共享内存的一般使用模式”这样的话,说明你把握到关键点了。

标签:网卡,理解,内核,进程,拷贝,CPU,Jack
来源: https://blog.csdn.net/lengye7/article/details/87905493

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有