(这里的零拷贝指的是可以不需要cpu参与的拷贝)
许多web应用提供大量的静态内容服务,这意味着服务器要从硬盘读取内容并将完全相同的内容写到response的socket中。此活动过程看起来只要少量的cpu活动,但它的效率非常低下:操作系统内核从硬盘读取数据,然后将这些数据通过内核-用户边界传递给应用程序,然后应用程序又将读取到的数据再次通过内核-用户边界来写入内核中的socket。从这个过程中我们看到,在整个数据从硬盘文件中读取,然后写入socket,应用程序是作为一个非常低效的媒介存在。
每次数据通过内核-用户边界时,数据都必须被拷贝一次,这消耗了一定的cpu时钟周期和内存。幸运地是,通过zero-copy的技术你完全可以省略掉这些不必要的拷贝操作。使用zero-copy的应用程序可以请求内核直接将硬盘中的数据拷贝到socket中,而不需要经过应用程序这个中间层。zero-copy大大提升了应用程序的性能而且减少了操作系统在内核态和用户态之间切换的次数。
java类库通过FileChannel类中的transferIo()方法来支持zero-copy。通过此方法可以直接将字节从一个通道传输到另一个可写的通道,而不需要经过应用程序。本文首先演示通过传统的复制语义完成简单文件传输所产生的开销,然后展示zero-copy的技术带来了怎样的性能提升。
数据传输:传统实现
考虑一下从文件中读取数据然后通过网络传输到另一个程序的场景(这个场景描述了很多服务应用的行为,包括提供静态页面的web服务,ftp服务,邮件服务,等等)。这个操作的核心是通过Listing1描述的两个调用来实现的:
Listing 1:
File.read(fileDesc, buf, len);
Socket.send(socket, buf, len);