加快客户机和服务器的处理速度


developerWorks 中国  >  AIX and UNIX  >

高性能网络编程,第 2 部分: 加快客户机和服务器的处理速度

developerWorks
文档选项
<tr valign="top"><td width="8"><img alt="" height="1" width="8" src="//www.ibm.com/i/c.gif"/></td><td width="16"><img alt="" width="16" height="16" src="//www.ibm.com/i/c.gif"/></td><td class="small" width="122"><p><span class="ast">未显示需要 JavaScript 的文档选项</span></p></td></tr>
将打印机的版面设置成横向打印模式

打印本页

将此页作为电子邮件发送

将此页作为电子邮件发送



级别: 中级

Girish Venkatachalam ([email protected]), 开放源代码顾问和倡导者

2007 年 11 月 19 日

本文为那些希望增强其网络吞吐量的 UNIX® 编程人员提供了诸多技巧。学习如何使用 mmap、收集分散的 I/O 和其他方法加速客户机和服务器的处理速度。

引言

本系列的第 1 部分(请参阅参考资料)重点介绍了利用诸如非阻塞 I/O 之类的高级编程技术最大限度提高网络利用率方面的一些小窍门。这篇文章还介绍了您可以使用的一些其他小窍门。

目前,大多使用硬盘进行文件存储。作为机械设备,在特定情形下,硬盘永远也达不到主要存储(如 RAM 或网络)所具有的速度。推荐使用 SCSI 或 SATA,因为与较旧的 IDE 磁盘相比,它在吞吐量上提供了快速改进。

还应确保您的磁盘使用 DMA 进行传输。

作 为编程人员,可以确定减少磁盘延迟的方法。最相关的主题包括:最小化系统调用上下文切换开销和内存副本开销 (memcpy(2))。对于 TCP 发送和接收缓冲区来说,使用确定的值对减少系统调用开销非常有用。在大多数 UNIX® 代码中,一般使用值 8192 或 0x8000。

当然,您还需要:

  • 通过将开销较大的代码移出循环来减少客户机或服务器 CPU 的负载。
  • 从不使用 sleep(2) 或同步元素。
  • 不考虑使用线程来提高网络性能。

多用途的 mmap(2) 方法

您知道内存映射的 I/O 和 I/O 映射的 I/O。通常在设备驱动程序中以及与外围设备进行通讯时使用此方法。您可以使用 UNIX 系统上的 mmap(2) 系统调用来映射主内存,使其直接指向辅助存储(硬盘)上的文件。

mmap(2) 是一种用途很广的系统调用(如 select(2)),但是,这里关心的重点是增强磁盘 I/O 的性能和减少内存副本开销。借助于 mmap(2) 将文件内容读入主内存,而不使用 read(2)/fread(2) 系统调用可以同时实现这两种要求。

因为消除了冗余的缓冲区副本,所以 mmap(2) 能够提供更高的性能。但是,用法语义并非完全显而易见。您必须使用 ftruncate(2) 调用来分配主内存空间,让内核知道需要分配多少空间来映射使用 mmap(2) 编写的文件。清单 1 显示了详细信息。


清单 1. mmap(2) 文件编写
/**************************************************************/
/**************************************************************/

/******************************************
* mmap(2) file write *
* *
*****************************************/
caddr_t *mm = NULL;

fd = open (filename, O_RDWR | O_TRUNC | O_CREAT, 0644);

if(-1 == fd)
errx(1, "File write");
/* NOT REACHED */

/* If you don't do this, mmapping will never
* work for writing to files
* If you don't know file size in advance as is
* often the case with data streaming from the
* network, you can use a large value here. Once
* write out the whole file, you can shrink it
* to the correct size by calling ftruncate
* again
*/

ret = ftruncate(ctx->fd,filelen);

mm = mmap(NULL, header->filelen, PROT_READ | PROT_WRITE,
MAP_SHARED, ctx->fd, 0);
if (NULL == mm)
errx(1, "mmap() problem");

