原文:http://www.kegel.com/c10k.html

转载:https://rtoax.blog.csdn.net/article/details/117317900

译文:https://rtoax.blog.csdn.net/article/details/108723496


是时候让Web服务器同时处理一万个客户端了,您不觉得吗?毕竟,网络现在是一个很大的地方。

而且计算机也很大。您可以以1200美元左右的价格购买带有2 GB RAM的1000MHz机器和1000Mbit / sec以太网卡。我们来看-在20000个客户端上,每个客户端分别为50KHz,100Kbytes和50Kbits / sec。从磁盘上获取4 KB的数据并将其每秒发送给网络(每2万个客户端一次),所需要的功能不应该超过它。(顺便说一下,每个客户端的费用为0.08美元。某些操作系统收取的每客户端100美元的许可费用看起来有点沉重!)因此,硬件不再是瓶颈。

1999年,最繁忙的ftp网站之一cdrom.com实际上通过千兆以太网管道同时处理了10000个客户端。到2001年为止,几家ISP现在都提供相同的速度 ,他们希望这种速度在大型企业客户中越来越受欢迎。

瘦客户端计算模式似乎正在风起云涌—这次服务器已在Internet上,为成千上万的客户端提供服务。

考虑到这一点,这里有一些有关如何配置操作系统和编写代码以支持数千个客户端的说明。讨论围绕类似Unix的操作系统展开,因为这是我个人感兴趣的领域,但是Windows也涵盖了一点。

内容


内容

相关网站

本书先阅读

I / O框架

I / O策略

1.每个线程服务许多客户端,并使用非阻塞I / O和级别触发的就绪通知

2.为每个线程服务许多客户端,并使用非阻塞I / O和就绪状态更改通知

3.为每个服务器线程服务许多客户端,并使用异步I / O

4.为每个服务器线程服务一个客户端

5.将服务器代码构建到内核中

将TCP堆栈放入用户空间

注释

限制打开的文件句柄

线程限制

Java问题

其他技巧

其他限制

内核问题

评估服务器性能

例子

有趣的基于select()的服务器

有趣的基于/ dev / poll的服务器

有趣的基于epoll的服务器

有趣的基于kqueue()的服务器

有趣的基于实时信号的服务器

有趣的基于线程的服务器

有趣的内核服务器

其他有趣的链接


相关网站

请参阅Nick Black出色的Fast UNIX Servers 页面,以大约在2009年的情况下查看情况。

2003年10月,Felix von Leitner整理了一个出色的网页 和有关网络可伸缩性的演示文稿,并提供了比较各种网络系统调用和操作系统的基准测试。他的观察之一是2.6 Linux内核确实击败了2.4内核,但是有很多很多很好的图表可以使OS开发人员在一段时间内考虑一下。(另请参阅Slashdot 评论;很有趣的是,看看是否有人对Felix的结果进行了跟踪基准的改进。)

本书先阅读

如果您还没有阅读过,请出去阅读 W. Richard Stevens的 著作《 Unix网络编程:网络Apis:套接字和Xti(第1卷)》。它描述了与编写高性能服务器有关的许多I / O策略和陷阱。它甚至谈到“雷群”问题。同时,请阅读Jeff Darcy关于高性能服务器设计的说明。

(另一本书对那些正在使用*而不是*写* Web服务器的人可能更有用的是 Cal Henderson的《构建可扩展网站》。)

I / O框架

