端节点算法学.docx
- 文档编号:5483354
- 上传时间:2022-12-17
- 格式:DOCX
- 页数:15
- 大小:32.19KB
端节点算法学.docx
《端节点算法学.docx》由会员分享,可在线阅读,更多相关《端节点算法学.docx(15页珍藏版)》请在冰豆网上搜索。
端节点算法学
端节点算法学
端节点算法学是网络算法学在端节点尤其是服务器上的运用。
我们可以认为它是建立高速服务器的一组系统性技术。
随着网络功能虚拟化的提出,将来数据中心绝大部分的网络设备都会在通用服务器上实现,因此端节点算法学的重要性就更突出了。
消除不必要的拷贝
如果我们跟踪一个网络包从进入网卡到完成处理的整个过程,会发现网络包在终端中被拷贝了多次,具体场景稍后会看到。
为什么我们要把数据拷贝这个问题单独提出来讨论,是因为在计算机中进行拷贝会消耗两个非常宝贵的资源:
内存带宽和内存本身。
内存带宽反映了系统读写数据的能力。
由于现代计算机中访存是最大的瓶颈,如果web服务器处理一个报文涉及到k次拷贝,那么这个web服务器的吞吐量就可能降至1/k。
计算机中内存的容量是确定的,如果一个报文在内存中存k份,则会降低内存的有效容量。
能够进入内存或cache的数据量少了,访问数据的延迟就增大了。
所以说数据拷贝是影响计算机系统性能的重要因素。
本章关注如何消除不必要的拷贝(P1)。
一个拷贝如果不是由硬件要求的,该拷贝是不必要的。
比如,网络适配器将收到的数据拷贝到计算机内存,这是硬件要求的;然而,应用程序和操作系统之间的拷贝,主要是由操作系统的结构化产生的要求,除此之外没有什么特别的理由,这个拷贝是可以考虑消除的。
除了拷贝之外,这一章还将讨论其它需要对数据包载荷进行的操作(如计算检查和)。
5.1为什么要拷贝数据
我们首先看看在终端中数据的多次拷贝是怎么发生的。
考虑用户向web服务器请求一个静态文件,该文件在磁盘上;web服务器从磁盘中读出文件,发送到网络上。
我们关注在此过程中,数据在web服务器中的转移过程。
图5.2给出了涉及到的计算机系统的主要部件和拷贝过程。
涉及到的主要硬件为CPU、存储器、内存总线、I/O总线、硬盘和网卡,主要软件为web应用程序和内核程序。
这里涉及到两个主要的内核子系统,文件子系统和网络子系统。
文件子系统负责文件管理,网络子系统负责报文收发和协议处理。
为简单起见,图中只画出了一个CPU(许多服务器有多个处理器),并且只关注对静态内容的请求,即文件直接从磁盘中读出。
如果请求的是动态内容,web服务器后面还需要一个数据库,由服务器侧的一个CGI程序处理请求,从数据库中读数据,构造网页,再传给web服务器。
注意,图中将文件子系统和网络子系统的代码画在处理器中。
实际上,这些代码也存放在主存中,由处理器从主存中获取。
然而,位于处理器指令cache中的代码可以看成是在处理器中的。
一个简单的故事
直观上,这个故事是很简单的。
首先web应用程序通过一个系统调用(如read())将文件从磁盘读入到它的缓冲区(应用缓冲区);然后构造一个HTTP响应头,通过一个系统调用(如write())将响应头和缓冲区内容交给网络子系统(TCP/IP程序);网络子系统将数据划分成适当大小的块,加上各层协议头后交给网络适配器发送。
如果讲原理,一般就讲到这个程度。
一个真实的故事
实际上,这个故事的细节要复杂得多。
首先,文件一般先从硬盘读入到一个称为文件缓冲区的内核空间,我们称copy1。
这个做法是值得提倡的,这样随后对该文件的请求就可以直接从内存得到,而不需要每次都去读硬盘。
所有的web服务器都是这么做的,这样可以极大地减小响应时间。
其次,文件数据从文件缓冲区拷贝到web程序的应用缓冲区,我们称copy2。
接着,web程序对一个TCP套接字执行一个write()系统调用。
在write()调用中描述的应用缓冲区被拷贝到一个套接字缓冲区,这是内核中不同于文件缓冲区和应用缓冲区的另一个缓冲区,这称为copy3。
最后,每个数据块在加上了各层协议头之后,由驱动程序将数据包拷贝到位于网卡的缓冲区中,发送出去。
这称为copy4。
在传输到网络之前,TCP程序还要扫描一遍数据,计算TCP检查和。
以上过程涉及到4次拷贝和1次涉及全部包数据的检查和计算。
资源消耗情况
我们看一下资源消耗情况。
不同内存区域之间的拷贝(copy2和copy3)需要CPU的参与,每个字都要通过内存总线读一次和写一次,是消耗资源最多的。
计算TCP检查和需对每个字读一次,最后写一个简单结果,因此使用内存总线一次。
涉及外设的拷贝(copy1和copy4),如果由CPU来做拷贝(称程序输入输出),其代价与内存区域之间的拷贝一样,每个字都要通过内存总线读、写各一次。
如果由设备来做拷贝(DMA),则每个字只需通过内存总线读一次或写一次。
涉及外设的拷贝还会消耗I/O总线带宽(copy1和copy4)。
对服务器吞吐量的影响
在web服务器的例子中,即使使用了DMA,每一个字也要使用内存总线7次。
因此,web服务器的吞吐量不会超过T/7,其中T为内存速度和内存总线速度中的较小值。
其次,额外的拷贝消耗了内存。
在图中,一个文件被存储在文件缓冲区、应用缓冲区和套接字缓冲区。
通常web服务器希望使用尽可能多的文件缓冲区来避免频繁地访问硬盘。
一个文件存在3处,将减少文件缓冲区可用的容量,降低缓存命中率,从而极大地降低整个服务器的性能。
总而言之,多余的拷贝在两个重要的方面损害了服务器的性能:
1)由于使用了过多的总线和内存带宽,使得服务器的运行速度低于总线速度;2)由于使用了过多的内存,使得服务器不得不大量地去从磁盘读文件,而不是从主存中读文件。
需要注意的是,我们只描述了获取静态内容的情形,实际上相当一部分请求是关于动态内容的。
动态内容通常由一个专门的CGI程序生成,然后通过某种进程间通信机制交给web服务程序去发送,这里又会涉及到一次拷贝。
下面我们将讨论这些拷贝,哪些是可以避免的,怎么避免。
5.2利用适配器内存消除copy4
我们首先关注与网络相关的拷贝,即copy4。
为什么需要copy4?
一个简单的解释是,因为适配器内存位于适配器上,而内核存储空间位于存储子系统,不在同一个硬件上。
但是这个理由并不充分。
我们知道在一个内存映射的体系结构中,设备的寄存器被映射到一块内存区域,CPU通过读写这块内存区域与设备通信。
因此从理论上说,在一个内存映射的体系结构中,内存可以位于总线上的任何地方。
所以,尽管内核存储空间通常是位于存储子系统的,但没有理由认为部分内核空间就不能位于网络适配器中(网络适配器通常包含一定容量的存储器)。
利用网络适配器中已有的存储空间(P4)和内核存储空间放置的自由度(P13),我们可以将套接字缓冲区放在网络适配器中。
这样应用缓冲区的内容直接拷贝到网络适配器的内存中。
如何计算检查和?
但是这里有一个问题,网络子系统在收发TCP包时需要计算TCP检查和,如果数据在应用缓冲区和适配器之间直接传递,那么TCP检查和怎么计算呢?
这里的一个想法是运用P2c(共享开销)。
数据从应用缓冲区拷贝到适配器上的缓冲区,假如这个拷贝由CPU完成,那么可以让CPU捎带着同时计算检查和。
比如,使用一个寄存器,对已经传输的数据进行累加。
但是这个方法有个致命的问题,就是在接收数据包的时候,CPU边拷贝数据边计算检查和,当发现数据接收错误时,数据已经进入到应用缓冲区中,这是违背TCP语义的。
所以这个方法从未被实施。
后来这个方法被HP实验室的研究人员采纳,应用到他们的网络适配器(称为Afterburner)中。
数据传输不是由CPU完成,而是由网卡通过DMA完成。
由于CPU不参与DMA过程,因此检查和计算是由网卡完成的。
这种网卡称为TCP卸载引擎,它将TCP的数据传输下放到网卡上完成,以减轻CPU的负担。
需要注意的是,考虑到TCP连接管理的复杂性,TCP连接的管理(建立、关闭等)仍由主CPU完成,只是将建立好的TCP连接移交给网络适配器。
这种方法的问题是,网络适配器需要很大的内存空间和较强的处理器来支持大量的TCP连接,网卡成本很高。
5.3消除copy3
下面考虑消除copy3。
注意,我们现在是独立地考虑每一种数据拷贝的消除方法,这些措施能否组合使用需要仔细考虑。
应用和内核之间需要一次拷贝有两个原因。
(1)应用和内核使用不同的虚拟地址空间,需要通过拷贝传递数据。
但是这个理由不是充分的,因为完全可以通过内存映射,将套接字缓冲区映射给应用程序使用。
(2)socketAPI使用拷贝语义,应用程序在将缓冲区的内容写入套接字(交给网络子系统)后,它可以往缓冲区中写入新的数据。
但是TCP通常需要缓存数据以备重发,因此TCP不能与应用共用一块缓冲区,需要通过数据拷贝来解除应用和内核之间的耦合。
第2个理由使得拷贝看起来是必要的。
如果不能避免拷贝,那我们能够减小拷贝的开销吗?
特别是,如果应用并不需要立即写缓冲区,那么每次都执行拷贝是否必要?
写时拷贝
有些操作系统(如Mac)提供写时拷贝(copy-on-write)功能,在很多情况下可以避免实际的拷贝。
写时拷贝的实现
写时拷贝的基础是虚拟内存。
程序使用虚拟地址,虚拟地址通过一个页表映射到物理地址,页表用虚拟页号(虚拟地址的高20位)进行索引。
如果需要的页不在内存中,硬件产生一个缺页中断,操作系统将相应的页读入内存。
查找页表的开销可以通过使用TLB来消除。
我们用一个例子说明写时拷贝的实现。
假定进程P1的虚拟页X映射到物理页L,需要复制X的内容到进程P2的虚拟页Y。
……
写时拷贝(续):
不幸的是,许多操作系统(如UNIX和Windows)不提供写时拷贝。
但是理解了写时拷贝的原理之后,类似的效果是可以实现的。
因为现代计算机都使用虚拟内存,通过修改页表来避免物理拷贝是能够做到的,只是需要找到一种替代COW位的保护机制。
(COW保护机制采用硬件检测、触发操作系统异常来解决)
5.4优化页面重映射
写时拷贝的例子忽略了很多细节,以致于让人觉得页面重映射是很简单的一个操作,一个大的缓冲区通过一个写页表操作就可以从应用程序传递到内核(或反过来)。
比如在图5.5中,假定操作系统希望将进程P1的虚拟页10(VT10)拷贝到进程P2(如内核)的虚拟页8(VT8),其中VT10指出一个存放包数据的物理页。
过于简单的想法是只需要修改VT8的页表表项,使其指向存放包数据的物理页就可以了。
这种过于简单的看法是很误导人的。
页面重映射的开销
有好几个额外的开销被这种简单的描述给掩盖了。
(1)多级页表
大多数现代的计算机系统使用多级页表映射(至少有两级),实际映射时可能要求修改多级页表,由此可能涉及多次写。
为了实现跨平台运行,有些操作系统同时维护了机器无关页表和机器相关页表,则涉及的写操作更多。
当页表不在内存中时,还需要在内存中为页表分配一个物理页帧,将页表调入物理页帧中,为此还需要修改目录页。
(若使用32位的虚拟地址和4KB的页,一个进程可以有约一百万个页,所以页表也要分页。
32位机器一般使用两级页表:
每1024个页表项组成一个页表,这些页表的起始地址(即页表所在的物理页帧号)保存在一个目录页中;目录页有1024个表项,目录页的起始地址保存在一个全局寄存器中。
虚拟地址的前10位用于查找目录页,得到页表的地址;虚拟地址的中间10位用于查找页表,得到虚拟页的物理页帧号。
当包含虚拟页页号的页表已经在内存中时,页面映射只需修改对应的页表项;当页表不在内存中时,还需要在内存中为页表分配一个物理页帧,将页表调入物理页帧中,为此还需要修改目录页。
)
(2)要求锁
页表是共享资源,修改页表必须用锁保护,因此修改页表前后要有请求锁和释放锁的开销。
(3)刷新TLB
为节省地址转换时间,常用的页表映射缓存在TLB中。
当一个新的虚拟页的地址映射写入页表时,相关的TLB表项要清除或修正。
(TLB只包括最近用到的虚拟页号,指令和数据页分开记录。
TLB分别保存64个最常用的指令和数据的虚拟页号,每个TLB项包括一个虚拟页号和相应的物理页帧号。
)
(4)在目标域中分配虚拟内存
需要为目标进程分配一个新的虚拟页(malloc)。
新的虚拟页需要向系统去申请,为此,系统需要做一些计算在目标进程中找到一个空闲的页表表项。
(5)锁住相应的页
物理页可能会被换出到磁盘上。
为防止页被换出,页必须被锁住,这也需要开销。
所有这些开销在多处理器系统中会被放大(以上不少操作都需要加锁,如malloc)。
其结果是,尽管页表映射看起来非常好,即无论包大小如何,页面重映射只需常数时间,但这个常数因子实际上是一个很大的开销(Q4),有研究人员在90年代早期的实验中证实了这一点。
也就是说,如果只是简单地使用页表重映射来避免拷贝,结果可能不像预期的那么好。
那么怎么办?
数据拷贝开销很大,但页面重映射看起来开销也不小,搞不好比拷贝一个数据包的开销还要大。
那是不是说页面重映射就不能用了呢?
好在研究人员并没有放弃这个想法,他们发明了一个称为fbufs(fastbuffers的简称)的操作系统设施,可以消除前4种页面映射开销的全部或大部分。
Fbufs(fastbuffers)
Fbufs基于这样的观察:
如果一个应用正在通过内核向网络发送大量的数据包,那么一个缓冲区可能会被重用多次。
方法一:
提前分配好需要的包缓冲区,并计算好所有的页面映射信息(P2a),发送时重复使用这些包缓冲区。
问题是不好预先估计所要的缓冲区数量。
方法二:
当数据传输开始时才按需分配包缓冲区并计算页面映射(P2b),然后将其缓存起来(P11a)供后续数据包使用。
尽管前几个包的延迟较大,但后续的包就免除了页面映射的开销。
不管哪一种方法,都可以做到“映射一次,重复使用”。
当需要传输的数据量很大时,页面映射的开销被平摊,可以认为开销为零。
为应用分配一组固定的物理页
为避免用户空间和内核空间之间的拷贝,将一组物理页P1、P2、……同时映射到内核和应用的页表中,供它们使用。
考虑到端系统上可能同时运行多个应用。
为进行安全隔离,设计者将一个有序的安全域序列(数据包经过的一系列处理程序)定义为一条路径,并为每一条路径预留不同的一组物理页。
图5.6是一个路径的例子,以太网软件实现为一个内核级的驱动,TCP/IP栈实现为一个内核级的安全域,Web应用实现在应用层。
图中存在两条接收路径:
(以太网,TCP/IP,web),(以太网,OSI,FTP)。
将一定数量的物理页映射给接收路径(以太网、Tcp/IP和web应用),再将另一组物理页映射给另一条接收路径。
这样,每一个应用使用一组固定的物理页。
为使该设计发挥作用,当一个数据包到达时,最底层的驱动(甚至是网络适配器)必须立即判断该数据包要被映射到哪条路径,从而将数据包拷贝到分配给这条路径的物理页中,这个功能称为提前解复用(earlydemultiplexing)。
在图5.6中,这是通过检查数据包的所有头部来确定的,比如,具有以太帧头、IP头、TCP头和端口80的包属于路径1。
映射到同一个物理页的虚拟页号相同
想一想,在进程间传递缓冲区描述符会有什么问题?
理论上,各个进程映射到同一个物理页上的虚拟页号可能不同。
比如,第一个进程的虚拟页10可能和第二个进程的虚拟页8映射到同一个物理页上。
这是很麻烦的,因为第二个进程读入VT10的描述符后,它必须要知道它对应了自己的虚拟页8。
为避免这种情况,设计者规定映射到同一个物理页的虚拟页号必须相同。
为此,系统将将所有进程的虚拟内存中一定数量的起始页预留为fbuf页。
收包处理过程
图中是只有两个安全域的一条路径。
进程1(writer)收到数据包后,从freefbufs队列取一个空闲缓冲区的描述符,将数据包写入该空闲缓冲区,然后将该缓冲区的描述符写入writtenfbufs队列;进程2从writtenfbufs队列中取包缓冲区描述符,从相应的包缓冲区中读数据处理,将释放的包缓冲区描述符写回到freefbufs队列。
到目前为止,接收路径的问题解决了。
网卡驱动将数据包装入一个空闲的包缓冲区,包缓冲区的描述符沿着接收路径传递,每个进程访问同一个物理内存页进行数据包处理,数据包处理完后,包描述符归还给驱动程序进行重用,在此过程中没有发生物理拷贝。
那么发送路径呢?
如何添加包头?
在发送路径上,每一个安全域都要给数据包加上一个包头。
然而为了实现安全保护,我们对于每条路径只允许一个写者,其余为读者,这意味着页只能由写者来修改。
那么,怎么允许其它进程添加包头呢?
应用如何使用fbufs?
现在还剩下一个重要的问题。
大量已有的应用软件是使用标准拷贝语义的socketAPI书写的,即应用执行了write()系统调用后,就可以重用包缓冲区甚至释放了。
然而使用了fbufs之后,在包缓冲区被其它进程使用完之前,应用是不允许写或释放包缓冲区的。
这个问题怎么解决呢?
修改应用API
该问题最终的解决方案是:
API不再保持拷贝语义,应用必须判断能不能写fbufs。
当一个fbuf被交给内核后,应用不能写这个fbuf,直至其被归还到空闲链表中。
为防止出错或恶意的代码,当一个fbuf从应用转递到内核后,内核翻转一个写允许比特,归还fbuf时再重新设置该位。
如果应用在不允许写的情况下做了一次写操作,则会产生一个异常,应用崩溃,但不会影响其它的进程。
已有的网络应用软件必须重写吗?
改变API听起来是一个很大的改动,这是否意味着大量已有的网络应用软件必须重写呢?
这显然是不可能的,这里有几种解决方案。
方法一:
已有的API增加新的系统调用。
比如,增广了fbufs的Solaris除了标准的write()外,还增加了一个uf_writer()调用。
要求高性能的应用可以用新的调用进行重写。
方法二:
用新的扩展实现一个公共的I/O库。
其实,这个问题最终的考虑不是API是否要变,而是修改应用程序来使用该API有多难。
实践表明,将应用移植到类fbuf的API,对应用所做的修改不大,且是局部的。
也就是说,Fbufs方案是可行的。
(可行性很重要,一个再好的方案如果推广起来难度大,也没有人使用)
5.5使用RDMA避免拷贝
在前面考虑的web服务器场景中,web服务器接收请求,然后将文件传输到网络上,Web服务器作为接收端并不需要保存请求消息。
下面考虑在两个终端之间传输一个大文件,接收端需要保存收到的包。
采用fbufs收包
假如采用fbufs,包到达网卡后被拷贝到一个包缓冲区,包缓冲区描述符在路径上传递,被各个安全域处理,在此过程中无数据拷贝。
最后应用进程将数据拷贝到其应用缓冲区中,释放包缓冲区。
为什么要拷贝?
因为文件内容需要保存或被应用处理,而包缓冲区要被重用。
(http请求消息不需要保存,但是文件内容是需要保存的)
采用TOE网卡收包
假设采用TOE网卡。
包到达网卡后,被放入相应的套接字缓冲区进行协议处理和重组。
DMA引擎将数据送入应用缓冲区,向CPU发出中断。
网卡驱动程序通知内核模块接收数据,交给应用程序(包缓冲区描述符)。
应用程序将数据拷贝到文件缓冲区,应用缓冲区重新交给网卡使用。
这里进行拷贝是为了归还应用缓冲区,为什么要重用应用缓冲区而不是重新分配一个呢?
因为准备DMA缓冲区是一种耗时的操作,内核需要将应用缓冲区映射到连续的物理页上,将缓冲区的虚拟地址翻译成能够被DMA使用的总线地址,然后将地址传给网卡。
将一大块应用缓冲区映射到连续的物理页上,并不总是可以做到的,所以DMA缓冲区在初始化时准备好,然后重复使用。
由于给每个套接字分配的缓冲区是有限的,在传输一个大文件的过程中,需要多次中断CPU来接收数据和拷贝数据。
(驱动程序用来管理设备资源,提供设备操作接口、收发数据接口、进行中断处理等。
应用程序通过系统调用来使用设备。
内核模块是连接应用层和协议处理引擎的钩子模块。
)
远程直接内存访问RDMA
通过网络进行DMA的愿景称RDMA。
其意图是……
也就是说,数据一次传输到位,不需要CPU再去移动数据。
RDMA要解决的问题
毫无疑问,网络适配器应卸载全部的协议处理,TOE网卡已经可以做到这一点。
除此之外,还有两个问题需要解决:
(1)接收端适配器如何知道应将数据放在哪儿?
它不能向主机求助,否则就违背了这个意图。
(2)如何保证安全,因为恶意的数据包可能会覆盖关键的内存区域。
5.5.1VAX的RDMA
RDMA在VAX集群中就已经被使用。
计算机集群就是用一批廉价的计算机来代替昂贵的大型机,许多web服务器实际上就是服务器集群。
DEC引进的VAX集群是一个成功的商用产品,为可伸缩应用(如数据库应用)提供计算平台。
该系统的核心是一个140Mb/s的网络,称为计算机互联(ComputerInterconnect,CL),使用一个以太网风格的协议。
用户可以将许多VAX计算机和网络硬盘连接到CL上。
VAX的RDMA解决方案
接收方应用进程锁住一些物理页,用作文件传输的目标存储区域,但呈现出来的逻辑视图是由一些地址连续的虚拟页组成的一个缓冲区。
然后,缓冲区ID被传送到发送端应用。
发送端应用将缓冲区ID及包存放的偏移量随同数据包一起发送。
数据包到达后,接收端适配器根据缓冲区ID和偏移量,将数据包内容拷贝到正确的位置。
包全部到达后,接收端不需要进行任何的页面重映射。
5.5.2RDMA在SAN中的应用
VAX集群引入了一个非常早期的存储区域网络。
存储区域网络是一个后端网络,它将大量计算机和网络硬盘连接在一起。
现在Infiniband在数据中心非常火,因为数据中心的节点之间需要传输大量数据。
尤其是现在数据中心部署了很多的分布式机器学习应用,如进行深度神经网络的训练,需要高吞吐低延迟的通信支持。
总之,如果在两台计算机之间需要传输大量的数据,采用RDMA是非常高效的方法,它可以节省两侧CPU的时间,并且数据存放一次到位,没有多余的拷贝。
5.6把避免拷贝技术扩展到文件系统
前面我们讨论了如何消除与网络通信有关的拷贝,现在我们重新回到web服务器应用场景,考虑文件系统中的拷贝。
为了提高响应速度,服务器通常将请求的文件先读入一个文件缓冲区(copy1),然后从文件缓冲区拷贝到应用缓冲区(copy2),这是必要的,因此copy1不在我们的考虑范围内。
本节的主要目的是消除copy2。
我们把之前讨论的避免拷贝技术扩展到文件系统,介绍三种消除文件系统冗余拷贝的技术。
5.6.1共享内存方法
有了前面通过页面重映射消除拷贝的经验(fbufs),我们自然想到是不是也能用内存映射的方法消除copy2呢?
类UNIX操作系统提供一个方便的系统调用,称为mmap(),它允许应用(如web服务器)将一个文件映射到它的虚拟内存地址空间。
其它操作系统也提供类似的功能。
概念上,当一个文件被映射到一个应用的地址空间,这个应用就好像在它的内存中缓存了这份文件。
实际上,这个缓存的文件只是一组映射。
也就是说,如果web程序将文件映射到了自己的地址空间,则它和文件cache访问的是同一组物理页,从而免除了拷贝的需要。
FlashWeb服务器
我们看一下FlashWeb服务器的做法。
为加快响应速度,web服务器将经常用到的文映射到自己的内存空间。
注意,受到可分配给文件页的物理页数量及页表映射的限制,FlashWeb服务器只能缓存和映射最近常用的文件,不能用来长期存放大量的文件。
事实上,FlashWeb服务器并没有缓存整个文件,只是缓存了一些文件分片,并使用LRU(LeastRecentlyUsed)策略将最近一段时间未用的文件取消映射。
只缓存一些文件分片有什么意义呢?
可以提高响应速度。
如果要访问的文件有一些分片在缓存中(通常是头几个分片),那么这些分片就立即可以发出去,然后再将其余的分片映射进来。
尚未解决的问题
FlashWeb没有消除CGI程序和web服务器之间的拷贝。
文件缓存只能缓
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 端节 算法