memcpy(mm + off, buf, len);
off += len;
/* Please don't forget to free mmap(2)ed memory! */
munmap(mm, filelen);
close(fd);

/**************************************************************/
/**************************************************************/

/******************************************
* mmap(2) file read *
* *
*****************************************/
fd = open(filename, O_RDONLY, 0);
if ( -1 == fd)
errx(1, " File read err");
/* NOT REACHED */

fstat(fd, &statbf);
filelen = statbf.st_size;

mm = mmap(NULL, filelen, PROT_READ, MAP_SHARED, fd, 0);

if (NULL == mm)
errx(1, "mmap() error");
/* NOT REACHED */

/* Now onwards you can straight away
* do a memory copy of the mm pointer as it
* will dish out file data to you
*/


bufptr = mm + off;
/* You can straight away copy mmapped memory into the
network buffer for sending */

memcpy(pkt.buf + filenameoff, bufptr, bytes);

/* Please don't forget to free mmap(2)ed memory! */
munmap(mm, filelen);
close(fd);

您可以使用 mmap(2) 在网络下读取文件,将网络内容转储到另一端的文件系统。

mmap(2) 有时可以提供帮助,但有时又会带来损害。例如,当尝试在 NFS 上使用 mmap(2) 处理某一区域时,就可能会带来损害。但是,在大多数其他情况下,只要有可能,最好使用 mmap(2)。

使用 readv 或 writev 分散收集 I/O

除 mmap(2) 外,您还可以使用称为 uio 或分散收集 I/O 的其他技术来加快客户端和服务器的处理速度。该技术不是使用一组字节作为缓冲区,您可以直接操作一组缓冲区,其中的每个缓冲区都可以指向不同源或目的地的 数据。虽然此技术在适用性方面有些限制,但它可临时为您提供帮助。例如,您可以从不同位置填充标头,并将它们合并在一起,而无需直接使用 writev(2) 代替多个 write(2) 进行复制,或使用带有多个 memcpy(2) 的单一 write(2) 进行复制。

若要让您的编程变得复杂化,使用带有非阻塞 I/O 的 uio 非常有用,如下面的清单 2 所示。


清单 2. 使用带有非阻塞 I/O 的 uio 非常有用
writeiovall(int fd, struct iov *iov, int nvec) {

int i, bytes;

i = 0;
while (i < nvec) {
do
{
rv = writev(fd, &vec[i], nvec - i);
} while (rv == -1 &&
(errno == EINTR || errno == EAGAIN));

if (rv == -1) {
if (errno != EINTR && errno != EAGAIN) {
perror("write");
}
return -1;
}
bytes += rv;
/* recalculate vec to deal with partial writes */
while (rv > 0) {
if (rv < vec[i].iov_len) {
vec[i].iov_base = (char *) vec[i].iov_base + rv;
vec[i].iov_len -= rv;
rv = 0;
}
else {
rv -= vec[i].iov_len;
++i;
}
}
}

/* We should get here only after we write out everything */

return 0;

}

在代码中,套接字写入可以编写一部分 uio 缓冲区,或者编写几个完整的 uio 缓冲区。或者可以编写几个 uio 缓冲区和部分编写其中的一个缓冲区。图 1 帮助显示了难点。


图 1. 带有非阻塞套接字的 uio
加快客户机和服务器的处理速度_第1张图片

其他高级技术

BSD 内核心代码使用一个称为 mbuf 的缓冲区的链接列表。您可以在 mbuf(9) 手册页的任何 BSD 系统部分或有关该主题的许多文章中获得有关它们的知识。系统地讨论不在本文的范围内,但在这里简单介绍一下。

从本质上讲,mbuf 是缓冲区的一个链接列表,每个缓冲区持有 128 到 1024 字节中的任何部分。它们一般都拥有大约 128 个字节。