提供了预打包的库,这些库可以抽象出下面介绍的一些技术,从而使您的代码与操作系统隔离,并使其更易于移植。

  • ACE是重量级的C ++ I / O框架,其中包含某些I / O策略和许多其他有用对象的面向对象的实现。特别是,他的Reactor是执行非阻塞I / O的OO方法,而Proactor是执行异步I / O的OO方法。
  • ASIO是一个C ++ I / O框架,正在成为Boost库的一部分。就像针对STL时代更新的ACE。
  • libevent是Niels Provos的轻量级C I / O框架。它支持kqueue和select,不久将支持poll和epoll。我认为,它只是水平触发的(什么是epoll的水平触发与边缘触发?两段代码彻底理解,它有好有坏。Niels有 一个很好的时间图表来处理一个事件 ,它是连接数的函数。它显示kqueue和sys_epoll是明确的赢家。
  • 我自己对轻量级框架的尝试(不幸的是,没有及时更新):
    • Poller是一个轻量级的C ++ I / O框架,它使用所需的任何基础就绪API(轮询,选择,/ dev / poll,kqueue或sigio)来实现级别触发的就绪API。对于比较各种API性能的基准测试很有用。 本文档链接到下面的Poller子类,以说明如何使用每个就绪API。
    • rn是一个轻量级的CI / O框架,是我继Poller之后的第二次尝试。它是lgpl(因此更易于在商业应用程序中使用)和C(因此更易于在非C ++应用程序中使用)。它被用于一些商业产品。
  • Matt Welsh 在2000年4月撰写了一篇论文,内容涉及在构建可伸缩服务器时如何平衡工作线程和事件驱动技术的使用。本文介绍了他的Sandstorm I / O框架的一部分。
  • 科里·尼尔森的天秤!库 -Windows的异步套接字,文件和管道I / O库

I / O策略

网络软件的设计人员有很多选择。这里有一些:

  • 是否以及如何从单个线程发出多个I / O调用

    • 别; 始终使用阻塞/同步调用,并且可能使用多个线程或进程来实现并发
    • 使用非阻塞调用(例如,将套接字设置为O_NONBLOCK上的write())启动I / O,并使用就绪通知(例如poll()或/ dev / poll)来了解何时可以在该通道上启动下一个I / O 。通常仅可用于网络I / O,而不能用于磁盘I / O。
    • 使用异步调用(例如aio_write())启动I / O,并使用完成通知(例如信号或完成端口)来了解I / O何时完成。适用于网络和磁盘I / O。
  • 如何控制为每个客户端提供服务的代码
    • 每个客户端一个进程(1980年左右开始使用的经典Unix方法)
    • 一个OS级线程可处理许多客户端;每个客户由以下人员控制:
      • 用户级线程(例如,GNU状态线程,带有绿色线程的经典Java)
      • 状态机(有点深奥,但在某些圈子中很流行;我最喜欢)
      • 延续(有点深奥,但在某些圈子中很流行)
    • 每个客户端有一个操作系统级别的线程(例如具有本地线程的经典Java)
    • 每个活动客户端有一个操作系统级线程(例如,具有apache前端的Tomcat; NT完成端口;线程池)
  • 是使用标准O / S服务,还是将一些代码放入内核(例如,在自定义驱动程序,内核模块或VxD中)

以下五个组合似乎很受欢迎:

  1. 为每个线程服务许多客户端,并使用非阻塞I / O和级别触发的就绪通知
  2. 为每个线程服务许多客户端,并使用非阻塞I / O和就绪状态更改通知
  3. 为每个服务器线程服务许多客户端,并使用异步I / O
  4. 为每个服务器线程服务一个客户端,并使用阻塞I / O
  5. 将服务器代码构建到内核中

1.每个线程服务许多客户端,并使用非阻塞I / O和级别触发的就绪通知

...在所有网络句柄上设置非阻塞模式,并使用select()或poll()告诉哪个网络句柄有数据等待。这是传统的最爱。通过这种方案,内核会告诉您文件描述符是否已准备好,自从上次内核告诉您文件描述符以来,您是否已对该文件描述符执行了任何操作。(“级别触发”的名称来自计算机硬件设计;与“边缘触发”的含义相反。乔纳森·莱蒙(Jonathon Lemon)在他的BSDCON 2000论文的kqueue()中介绍了这些术语 。)

注意:记住内核的就绪通知只是一个提示,这一点特别重要。当您尝试从文件描述符中读取文件描述符时,可能不再准备就绪。这就是为什么在使用就绪通知时使用非阻塞模式很重要的原因。

此方法的一个重要瓶颈是,如果当前页面不在内核中,则从磁盘块读取(read)或sendfile()。在磁盘文件句柄上设置非阻止模式无效。内存映射的磁盘文件也是如此。服务器第一次需要磁盘I / O时,其进程将阻塞,所有客户端都必须等待,并且原始的非线程性能浪费了。
这就是异步I / O的目的,但是在缺少AIO的系统上,执行磁盘I / O的工作线程或进程也可以解决此瓶颈。一种方法是使用内存映射文件,如果mincore()指示需要I / O,请要求工作人员执行I / O,然后继续处理网络流量。Jef Poskanzer提到Pai,Druschel和Zwaenepoel的1999 Flash Web服务器使用了该技巧。他们在 Usenix '99就可以了。看起来mincore()在BSD衍生的Unix(例如FreeBSD 和Solaris )中可用,但不属于Single Unix Specification。由于Chuck Lever,它可以从Linux 2.3.51版开始作为Linux的一部分使用 。

但是 在2003年11月的freebsd-hackers名单上,Vivek Pei等人报告了 使用其Flash Web服务器的系统范围分析来解决瓶颈的非常好结果。他们发现一个瓶颈是mincore(猜想这毕竟不是一个好主意)。另一个瓶颈是sendfile在磁盘访问时阻塞。他们通过引入修改后的sendfile()来提高性能,该方法在获取磁盘页面尚不在核心时返回类似于EWOULDBLOCK的内容。(不确定您如何告诉用户该页面现在位于页面上……在我看来,这里真正需要的是aio_sendfile()。)优化的最终结果是,在1GHZ / 1GB FreeBSD盒子上,SpecWeb99得分约为800,这比spec.org上记录的任何内容都要好。

单线程可以通过多种方式来判断一组非阻塞套接字中的哪些已准备好进行I / O:

  • 传统的select()
    不幸的是,select()仅限于FD_SETSIZE句柄。该限制被编译到标准库和用户程序中。(某些C库版本使您可以在用户应用编译时提高此限制。)

    有关如何与其他就绪通知方案互换使用select()的示例,请参见 Poller_select (cc, h)。

  • 传统的poll()
    没有对poll()可以处理的文件描述符数量进行硬编码的限制,但是它确实变慢了大约数千,因为大多数文件描述符在任何时候都处于空闲状态,并且扫描了数千个文件描述符需要时间。

    某些操作系统(例如Solaris 8)通过使用轮询提示等技术来加速poll()等,该技术 由Niels Provos在1999年针对Linux 实施并进行了基准测试。

    有关如何将poll()与其他就绪通知方案互换使用的示例,请参见 Poller_poll (cc, h, Benchmarks)。

  • / dev / poll - Solaris
    这是建议的Solaris轮询替代。

    / dev / poll背后的想法是利用经常以相同的参数多次调用poll()的事实。使用/ dev / poll,您可以打开/ dev / poll的句柄,并通过写入该句柄仅一次告诉OS您感兴趣的文件。从那时起,您只需从该句柄中读取一组当前准备好的文件描述符即可。

    它在Solaris 7中安静地出现(请参见patchid 106541),但它的首次公开出现在 Solaris 8中; 根据Sun的说法,在750个客户端上,这占poll()开销的10%。

    在Linux上尝试了/ dev / poll的各种实现,但是没有一个能像epoll一样出色,并且从未真正完成过。不建议在Linux上使用/ dev / poll。

    有关 如何与许多其他就绪通知方案互换使用/ dev / poll的示例,请参见 Poller_devpoll (cc, h 基准)。(警告-该示例适用于Linux / dev / poll,在Solaris上可能无法正常工作。)

  • kqueue()- FreeBSD
    这是FreeBSD(以及不久之后的NetBSD)的建议轮询替代。

    见下文。 kqueue()可以指定边沿触发或电平触发。

  • 我大epoll()呢???

2.为每个线程服务许多客户端,并使用非阻塞I / O和就绪状态更改通知

就绪更改通知(或边缘触发的就绪通知)意味着您为内核提供了一个文件描述符,然后,当该描述符从未就绪过渡 到就绪时,内核会以某种方式通知您。然后,它假定您知道文件描述符已准备就绪,并且在您执行导致文件描述符不再准备就绪的操作之前(例如,直到收到关于以下内容的EWOULDBLOCK错误为止),该文件描述符将不再发送该类型的任何就绪通知。发送,接收或接受呼叫,或者发送或接收的传输少于请求的字节数)。

使用就绪状态更改通知时,您必须为虚假事件做好准备,因为一种常见的实现方式是,无论何时接收到任何数据包,无论文件描述符是否已准备就绪,都会发出就绪状态信号。

这与“ 级别触发 ”的就绪通知相反。编程错误的容忍度要低一些,因为如果您仅错过一个事件,那么该事件所针对的连接将永远卡住。尽管如此,我发现边缘触发的就绪通知使使用OpenSSL编程非阻塞客户端变得更加容易,因此值得尝试。

[Banga,Mogul,Drusha '99] 在1999年描述了这种方案。

有几种API可让应用程序检索“文件描述符准备就绪”通知:

  • kqueue() 这是FreeBSD(以及即将推出的NetBSD)的推荐的边沿触发轮询轮询。

    FreeBSD 4.3和更高版本以及2002年10月起的NetBSD-current支持对poll()的通用替代,称为 kqueue()/ kevent();它支持边沿触发和电平触发。(另请参见乔纳森·莱蒙(Jonathan Lemon)的页面 和他在kqueue()上的BSDCon 2000论文。)

    与/ dev / poll一样,您分配了一个侦听对象,但没有打开文件/ dev / poll,而是调用kqueue()来分配一个对象。要更改您正在侦听的事件或获取当前事件的列表,请在kqueue()返回的描述符上调用kevent()。它不仅可以侦听套接字的准备情况,还可以侦听纯文件的准备情况,信号甚至I / O完成情况。

    注意:从2000年10月开始,FreeBSD上的线程库与kqueue()不能很好地交互。显然,当kqueue()阻塞时,整个进程都会阻塞,而不仅仅是调用线程。

    有关如何与许多其他就绪通知方案互换使用kqueue()的示例,请参见 Poller_kqueue (cc, h, 基准)。

    使用kqueue()的示例和库:

    • PyKQueue -kqueue()的Python绑定
    • 罗纳德·吉尔梅特(Ronald F. Guilmette)的示例回显服务器;另请参阅 他在2000年9月28日发布的freebsd.questions帖子。
  • epoll
    这是2.6 Linux内核的推荐的边沿触发轮询轮询。

    2001年7月11日,Davide Libenzi提出了一种替代实时信号的方法。他的补丁程序提供了他现在所说的 / dev / epoll www.xmailserver.org/linux-patches/nio-improve.html。这就像实时信号就绪通知一样,但是它合并了冗余事件,并且具有用于批量事件检索的更有效方案。

    Epoll的接口从/ dev中的特殊文件更改为系统调用sys_epoll之后,从2.5.46开始将其合并到2.5内核树中。适用于旧版epoll的补丁可用于2.4内核。

    关于在2002年万圣节前后将epoll,aio和其他事件源统一在linux内核邮件列表上的争论很长 。这可能会发生,但是Davide通常首先集中精力加强epoll。

  • Polyakov的kevent(Linux 2.6+) 新闻快报:2006年2月9日以及2006年7月9日,Evgeniy Polyakov发布了似乎统一了epoll和aio的补丁程序。他的目标是支持网络AIO。 看到:
    • 有关kevent的LWN文章
    • 他七月份的公告
    • 他的活动页面
    • 他的naio页面
    • 最近的一些讨论
  • Drepper的新网络接口(Linux 2.6+的建议)
    在OLS 2006上,Ulrich Drepper提出了一种新的高速异步网络API。看到:

    • 他的论文“ 异步零复制网络I / O的需求 ”
    • 他的幻灯片
    • 7月22日的LWN文章
  • 实时信号
    这是2.4 Linux内核的推荐的边沿触发轮询替代。

    2.4 linux内核可以通过特定的实时信号传递套接字就绪事件。以下是启用此行为的方法:

    /* Mask off SIGIO and the signal you want to use. */
    sigemptyset(&sigset);
    sigaddset(&sigset, signum);
    sigaddset(&sigset, SIGIO);
    sigprocmask(SIG_BLOCK, &m_sigset, NULL);
    /* For each file descriptor, invoke F_SETOWN, F_SETSIG, and set O_ASYNC. */
    fcntl(fd, F_SETOWN, (int) getpid());
    fcntl(fd, F_SETSIG, signum);
    flags = fcntl(fd, F_GETFL);
    flags |= O_NONBLOCK|O_ASYNC;
    fcntl(fd, F_SETFL, flags);

    当正常的I / O功能(如read()或write())完成时,它将发送该信号。要使用此功能,请编写一个普通的poll()外循环,并在其中处理了poll()注意的所有fd之后,循环调用 sigwaitinfo()。
    如果sigwaitinfo或sigtimedwait返回您的实时信号,则siginfo.si_fd和siginfo.si_band会提供与pollfd.fd和pollfd.revents在调用poll()之后几乎相同的信息,因此您将处理I / o,并继续调用sigwaitinfo ()。
    如果sigwaitinfo返回传统的SIGIO,则信号队列溢出,因此您可以 通过将信号处理程序临时更改为SIG_DFL来刷新信号队列,并返回到外部poll()循环。

    有关如何与许多其他就绪通知方案互换使用rtsignal的示例,请参见 Poller_sigio (cc, h)。

    有关直接使用此功能的示例代码,请参见Zach Brown的phhttpd。(或者不; phhttpd有点难以理解...)

    [ Provos,Lever和Tweedie 2000 ]使用sigtimedwait(),sigtimedwait4()的变体描述了phhttpd的最新基准,它使您可以通过一个呼叫检索多个信号。有趣的是,sigtimedwait4()对于他们的主要好处似乎是它允许应用程序评估系统过载(因此它可以正常运行)。(请注意poll()提供了相同的系统过载度量。)

  • 每fd信号
    Chandra和Mosberger提出了对实时信号方法的一种改进,称为“每fd信号”,它通过合并冗余事件来减少或消除实时信号队列溢出。不过,它并没有比epoll更好。他们的论文( www.hpl.hp.com/techreports/2000/HPL-2000-174.html)比较了该方案与select()和/ dev / poll的性能。

    维塔利鲁班宣布在2001年5月18日实施该计划的补丁 ; 他的补丁位于www.luban.org/GPL/gpl.html。(注意:截至2001年9月,此修补程序在高负载下仍可能存在稳定性问题。 大约4500名用户的dkftpbench可能会触发oops。)

    有关如何与许多其他就绪通知方案互换使用per-fd信号的示例,请参见 Poller_sigfd (cc, h)。

3.为每个服务器线程服务许多客户端,并使用异步I / O

这在Unix中尚未流行,可能是因为很少有操作系统支持异步I / O,也可能是因为它(例如非阻塞I / O)需要重新考虑应用程序。在标准Unix下,aio_接口 (从该链接向下滚动到“异步输入和输出”)提供异步I / O,该接口将信号和值与每个I / O操作相关联。信号及其值被排队,并有效地传递给用户进程。这来自POSIX 1003.1b实时扩展,并且在Single Unix Specification版本2中。

AIO通常与边沿触发的完成通知一起使用,即操作完成时将信号排队。(它也可以通过调用aio_suspend()与级别触发的完成通知一起使用 ,尽管我怀疑很少有人这样做。)

glibc 2.1和更高版本提供了为实现标准合规性而不是性能而编写的通用实现。

从2.5.32开始,Ben LaHaise的Linux AIO实现已合并到主要Linux内核中。它不使用内核线程,并且具有非常有效的基础api,但是(从2.6.0-test2版本开始)尚不支持套接字。(对于2.4内核也有一个AIO补丁,但是2.5 / 2.6的实现有所不同。)更多信息:

  • 页面“ Linux的内核异步I / O(AIO)支持 ”试图将有关2.6内核的AIO实现的所有信息联系在一起(发布于2003年9月16日)
  • 第三回合: Benjamin CR LaHaise的aio vs / dev / epoll(在2002 OLS上展示)
  • Bhattacharya,Pratt,Pulaverty和Morgan,IBM的Linux 2.5中的异步I / O Suport;在OLS'2003上展示
  • Suparna Bhattacharya的Linux异步I / O(aio)设计说明 -比较Ben的AIO,SGI的KAIO和其他一些AIO项目
  • Linux AIO主页 -Ben的初步补丁,邮件列表等。
  • linux-aio邮件列表档案
  • libaio- oracle-在libaio之上实现标准Posix AIO的库。 乔尔•贝克尔(Joel Becker)在2003年4月18日首次提及。

Suparna还建议您看看 DAFS API的AIO方法。

Red Hat AS 和Suse SLES都在2.4内核上提供了高性能的实现。它与2.6内核实现有关,但并不完全相同。

2006年2月,正在尝试提供网络AIO;请参阅上面有关Evgeniy Polyakov基于kevent的AIO的注释。

在1999年,SGI为Linux 实现了高速AIO。从1.1版开始,据说可以同时与磁盘I / O和套接字一起使用。似乎使用内核线程。对于不能等Ben的AIO支持套接字的人来说,它仍然很有用。

据说 O'Reilly的书 POSIX.4:《现实世界中的编程》 包括了对aio的良好介绍。

一种较早的,非标准的教程,在Solaris AIO实现在线 在Sunsite。可能值得一看,但是请记住,您需要在精神上将“ aioread”转换为“ aio_read”等。

请注意,AIO无法提供一种在不阻止磁盘I / O的情况下打开文件的方法。如果您关心由打开磁盘文件引起的睡眠, Linus建议 您仅应在不同的线程中执行open(),而不希望进行aio_open()系统调用。

在Windows下,异步I / O与术语“重叠I / O”和IOCP或“ I / O完成端口”关联。微软的IOCP将异步技术(如异步I / O(如aio_write)和排队完成通知(如将aio_sigevent字段与aio_write结合使用))的现有技术结合了一种新思想,即保留一些请求以尝试保持关联的运行线程数具有单个IOCP常数。有关更多信息,请参见 sysinternals.com上Mark Mark Russinovich的Inside I / O Completion Ports,Jeffrey Richter的书“为Microsoft Windows 2000编程服务器端应用程序”(亚马逊, MSPress), 美国专利#06223207或 MSDN。

4.为每个服务器线程服务一个客户端

...并让read()和write()块。具有为每个客户端使用整个堆栈框架的缺点,这会浪费内存。许多操作系统也难以处理数百个线程。如果每个线程获得2MB堆栈(这不是一个不常见的默认值),则在32位计算机上使用1GB用户可访问VM的(2 ^ 30/2 ^ 21)= 512个线程会耗尽*虚拟内存*(例如,例如,x86上通常提供的Linux)。您可以通过为每个线程分配较小的堆栈来解决此问题,但是由于大多数线程库不允许在创建后增加线程堆栈,因此这样做意味着设计程序以最大程度地减少堆栈使用。您也可以通过移至64位处理器来解决此问题。

Linux,FreeBSD和Solaris中的线程支持正在改善,即使对于主流用户,64位处理器也已迫在眉睫。也许在不久的将来,那些愿意为每个客户端使用一个线程的人甚至可以为10000个客户端使用该范例。不过,目前,如果您确实想支持那么多客户,则最好使用其他一些范例。

有关线程的观点,请参阅 HotOS IX上由Condit的von Behren和UCB的Brewer撰写的“ 为什么事件是个坏主意(对于高并发服务器)”。来自反线程阵营的任何人都要指出一篇反驳该论文的论文吗?:-)