由于是内核负责在数据到达后立即清除网络接口卡上的硬件缓冲区,所以 mbuf 子系统在处理网络数据方面非常有效。在千兆位网络上,如果不能正确处理,则内核的负载将非常重。

每个 mbuf 都包含三个重要信息片段:

  • 数据的开始处
  • 数据的大小
  • 数据的类型

它还包含许多其他内容,但这些是帮助处理的关键字段。

有许多宏和函数可帮助检索标头,并在处理完成后移除标头,以及挂起和预先计划数据。只有通过使用复杂的框架,内核才能高效地完成其作业。

如果您确实对获取应用程序的最佳性能感兴趣,则可以尝试针对您的用户级协议处理实现一些熟悉的内容。确保这些代码开销不会占用其他处理开销。

不必使用磁盘,您可以使用闪存编写一个自定义的磁盘驱动程序,并进行 RAID 处理。

增强性能就像一个永远没有结尾的故事。这个故事会永远不停地讲下去……

共享本文……

digg 请 Digg 这个故事
del.icio.u 发布到 del.icio.u
Slashdot Slashdot 一下!


参考资料

学习
  • 您可以参阅本文在 developerWorks 全球站点上的 英文原文 。

  • 高性能网络编程:查看本系列中的其他部分。

  • mmap(2):“The Open Group Base Specifications Issue 6”中的此手册页提供了更加详细的信息。

  • uio 结构:AIX® 技术参考详细介绍了 uio。

  • readv(2) 和 writev(2):“The Open Group Base Specifications Issue 6”提供了有关这些手册页的详细信息。

  • /guide/bgnet/output/html 的索引:Beej 的《网络编程指南》提供了获取高级网络技术的链接。

  • Polipo:详细了解此缓存 Web 代理。

  • PMTU (Path MTU) Discovery:该站点提供有关处理过大数据包的信息。

  • 受欢迎的内容:查看您的同事所感兴趣的 AIX 和 UNIX 文章。

  • 按主题搜索“AIX and UNIX”库:
    • 系统管理
    • 应用程序开发
    • 性能
    • 移植
    • 安全性
    • 提示
    • 工具和实用程序
    • Java™ 技术
    • Linux®
    • 开放源代码

  • AIX and UNIX 专区:developerWorks 的“AIX and UNIX 专区”提供了大量与 AIX 系统管理的所有方面相关的信息,您可以利用它们来扩展自己的 UNIX 技能。

  • AIX and UNIX 新手入门:访问“AIX and UNIX 新手入门”页面可了解更多关于 AIX 和 UNIX 的内容。

  • AIX 6 Wiki:发现 AIX 相关技术信息的协作环境。

  • Safari 书店:访问此电子参考资料库可查找特定的技术资源。

  • developerWorks 技术事件和网络广播:了解最新的 developerWorks 技术事件和网络广播。

  • Podcasts:收听 Podcast 并与 IBM 技术专家保持同步。

获得产品和技术
  • IBM 试用软件:从 developerWorks 可直接下载这些试用软件,您可以利用它们开发您的下一个项目。


讨论
  • 参与 developerWorks Blog,从而加入到 developerWorks 社区中来。

  • 参与“AIX and UNIX”论坛:
    • AIX—技术论坛
    • AIX 6 公开测试版
    • AIX for Developers 论坛
    • 集群系统管理
    • IBM Support Assistant
    • 性能工具—技术
    • 虚拟化—技术
    • 更多“AIX and UNIX”论坛



关于作者

Photo of Girish Venkatachalam

Girish Venkatachalam 从事 UNIX 程序员的工作已经超过 10 年。他为 Nucleus 操作系统开发了用于嵌入式系统的 IPsec。他的兴趣还包括加密、多媒体、网络和嵌入式系统。他还喜欢游泳、骑自行车、瑜珈,他是一名健身狂热爱好者。您可以通过 [email protected] 与他联系。

 

你可能感兴趣的:(加快客户机和服务器的处理速度)