Linux线程

LinuxTheads是标准Linux线程库的名称。自glibc2.0起,它已集成到glibc中,并且大多数与Posix兼容,但性能和信号支持不佳。

NGPT:适用于Linux的下一代Posix线程

NGPT是IBM 发起的一个项目,旨在为Linux提供良好的Posix兼容线程支持。它现在处于2.2的稳定版本,并且运行良好...但是NGPT团队 宣布 他们将NGPT代码库置于仅支持模式,因为他们认为这是“长期支持社区的最佳方法”。NGPT团队将继续致力于改善Linux线程支持,但现在专注于改善NPTL。(对NGPT小组的出色工作和向NPTL承认的优美方式表示敬意。)

NPTL:Linux的本地Posix线程库

NPTL是Ulrich Drepper (glibc的仁慈dict ^ H ^ H ^ H ^ Hmaintainer )和 Ingo Molnar的一个项目, 旨在为Linux提供世界一流的Posix线程支持。

从2003年10月5日起,NPTL现在已作为附加目录(就像linuxthreads)合并到glibc cvs树中,因此几乎可以肯定它将与glibc的下一个版本一起发布。

包含NPTL早期快照的第一个主要发行版是Red Hat9。(这对于某些用户来说有点不方便,但是有人必须打破僵局...)

NPTL链接:

  • NPTL讨论的邮件列表
  • NPTL源代码
  • NPTL的初始公告
  • 描述NPTL目标的原始白皮书
  • 修订的白皮书描述了NPTL的最终设计
  • Ingo Molnar的第一个基准测试表明它可以处理10 ^ 6线程
  • Ulrich的基准测试比较了LinuxThreads,NPTL和IBM的NGPT的性能。似乎表明NPTL比NGPT快得多。

这是我描述NPTL历史的尝试(另请参阅Jerry Cooperstein的文章):

在2002年3月,NGPT小组的Bill Abt与glibc维护者Ulrich Drepper以及其他人开会 ,共同探讨如何处理LinuxThreads。会议提出的一个想法是提高互斥量性能。Rusty Russell 等人随后实现了 快速用户空间互斥体(futexes),现在NGPT和NPTL都使用了它们。大多数与会者认为NGPT应该合并到glibc中。

不过,乌尔里希·德雷珀(Ulrich Drepper)不喜欢NGPT,并认为他可以做得更好。(对于曾经尝试为glibc贡献补丁的人来说,这可能并不令人惊讶:-)在接下来的几个月中,Ulrich Drepper,Ingo Molnar和其他人贡献了glibc和内核更改,这些被称为本机Posix线程库(NPTL)。NPTL使用为NGPT设计的所有内核增强功能,并利用了一些新功能。Ingo Molnar 描述 了以下内核增强功能:

NPTL使用NGPT引入的三个内核功能:getpid()返回PID,CLONE_THREAD和futexes;NPTL还使用(并依赖)作为该项目一部分开发的更广泛的新内核功能集。

NGPT在2.5.8左右引入内核的某些项目已被修改,清理和扩展,例如线程组处理(CLONE_THREAD)。[影响NGPT兼容性的CLONE_THREAD更改已与NGPT人员同步,以确保NGPT不会以任何不可接受的方式破坏。]

设计白皮书http://people.redhat.com/drepper/nptl-design.pdf中描述了为NPTL开发并使用的内核功能。

简短列表:TLS支持,各种克隆扩展(CLONE_SETTLS,CLONE_SETTID,CLONE_CLEARTID),POSIX线程信号处理,sys_exit()扩展(在VM发行时发行TID futex),sys_exit_group()系统调用,sys_execve()增强并支持分离线程。

还有一些工作要扩展PID空间-例如。由于64K PID假设,max_pid和pid分配可伸缩性工作,导致procfs崩溃。另外,还完成了一些仅性能方面的改进。

本质上,新功能是对1:1线程的一种不妥协的方法-内核现在在可以改善线程的所有方面提供帮助,并且我们为每个基本线程原语精确地进行了最少必要的上下文切换和内核调用。

两者之间的一大区别是NPTL是1:1线程模型,而NGPT是M:N线程模型(请参见下文)。尽管如此, Ulrich的初始基准 似乎表明NPTL确实比NGPT快得多。(NGPT团队期待看到Ulrich的基准代码来验证结果。)

FreeBSD线程支持

FreeBSD支持LinuxThreads和用户空间线程库。另外,在FreeBSD 5.0中引入了称为KSE的M:N实现。有关一个概述,请访问www.unobvious.com/bsd/freebsd-threads.html。

2003年3月25日, Jeff Roberson在freebsd-arch上发布了:

...感谢Julian,David Xu,Mini,Dan Eischen和其他所有参与KSE和libpthread开发Mini的人提供的基础,我已经开发了1:1线程实现。该代码与KSE并行工作,不会以任何方式破坏它。实际上,通过测试共享位可以帮助使M:N线程更紧密。...

在2006年7月, Robert Watson提出1:1线程实现成为FreeBsd 7.x中的默认设置:

我知道以前已经讨论过这个问题,但是我认为7.x会向前发展,是时候重新考虑了。在许多常见应用程序和场景的基准测试中,libthr展示了比libpthread更好的性能... libthr也已在我们许多平台上实现,并且已经在多个平台上实现了libpthread。我们对MySQL和其他重线程用户的第一个建议是“ Switch to libthr”,这也是有启发性的!...因此,草人建议是:将libthr设置为7.x上的默认线程库。

NetBSD线程支持

根据苏打则之记:

基于调度程序激活模型的内核支持的M:N线程库于2003年1月18日合并到NetBSD-current中。

有关详细信息,请参阅 在FREENIX '02上由Wasabi Systems,Inc.的Nathan J. Williams撰写的NetBSD操作系统上调度程序激活的实现。

Solaris线程支持

Solaris中的线程支持正在发展……从Solaris 2到Solaris 8,默认线程库使用M:N模型,但是Solaris 9默认为1:1模型线程支持。请参见Sun的多线程编程指南 和有关Java和Solaris线程的Sun注释。

JDK 1.3.x和更早版本中的Java线程支持

众所周知,直到JDK1.3.x的Java不支持任何处理网络连接的方法,每个客户端只有一个线程。 Volanomark是一个很好的微基准,它可以测量各种同时连接数下每秒的吞吐量。到2003年5月为止,来自各个供应商的JDK 1.3实现实际上能够处理上万个同时连接-尽管性能显着下降。有关 哪些JVM可以处理10000个连接以及随着连接数量增加性能如何下降的想法,请参阅表4。

注意:1:1线程与M:N线程

实现线程库时有一个选择:您可以将所有线程支持放入内核(这称为1:1线程模型),也可以将其相当一部分移入用户空间(这称为M :N线程模型)。一方面,M:N被认为具有更高的性能,但它是如此复杂,以至于很难做到正确,并且大多数人正在远离它。

  • 为什么Ingo Molnar比M:N更喜欢1:1
  • Sun正在转向1:1线程
  • NGPT是Linux的M:N线程库。
  • 尽管Ulrich Drepper计划在新的glibc线程库中使用M:N线程,但此后他已切换到1:1线程模型。
  • MacOSX似乎使用1:1线程。
  • FreeBSD和 NetBSD 似乎仍然相信M:N线程...唯一的障碍?好像freebsd 7.0可能会切换到1:1线程(请参见上文),因此也许M:N线程的信徒终于在所有地方都被证明是错误的。

5.将服务器代码构建到内核中

据说Novell和Microsoft都在不同的时间执行了此操作,至少一个NFS实现执行了此操作, khttpd针对Linux和静态网页执行了此操作,而 “ TUX”(线程化linUX Web服务器) 是一个令人眼花fast乱的快速灵活的内核空间。 Ingo Molnar的HTTP服务器,用于Linux。Ingo在2000年9月1日的公告中 说,可以从ftp://ftp.redhat.com/pub/redhat/tux下载TUX的Alpha版本 ,并说明了如何加入邮件列表以获取更多信息。
linux-kernel列表一直在讨论这种方法的优缺点,并且共识似乎不是将Web服务器移入内核,而是应在内核中添加尽可能小的钩子以提高Web服务器性能。这样,其他类型的服务器都可以受益。参见例如 Zach Brown 关于userland vs.kernel http服务器的评论。似乎2.4 linux内核为用户程序提供了足够的功能,因为X15服务器的运行速度与Tux差不多,但是没有使用任何内核修改。

将TCP堆栈放入用户空间

例如,参见 netmap数据包I / O框架,以及基于该框架的 Sandstorm 概念验证Web服务器。

注释

理查德·古奇(Richard Gooch)撰写 了一篇讨论I / O选项的论文。

在2001年,Tim Brecht和MMichal Ostrowski 测量了 基于简单选择服务器的各种策略。他们的数据值得一看。

在2003年,Tim Brecht发布 了userver的源代码,这是一个小型Web服务器,由Abhishek Chandra,David Mosberger,David Pariag和Michal Ostrowski编写的多台服务器组成。它可以使用select(),poll(),epoll()或sigio。

早在1999年3月, Dean Gaudet发表了:

我不断被问到“你们为什么不使用像宙斯这样的基于选择/事件的模型?这显然是最快的。” ...

他的原因归结为“这真的很难,而且回报还不清楚”。然而,在短短几个月内,人们显然愿意为此付出努力。

标记Russinovich写了 一篇社论和 文章 讨论在2.2 Linux内核I / O战略的问题。值得一读,即使他似乎在某些方面也有误会。特别是,他似乎认为Linux 2.2的异步I / O(请参见上面的F_SETSIG)不会在数据准备就绪时通知用户进程,而只是在新连接到达时通知用户进程。这似乎是一种奇怪的误解。另请参见 上较早草案的意见, 30英格·蒙内的反驳1999年4月, 2 Russinovich的意见1999年5月, 一个反驳的阿伦·考克斯,以及各种 岗位到Linux内核。我怀疑他是想说Linux不支持异步磁盘I / O,这曾经是真的,但是现在SGI已经实现了KAIO,现在不再是真的了。

有关“完成端口”的信息,请参见sysinternals.com和 MSDN上的这些页面。简而言之,win32的“重叠I / O”级别太低,以至于不方便使用;“完成端口”是提供完成事件队列的包装器,此外还提供调度魔术,该魔术试图保持运行次数如果已经从该端口拾取完成事件的其他线程正在休眠(也许正在阻塞I / O),则允许更多线程拾取完成事件来使线程保持恒定。

另请参阅OS / 400对I / O完成端口的支持。

还有在1999年9月在题为Linux内核一个有趣的讨论“ > 15,000u同时连接 ”(和第二周的线程)。强调:

  • 埃德·霍尔(Ed Hall) 就他的经历发表了一些笔记;他在运行Solaris的UP P2 / 333上实现了每秒1000次以上的连接。他的代码使用了一个小的线程池(每个CPU 1或2个线程),每个线程都使用“基于事件的模型”管理大量的客户端。
  • Mike Jagdis 发表了对轮询/选择开销的分析,并说:“当前的选择/轮询实现可以显着改善,尤其是在阻塞情况下,但是开销会随着描述符数量的增加而增加,因为选择/轮询不会,并且不能,记住哪些描述符很有趣。使用新的API可以轻松解决。欢迎提出建议...”
  • 迈克(Mike)发表了他在改进select()和poll()方面的工作。
  • Mike 发表了一些关于可能使用的API来代替poll()/ select()的内容:“在编写“ pollfd like”结构的“ device like” API怎么样,“ device”侦听事件并传递“ pollfd like”结构在阅读时代表他们吗?...“
  • Rogier Wolff 建议 使用“数字专家建议的API”, http://www.cs.rice.edu/~gaurav/papers/usenix99.ps
  • Joerg Pommnitz 指出,遵循这些思路的任何新API不仅应等待文件描述符事件,而且还应等待信号以及SYSV-IPC。我们的同步原语当然应该至少能够完成Win32的WaitForMultipleObjects所能做的事情。
  • Stephen Tweedie 断言,F_SETSIG,排队的实时信号和sigwaitinfo()的组合是http://www.cs.rice.edu/~gaurav/papers/usenix99.ps中提出的API的超集。他还提到,如果您对性能感兴趣,可以始终保持信号阻塞。而不是异步传递信号,该过程使用sigwaitinfo()从队列中获取下一个信号。
  • Jayson Nordwick 将 完成端口与F_SETSIG同步事件模型进行了比较,得出的结论非常相似。
  • 艾伦·考克斯( Alan Cox)指出,2.3.18ac中包含了SCT SIGIO补丁的较旧版本。
  • Jordan Mendelson 发布了一些示例代码,展示了如何使用F_SETSIG。
  • Stephen C. Tweedie 继续对完成端口和F_SETSIG进行比较,并指出:“通过信号出队机制,如果库使用相同的机制,则您的应用程序将获得发往各个库组件的信号,”但该库可以设置它自己的信号处理程序,因此这不会影响程序。
  • Doug Royer 指出,他在Sun日历服务器上工作时,在Solaris 2.6上已获得100,000个连接。其他人则对Linux上需要多少RAM以及将遇到哪些瓶颈进行了估算。

有趣的阅​​读!

限制打开的文件句柄

  • 任何Unix:由ulimit或setrlimit设置的限制。
  • Solaris:请参阅Solaris FAQ,问题3.46(或其有关;它们会定期对问题重新编号)。
  • FreeBSD:

    编辑/boot/loader.conf,添加以下行

    set kern.maxfiles=XXXX

    其中XXXX是所需的文件描述符系统限制,然后重新启动。感谢一位匿名读者,他写信说他已经在FreeBSD 4.3上实现了10000多个连接,并说

    “ FWIW:您实际上无法通过sysctl来微调FreeBSD中的最大连接数。您必须在/boot/loader.conf文件中
    进行此操作。 其原因是zalloci()调用用于初始化套接字和tcpcb结构的区域很早就在系统启动时发生,以使该区域既是类型稳定的又是可交换的。
    您还需要将mbufs的数量设置得更高,因为(在未修改的情况下)内核)为tcptempl结构的每个连接消耗一个mbuf,用于实现keepalive。”

    另一位读者说

    “从FreeBSD 4.4开始,不再分配tcptempl结构;您不必担心每个连接都会占用一个mbuf。”

    也可以看看:

    • FreeBSD手册
    • 在“ 手动调试”中进行 SYSCTL TUNING, LOADER TUNABLES和 内核配置TUNING
    • 调整FreeBSD 4.3高性能盒的效果,Daemon News,2001年8月
    • postfix.org调整说明,涵盖FreeBSD 4.2和4.4
    • 测量工厂的注释,大约是FreeBSD 4.3
  • OpenBSD:读者说

    “在OpenBSD中,需要进行额外的调整以增加每个进程可用的打开文件句柄的数量:/etc/login.conf中的openfiles-cur参数 需要增加。您可以使用sysctl -w或in更改kern.maxfiles。 sysctl.conf,但没有任何作用。这很重要,因为在出​​厂时,login.conf限制对于非特权进程来说是64的极低,对于特权特权是128。

  • Linux:请参阅Bodo Bauer的/ proc文档。在2.4内核上:
    echo 32768 > /proc/sys/fs/file-max

    增加打开文件的系统限制,并且

    ulimit -n 32768

    增加当前过程的限制。

    在2.2.x内核上,

    echo 32768 > /proc/sys/fs/file-max
    echo 65536 > /proc/sys/fs/inode-max

    增加打开文件的系统限制,并且

    ulimit -n 32768

    增加当前过程的限制。

    我验证了Red Hat 6.0(2.2.5左右,加上补丁)上的进程可以以此方式打开至少31000个文件描述符。另一位同仁已验证2.2.12上的进程可以这种方式(具有适当的限制)打开至少90000个文件描述符。上限似乎是可用内存。
    Stephen C. Tweedie 发布了 有关如何在启动时使用initscript和pam_limit全局或每用户设置ulimit限制的信息。
    但是,在较早的2.2内核中,即使进行了上述更改,每个进程的打开文件数仍限制为1024。
    另请参见 Oskar的1998年文章,该文章讨论了2.0.36内核中文件描述符在每个进程和整个系统范围内的限制。

线程限制

在任何体系结构上,您可能需要减少为每个线程分配的堆栈空间量,以避免虚拟内存用完。如果使用pthread,则可以在运行时使用pthread_attr_init()进行设置。

  • Solaris:我听说它支持的内存数量尽可能多。
  • 带有NPTL:/ proc / sys / vm / max_map_count的Linux 2.6内核可能需要增加到32000左右的线程以上。(不过,除非您使用的是64位处理器,否则您将需要使用非常小的堆栈线程来获得接近该数量的线程。)请参阅NPTL邮件列表,例如主题为“ 不能创建超过32K的线程” 线程? ”,以获取更多信息。
  • Linux 2.4:/ proc / sys / kernel / threads-max是最大线程数;在我的Red Hat 8系统上默认为2047。您可以像往常一样通过将新值回显到该文件中来设置增加此值,例如“ echo 4000> / proc / sys / kernel / threads-max”
  • Linux 2.2:至少在Intel上,甚至2.2.13内核也限制了线程数。我不知道其他架构的局限性。 Mingo在Intel上发布了2.1.131的补丁程序,删除了此限制。它似乎已集成到2.3.20中。

    另请参见Volano有关在2.2内核中提高文件,线程和FD_SET限制的详细说明。哇。本文档为您介绍了很多东西,这些东西很难弄清楚自己,但是有些过时了。

  • Java:请参阅Volano的详细基准测试信息,以及有关如何调整各种系统 以处理大量线程的信息。

Java问题

在JDK 1.3之前,Java的标准网络库主要提供了“ 每个客户端一个线程”模型。有一种方法可以进行非阻塞读取,但是没有方法可以进行非阻塞写入。

2001年5月,JDK 1.4引入了程序包java.nio, 以提供对非阻塞I / O(以及其他一些功能)的完全支持。有关某些警告,请参见发行说明。试试看,并给Sun反馈!

惠普的Java还包括一个线程轮询API。

2000年,Matt Welsh为Java实现了非阻塞套接字。他的性能基准表明,与阻塞处理许多(最多10000个)连接的服务器中的套接字相比,它们具有优势。他的课程库称为 java-nbio;这是Sandstorm项目的一部分 。可以使用显示10000个连接的性能的基准 。

另请参见 Dean Gaudet 关于Java,网络I / O和线程的文章,以及 Matt Welsh关于事件与工作线程的论文。

在NIO之前,有一些改进Java网络API的建议:

  • Matt Welsh的 Jaguar系统 提出了预序列化的对象,新的Java字节码和内存管理更改,以允许在Java中使用异步I / O。
  • CC 将Java与虚拟接口体系结构接口。Chang和T. von Eicken提出了内存管理更改,以允许在Java中使用异步I / O。
  • JSR-51 是随java.nio软件包提供的Sun项目。Matt Welsh参加了(谁说Sun不听?)。

其他技巧

  • 零复制
    正常情况下,数据从这里到那里会被多次复制。将这些副本消除到最低限度的物理方案称为“零副本”。

    • Thomas Ogrisegg在Linux 2.4.17-2.4.20下针对mmaped文件的零拷贝发送补丁。声称它比sendfile()更快。
    • IO-Lite 是针对一组I / O原语的建议,它消除了对许多副本的需求。
    • 艾伦·考克斯(Alan Cox)指出,零拷贝有时不值得在1999年解决。(尽管他确实喜欢sendfile()。)
    • Ingo 于2000年7月在TUX 1.0的2.4内核中实现了一种零拷贝TCP形式,并表示他很快将其提供给用户空间。
    • Drew Gallatin和Robert Picco在FreeBSD中增加了一些零拷贝功能。这个想法似乎是,如果您在套接字上调用write()或read(),则指针是页面对齐的,并且传输的数据量至少是一页,并且*并且*您不会立即重用缓冲区,将使用内存管理技巧来避免复制。但是请在linux内核上查看 此消息的后续内容,以 使人们对这些内存管理技巧的速度感到担忧。

      根据苏打则之记:

      自NetBSD-1.6发行以来,通过指定内核选项“ SOSEND_LOAN”,支持发送方零复制。现在,此选项是NetBSD-current上的默认选项(您可以通过在NetBSD_current的内核选项中指定“ SOSEND_NO_LOAN”来禁用此功能)。使用此功能,如果将大于4096字节的数据指定为要发送的数据,则会自动启用零复制。

    • sendfile()系统调用可以实现零复制网络。
      Linux和FreeBSD中的sendfile()函数使您可以告诉内核发送部分或全部文件。这使OS可以尽可能高效地执行操作。它可以在使用线程的服务器或使用非阻塞I / O的服务器中同样出色地使用。(在Linux中,它是目前不良记录; 使用_syscall4叫它安迪Kleen的是写作,涵盖这一新手册页见也。探索的sendfile系统调用由杰夫·特兰特在Linux公报发布91) 有传言说,FTP .cdrom.com从sendfile()中明显受益。

      对于2.4内核,sendfile()的零复制实现正在进行中。参见LWN 2001年1月25日。

      一位将sendfile()与Freebsd一起使用的开发人员报告说,使用POLLWRBAND而不是POLLOUT会有很大的不同。

      Solaris 8(从2001年7月开始更新)具有一个新的系统调用“ sendfilev”。 手册页的副本在这里。。Solaris 8 7/01 发行说明 也提到了它。我怀疑这在以阻塞模式发送到套接字时最有用。与无阻塞套接字一起使用会有些痛苦。

  • 通过使用writev(或TCP_CORK)避免小帧
    Linux下的一个新套接字选项TCP_CORK告诉内核避免发送部分帧,这会有所帮助,例如,当有很多小的write()调用无法捆绑在一起时某些原因。取消设置该选项将刷新缓冲区。不过,最好使用writev()...

    有关在Linux内核上有关TCP_CORK和可能的替代MSG_MORE的一些非常有趣的讨论的摘要,请参见LWN 2001年1月25日。

  • 明智地处理过载。
    [ Provos,Lever和Tweedie 2000 ]指出,当服务器过载时,断开传入连接可以改善性能曲线的形状,并降低总体错误率。他们使用了平滑版本的“准备好I / O的客户端数量”来衡量过载。该技术应该很容易适用于使用select,poll或任何每次调用返回准备事件计数的系统调用编写的服务器(例如/ dev / poll或sigtimedwait4())。
  • 某些程序可以从使用非Posix线程中受益。
    并非所有线程都是平等的。例如,Linux(及其在其他操作系统中的朋友)中的clone()函数可让您创建一个具有其自己当前工作目录的线程,这对于实现ftp服务器非常有帮助。有关使用本机线程而不是pthread的示例,请参见Hoser FTPd。
  • 缓存自己的数据有时可能是一个胜利。
    Vivek Sadananda Pai(vivek@cs.rice.edu)在5月9日在new-httpd上发表的“ Re:解决混合服务器问题” 指出:

    “在FreeBSD和Solaris / x86上,我已将基于选择的服务器与多进程服务器的原始性能进行了比较。在微基准测试中,由于软件体系结构而导致的性能差异很小。基于服务器的服务器源于应用程序级缓存,虽然多进程服务器可以以更高的成本实现它,但要在实际工作负载上获得相同的收益(相对于微基准测试)则更加困难。那会出现在下次的Usenix会议论文。如果你有跋,该文件可在 http://www.cs.rice.edu/~vivek/flash99/ “

其他限制

  • 旧的系统库可能使用16位变量来保存文件句柄,这会在32767句柄以上引起麻烦。glibc2.1应该可以。
  • 许多系统使用16位变量来保存进程或线程ID。将Volano可伸缩性基准移植到C,看看各种操作系统的线程数上限是多少会很有趣。
  • 某些操作系统预分配了过多的线程本地内存。如果每个线程获得1MB,并且虚拟机总空间为2GB,则将创建2000个线程的上限。
  • 查看http://www.acme.com/software/thttpd/benchmarks.html底部的性能比较图 。请注意,即使在Solaris 2.6上,各种服务器在128个以上的连接上也有问题吗?知道原因的人,请告诉我。
    注意:如果TCP堆栈有一个导致在SYN或FIN时短暂(200ms)延迟的错误(如Linux 2.2.0-2.2.6那样),并且OS或http守护程序对打开的连接数有硬限制,您完全可以期待这种行为。可能还有其他原因。

内核问题

对于Linux,内核瓶颈似乎一直在被修复。请参阅《Linux周报》,《 内核流量》, 《 Linux-内核邮件列表》和我的《 Mindcraft Redux》页面。

1999年3月,Microsoft发起了一个基准测试,将NT与Linux进行比较,以服务大量的http和smb客户端,但他们没有看到Linux的良好结果。另请参阅我在Mindcraft的1999年4月基准测试中的文章 。

另请参见Linux可伸缩性项目。他们正在做有趣的工作,包括 Niels Provos的提示民意测验,以及一些关于雷声群问题的工作。

另请参见Mike Jagdis关于改进select()和poll()的工作;这是Mike的相关文章。

Mohit Aron(aron@cs.rice.edu)写道,TCP中基于速率的时钟可以将“慢速”连接上的HTTP响应时间缩短80%。

评估服务器性能

特别是以下两个测试是简单,有趣和困难的:

  1. 每秒原始连接数(每秒可以服务多少个512字节文件?)
  2. 具有许多慢速客户端的大文件的总传输率(在性能达到预期之前可以从服务器同时下载多少28.8k调制解调器客户端?)

Jef Poskanzer发布了比较许多Web服务器的基准测试。有关 其结果,请参见http://www.acme.com/software/thttpd/benchmarks.html。

我也有 一些关于将thttpd与Apache进行比较的旧笔记,这可能是初学者感兴趣的。

Chuck Lever不断提醒我们有关 Banga和Druschel关于Web服务器基准测试的论文。值得一读。

IBM有一篇出色的论文,标题为《Java服务器基准测试》 [Baylor等,2000]。值得一读。

例子

Nginx是一个Web服务器,它使用目标OS上可用的任何高效网络事件机制。它越来越流行;甚至还有 关于它的书籍(由于此页面最初是撰写的,因此还有更多,包括该书的第四版。)

有趣的基于select()的服务器

  • thttpd 非常简单。使用单个过程。它具有良好的性能,但不能随CPU的数量扩展。也可以使用kqueue。
  • Mathopd。类似于thttpd。
  • fhttpd
  • boa
  • Roxen
  • 宙斯(Zeus),试图成为绝对最快的商业服务器。请参阅他们的调优指南。
  • 在http://www.acme.com/software/thttpd/benchmarks.html列出的其他非Java服务器
  • BetaFTPd
  • Flash-Lite-使用IO-Lite的Web服务器。
  • Flash:高效且可移植的Web服务器 -使用select(),mmap(),mincore()
  • 从2003年开始的Flash Web服务器 -使用select(),修改过的sendfile()和async open()
  • xitami-使用select()实现自己的线程抽象,以将其移植到没有线程的系统。
  • Medusa-用Python编写的服务器编写工具包,旨在提供非常高的性能。
  • userver-小型HTTP服务器,可以使用select,poll,epoll或sigio

有趣的基于/ dev / poll的服务器

  • N. Provos,C.杠杆, “可扩展的网络I / O在Linux中,” 月,2000。[FREENIX轨道,PROC。USENIX 2000,加利福尼亚州,圣地亚哥(2000年6月)。]描述了修改为支持/ dev / poll的thttpd版本。性能与phhttpd进行了比较。

有趣的基于epoll的服务器

  • ribs2
  • cmogstored-将epoll / kqueue用于大多数联网,将线程用于磁盘并接受4

有趣的基于kqueue()的服务器

  • thttpd(从2.21版开始?)
  • 阿德里安·查德(Adrian Chadd)说:“我正在做很多工作,以使鱿鱼实际上像kqueue IO系统一样。” 这是一个正式的鱿鱼子项目;请参阅 http://squid.sourceforge.net/projects.html#commloops。(这显然比Benno的 补丁更新。)

有趣的基于实时信号的服务器

  • 铬的 X15。它使用2.4内核的SIGIO功能以及sendfile()和TCP_CORK,据报道甚至达到了比TUX更高的速度。该源可根据社区源(非开源)许可证获得。请参阅 Fabio Riccardi 的原始公告。
  • Zach Brown的 phhttpd- “被编写来展示sigio / siginfo事件模型的快速Web服务器。如果您在生产环境中尝试使用此代码,则应将其视为高度实验性的代码,并高度自觉。” 使用2.3.21或更高版本的siginfo功能,并包括早期内核所需的补丁程序。据说比khttpd还要快。请参阅他在1999年5月31日的帖子中 的一些注释。

有趣的基于线程的服务器

  • Hoser FTPD。请参阅其基准页面。
  • 彼得·埃里克森(Peter Eriksson)的phttpd和
  • ftp文件
  • http://www.acme.com/software/thttpd/benchmarks.html上列出的基于Java的服务器
  • Sun的Java Web Server ( 据报道可处理500个并发客户端)

有趣的内核服务器

  • khttpd
  • Ingo Molnar等人的“ TUX”(线程化linUX Web服务器)。对于2.4内核。

其他有趣的链接

  • Jeff Darcy关于高性能服务器设计的说明
  • 爱立信的ARIES项目 -在1至12个处理器上针对Apache 1 vs. Apache 2 vs. Tomcat的基准测试结果
  • Peter Ladkin教授的“ Web服务器性能”页面。
  • Novell的FastCache-声称每秒10000次命中。相当不错的性能图。
  • Rik van Riel的Linux Performance Tuning网站

C10K问题:是时候让Web服务器同时处理一万个客户端了相关推荐

  1. 微点注册web服务器没反应,微点主动防御网络版客户端Web设置教程.doc

    文档介绍: IIS安装方式如果贵单位已经拥有Web服务器,请将该文件夹中的文件复制到IIS指定的Web网站里即可,并将安装光盘中的客户端文件改名为mpavsetup.exe复制到该目录,用户直接通过访 ...

  2. 静态Web服务器-多任务版

    1. 静态Web服务器的问题 目前的Web服务器,不能支持多用户同时访问,只能一个一个的处理客户端的请求,那么如何开发多任务版的web服务器同时处理 多个客户端的请求? 可以使用多线程,比进程更加节省 ...

  3. nodejs没有net模块_Node.js实战16:用http模块创建web服务器

    Nodejs的http模块,是基于net.server,经过c++二次封装,也是nodejs的核心模块. 功能比net.server更强,可解析和操作更多细节内容,如值.content-length. ...

  4. Mongoose源码剖析:外篇之web服务器

    引言 在深入Mongoose源码剖析之前,我们应该清楚web服务器是什么?它提供什么服务?怎样提供服务?使用什么协议?客户端如何唯一标识web服务器的资源?下面我们抛开Mongoose,来介绍一个we ...

  5. HTTP权威指南记录 ---- Web服务器

    Web服务器 Web服务器的实现 Web服务器会对HTTP请求进行处理并提供响应.术语"Web服务器"可以用来表示Web服务器的软件,也可以用来表示提供Web页面的特定设备或计算机 ...

  6. ENSP如何开启服务器的http_如何使用HTTP模块在Node.js中创建Web服务器(上)

    当你在浏览器中查看网页时,其实是在向互联网上的另一台计算机发出请求,然后它会将网页提供给你作为响应.你通过互联网与之交谈的那台计算机就是Web服务器,Web服务器从客户端(例如你的浏览器)接收HTTP ...

  7. boa服务器如何运行cgi,嵌入式WEB服务器BOA+CGI.ppt

    嵌入式WEB服务器BOACGI 嵌入式WEB服务器:BOA+CGI 报 告 人: 李 实 * ASIPP 随着Internet技术的兴起,在嵌入式设备的管理与交互中,基于Web方式的应用成为目前的主流 ...

  8. Mr.J-- HTTP学习笔记(五)-- Web服务器

    Web 服务器实现了 HTTP 和相关的 TCP 连接处理. 负责管理 Web 服务器提供的资源, 以及对 Web 服务器的配置. 控制及扩展方面的管理. 我的专栏:  HTTP学习笔记 Web服务器 ...

  9. 服务器根没有web文件系统,Web服务器

    Web服务器会做些什么 (1) 建立连接--接受一个客户端连接,或者如果不希望与这个客户端建立连接,就将其关闭. (2) 接收请求--从网络中读取一条HTTP 请求报文. (3) 处理请求--对请求报 ...

最新文章

  1. mysql本地服务器密码,mysql如何修改密码
  2. edx错误的地方开始安装
  3. 彻底理解 Redis 的持久化和主从复制
  4. 名词解释CPC、CPM、CPA.......[来源于网络]
  5. 实验任务四:登录界面、实验任务五:猜数字
  6. python 排名函数_一个危险的Python函数,不推荐使用
  7. 快速创建springBoot
  8. python中将已有链接的视频进行下载
  9. PHP面试题:对于大流量的网站,您采用什么样的方法来解决访问量问题?
  10. springboot util 测试类怎么写_SpringBoot入门建站全系列(九)文件上传功能与下载方式...
  11. Android入门逆引手册 - 12 评分条(RatingBar)的使用
  12. LeetCode 1062. 最长重复子串(二分查找)
  13. 取文件 shell_webshell文件上传分析溯源
  14. [Perl系列—] 1. 清空目录及目录中的所有文件
  15. yii 使用 有赞sdk_有赞 App 动态化配置中心实践
  16. Python出租车GPS数据处理(TransBigData)
  17. plot函数linewidth区别
  18. 软件安全性与软件可靠性
  19. 微软云+Servlet实现图片上传接口
  20. OS实验-模拟实现首次/最佳/最坏适应算法的内存块分配和回收

热门文章

  1. 使用WMI来得到系统的服务
  2. webshell及工具
  3. 1024程序员节福利第一波
  4. C++ 工程调用Intel IPPS库
  5. 【FPGA】: ip核——Fir滤波器
  6. 将 Google 登录集成到您的 Android 应用中
  7. 【芯片方案】红外人体测温仪方案设计
  8. 在Hbase使用过滤器(行键过滤器、列族与列过滤器、值过滤器)
  9. 如何拍背景虚化的照片_拍摄人像背景虚化的照片怎么拍?
  10. 字节 位 字符 宽字符