<-
Apache HTTP 服务器 2.4 > 性能调优

Apache性能调优

Apache 2.x是一种通用的Web服务器,旨在在灵活性,可移植性和性能之间取得平衡。尽管不是专门为设置基准记录而设计的,但Apache 2.x能够在许多实际情况下实现高性能。

与Apache 1.3相比,版本2.x包含许多其他优化功能,以提高吞吐量和可伸缩性。默认情况下,其中大多数改进都是启用的。但是,有一些编译时和运行时配置选择会严重影响性能。本文档描述了服务器管理员可以配置的选项,以调整Apache 2.x安装的性能。这些配置选项中的一些使httpd可以更好地利用硬件和OS的功能,而其他一些则允许管理员以速度为代价来交换功能。

支持Apache!

也可以看看

最佳

硬件和操作系统问题

影响Web服务器性能的最大硬件问题是RAM。Web服务器永远都不必交换,因为交换会增加每个请求的延迟,使之超过用户认为“足够快”的程度。这会导致用户点击停止并重新加载,从而进一步增加了负载。您可以并且应该控制该MaxRequestWorkers设置,以使服务器不会产生太多子代以至于无法开始交换。这样做的过程很简单:通过使用诸如之类的工具查看进程列表,确定平均Apache进程的大小 top,然后将其划分为总可用内存,为其他进程留出一些空间。

除此之外,其他一切都很普通:获得足够快的CPU,足够快的网卡和足够快的磁盘,其中“足够快”是需要通过实验确定的东西。

操作系统的选择很大程度上取决于本地情况。但是一些已被证明通常有用的准则是:

最佳

运行时配置问题

主机名查找和其他DNS注意事项

在Apache 1.3之前,HostnameLookups默认为On。这会增加每个请求的等待时间,因为它需要在请求完成之前完成DNS查找。在Apache 1.3中,此设置默认为Off。如果您需要将日志文件中的地址解析为主机名,请使用logresolve Apache随附的 程序或可用的众多日志报告软件包之一。

建议您在生产Web服务器计算机以外的其他计算机上对日志文件进行这种后处理,以免此活动对服务器性能产生不利影响。

如果您使用任何Allow from domainDeny from domain 指令(即​​,使用主机名或域名,而不是IP地址),则需要支付两次DNS查找费用(反向查询,然后进行正向查询,以确保不进行反向查询)欺骗)。因此,为了获得最佳性能,请尽可能在使用这些指令时使用IP地址而不是名称。

请注意,可以对指令进行范围调整,例如在一个<Location "/server-status">节内。在这种情况下,仅对符合条件的请求执行DNS查找。这是一个禁用查找的示例,除了.html.cgi文件:

HostnameLookups off
<Files ~ "\.(html|cgi)$">
  HostnameLookups on
</Files>

但即使如此,如果您仅在某些CGI中需要DNS名称,则可以考虑在gethostbyname需要它的特定CGI中进行调用。

关注SymLinks和SymLinksIfOwnerMatch

无论您在URL空间中的哪个位置没有Options FollowSymLinksOptions SymLinksIfOwnerMatch,Apache都需要发出额外的系统调用来检查符号链接。(每个文件名组件一个额外的调用。)例如,如果您有:

DocumentRoot "/www/htdocs"
<Directory "/">
  Options SymLinksIfOwnerMatch
</Directory>

和请求针对URI制成/index.html,然后Apache将执行lstat(2)/www/www/htdocs/www/htdocs/index.html。这些结果 lstats永远不会被缓存,因此它们将在每个单个请求中出现。如果您确实需要符号链接安全检查,则可以执行以下操作:

DocumentRoot "/www/htdocs"
<Directory "/">
  Options FollowSymLinks
</Directory>

<Directory "/www/htdocs">
  Options -FollowSymLinks +SymLinksIfOwnerMatch
</Directory>

这至少避免了对DocumentRoot路径的额外检查 。请注意,您需要添加类似的部分,如果您有任何AliasRewriteRule路径,您的文档根目录之外。为了获得最高性能,并且没有符号链接保护,请在FollowSymLinks 各处设置,并且永远不要设置SymLinksIfOwnerMatch

AllowOverride

无论您在URL空间中的何处允许覆盖(通常是 .htaccess文件),Apache都会尝试.htaccess为每个文件名组件打开 。例如,

DocumentRoot "/www/htdocs"
<Directory "/">
  AllowOverride all
</Directory>

并请求URI /index.html。然后Apache会试图打开/.htaccess/www/.htaccess/www/htdocs/.htaccess。解决方案与的先前情况类似Options FollowSymLinks。为了获得最佳性能AllowOverride None ,请在文件系统中的任何地方使用。

谈判

如果您确实对每一盎司的性能都非常感兴趣,请尽可能避免进行内容协商。在实践中,谈判的好处胜于性能损失。在一种情况下,您可以加快服务器速度。而不是使用通配符,例如:

DirectoryIndex index

使用完整的选项列表:

DirectoryIndex index.cgi index.pl index.shtml index.html

首先列出最常见的选择。

还要注意,显式创建type-map 文件比使用来提供更好的性能 MultiViews,因为可以通过读取单个文件来确定必要的信息,而不必扫描目录中的文件。

如果您的站点需要进行内容协商,请考虑使用 type-map文件而非Options MultiViews指令来完成协商。有关协商 方法的完整讨论和创建type-map文件的说明,请参阅 内容协商文档。

内存映射

在Apache 2.x需要查看所传递文件的内容的情况下(例如,在进行服务器端包含处理时),如果操作系统支持某种形式的,通常它会对该文件进行内存映射mmap(2)

在某些平台上,此内存映射可提高性能。但是,在某些情况下,内存映射可能会损害httpd的性能甚至稳定性:

对于其中两个因素都适用的安装,您应使用EnableMMAP off以禁用已交付文件的内存映射。(注意:可以根据每个目录覆盖此指令。)

发送文件

在Apache 2.x可以忽略要传递的文件内容的情况下(例如,在提供静态文件内容时),如果操作系统支持该sendfile(2)操作,则通常使用内核sendfile支持文件。

在大多数平台上,使用sendfile通过消除单独的读取和发送机制来提高性能。但是,在某些情况下,使用sendfile可能会损害httpd的稳定性:

对于其中两个因素均适用的安装,应使用EnableSendfile off禁用文件内容的sendfile传递。(注意:可以根据每个目录覆盖此指令。)

流程创建

对于Apache 1.3 MinSpareServersMaxSpareServersStartServers设置都对测试结果巨大的影响。特别是,Apache需要一个“加速”期才能达到足以满足所施加负载的子级数。最初生成 StartServers子代后,每秒只能创建一个子代来满足 MinSpareServers 设置。因此,由100个并发客户端访问的服务器(使用默认值StartServers5将花费95秒左右的时间来产生足够的子代来处理负载。实际上,这在现实生活中的服务器上效果很好,因为它们不经常重启。但是,在只能运行十分钟的基准测试上,它的性能确实很差。

实施每秒一秒的规则是为了避免随着新子代的启动而淹没机器。如果机器忙于产生子代,则无法处理请求。但是它对Apache的感知性能产生了巨大的影响,因此必须将其替换。从Apache 1.3开始,代码将放宽每秒规则。它会先生成一个,然后等待一秒钟,然后再生成两个,然后等待一秒钟,再生成四个,然后它会以指数方式继续运行,直到每秒每秒生成32个孩子。只要满足MinSpareServers 设置,它就会停止 。

这似乎足够灵敏,几乎不需要旋转MinSpareServersMaxSpareServersStartServers旋钮。每秒产生4个以上的子代时,将向发出一条消息 ErrorLog。如果您看到很多此类错误,请考虑调整这些设置。使用mod_status输出作为指导。

与流程创建相关的是由MaxConnectionsPerChild 设置引起的流程死亡 。默认情况下为0,这意味着每个孩子处理的连接数没有限制。如果您的配置当前将此值设置为一个很小的数字,例如30,您可能希望将其设置得较大。如果运行的是SunOS或Solaris的旧版本,则10000由于内存泄漏而将其限制为大约。

使用保持活动状态时,孩子将一直忙于不做任何事情,等待已打开的连接上的更多请求。默认KeepAliveTimeout5 秒数尝试最小化此影响。这里的权衡是在网络带宽和服务器资源之间。在任何情况下,您都不应将其提高到60几秒钟以上,因为 大多数收益都会丢失

最佳

编译时配置问题

选择一个MPM

Apache 2.x支持可插拔并发模型,称为 多处理模块(MPM)。构建Apache时,必须选择要使用的MPM。对于某些平台mpm_netware, 有针对特定平台的MPM : mpmt_os2、和mpm_winnt。对于一般的Unix类型的系统,有几种MPM可供选择。MPM的选择会影响httpd的速度和可伸缩性:

有关这些和其他MPM的更多信息,请参阅MPM 文档

模组

由于内存使用是性能中的重要考虑因素,因此您应该尝试消除实际上不使用的模块。如果已将模块构建为DSO,则消除模块是注释掉LoadModule该模块的关联指令的简单问题。这使您可以尝试删除模块并查看您的站点在缺少模块的情况下是否仍能正常运行。

另一方面,如果您有静态链接到Apache二进制文件中的模块,则需要重新编译Apache才能删除不需要的模块。

当然,这里出现的一个相关问题是,您需要哪些模块,不需要哪些模块。当然,这里的答案会因一个网站而异。然而, 最小的模块,你可以用得到的名单往往包括mod_mimemod_dir,和mod_log_configmod_log_config当然是可选的,因为您可以运行没有日志文件的网站。但是,不建议这样做。

原子操作

一些模块(例如mod_cache工作程序MPM的最新开发版本)使用APR的原子API。该API提供了可用于轻量级线程同步的原子操作。

默认情况下,APR使用每个目标OS / CPU平台上可用的最有效机制来实现这些操作。例如,许多现代CPU都具有在硬件中执行原子比较和交换(CAS)操作的指令。但是,在某些平台上,APR默认使用原子API的基于互斥体的较慢实现,以确保与缺少此类指令的较旧CPU模型兼容。如果要为以下平台之一构建Apache,并且计划仅在较新的CPU上运行,则可以通过使用以下--enable-nonportable-atomics选项配置Apache,从而在构建时选择更快的原子实现:

./buildconf
./configure --with-mpm=worker --enable-nonportable-atomics=yes

--enable-nonportable-atomics选项与以下平台有关:

mod_status和ExtendedStatus On

如果您包括在内,mod_status并且还在ExtendedStatus On构建和运行Apache时进行了设置 ,则Apache将在每个请求上执行两次调用 gettimeofday(2)(或times(2) 取决于您的操作系统),以及对1.3进行多次额外的调用time(2)。这样做是为了使状态报告包含时序指示。为了获得最佳性能,请设置ExtendedStatus off(这是默认设置)。

接受序列化-多个套接字

警告:

考虑到在Apache HTTP Server 2.x版本中所做的更改,本部分尚未完全更新。一些信息可能仍然有用,但请谨慎使用。

这讨论了Unix套接字API中的一个缺点。假设您的Web服务器使用多个Listen语句来侦听多个端口或多个地址。为了测试每个套接字以查看连接是否就绪,Apache使用了 select(2)select(2)表示套接字上有零个至少一个连接正在等待。Apache的模型包含多个子级,所有空闲的子级同时测试新连接。一个简单的实现看起来像这样(这些示例与代码不匹配,它们被设计用于教学目的):

        for (;;) {
          for (;;) {
            fd_set accept_fds;

            FD_ZERO (&accept_fds);
            for (i = first_socket; i <= last_socket; ++i) {
              FD_SET (i, &accept_fds);
            }
            rc = select (last_socket+1, &accept_fds, NULL, NULL, NULL);
            if (rc < 1) continue;
            new_connection = -1;
            for (i = first_socket; i <= last_socket; ++i) {
              if (FD_ISSET (i, &accept_fds)) {
                new_connection = accept (i, NULL, NULL);
                if (new_connection != -1) break;
              }
            }
            if (new_connection != -1) break;
          }
          process_the(new_connection);
        }

但是,这种幼稚的实现存在严重的饥饿问题。回想一下,多个子代会同时执行此循环,因此,多个子代会在两次select请求之间处于阻塞 状态。select当任何请求出现在任何套接字上时,所有被阻止的子级都将唤醒并返回 。(唤醒的子代数取决于操作系统和时序问题。)然后,它们全都陷入循环并尝试accept建立连接。但是只有一个能够成功(假设仍然只有一个连接可用)。其余部分将被阻止accept。这有效地将那些子级锁定为能够从该一个套接字(而不是其他套接字)提供请求,并且它们将被卡在那里,直到该套接字上出现足够的新请求以将其唤醒为止。此饥饿问题最早在PR#467中记录。至少有两种解决方案。

一种解决方案是使套接字无阻塞。在这种情况下,accept不会阻止孩子,他们将被允许立即继续。但这浪费了CPU时间。假设您在中有十个闲置孩子 select,并且一个连接到达。然后,其中的9个孩子将醒来,尝试accept建立连接,失败,然后循环回去select,什么也做不了。同时,这些子级中的任何一个都不会为其他套接字上发生的请求提供服务,直到他们重新回到另一个套接字为止select。总体而言,除非您拥有(在多处理器设备中)闲置的CPU数量与孩子的闲置数量(不太可能的情况)一样,否则该解决方案似乎效果不佳。

Apache使用的另一种解决方案是将条目序列化到内部循环中。循环如下所示(差异突出显示):

        for (;;) {
          accept_mutex_on ();
          for (;;) {
            fd_set accept_fds;
            
            FD_ZERO (&accept_fds);
            for (i = first_socket; i <= last_socket; ++i) {
              FD_SET (i, &accept_fds);
            }
            rc = select (last_socket+1, &accept_fds, NULL, NULL, NULL);
            if (rc < 1) continue;
            new_connection = -1;
            for (i = first_socket; i <= last_socket; ++i) {
              if (FD_ISSET (i, &accept_fds)) {
                new_connection = accept (i, NULL, NULL);
                if (new_connection != -1) break;
              }
            }
            if (new_connection != -1) break;
          }
          accept_mutex_off ();
          process the new_connection;
        }

这些功能 accept_mutex_onaccept_mutex_off 实现了互斥信号灯。任何时候只有一个孩子可以使用该互斥锁。实现这些互斥有多种选择。该选择在 src/conf.h(1.3之前)或 src/include/ap_config.h(1.3或更高版本)中定义。一些体系结构没有做出任何锁定选择,在这些体系结构上使用多个Listen 指令是不安全的 。

Mutex指令可用于mpm-accept在运行时更改互斥量的互斥量实现 。该指令记录了不同互斥量实现的特殊注意事项。

已经考虑但从未实现的另一种解决方案是部分序列化循环-即,让一定数量的进程进入。这仅在多处理器盒上才有意义,因为多处理器盒可能同时运行多个子代,而序列化实际上并没有利用全部带宽。这是未来研究的可能领域,但是由于高度并行的Web服务器不是标准,因此优先级仍然很低。

理想情况下,Listen 如果要获得最高性能,则应在运行服务器时不使用多条 语句。但是请继续阅读。

接受序列化-单插槽

上面对于多个套接字服务器来说是不错的选择,但是对于单个套接字服务器呢?从理论上讲,他们不应该遇到任何这些相同的问题,因为所有孩子都可以阻塞,accept(2)直到建立连接为止,并且没有饥饿。在实践中,这几乎隐藏了非阻塞解决方案中上面讨论的“旋转”行为。在大多数TCP堆栈的实现方式中,内核实际上唤醒了所有被阻塞的进程accept当单个连接到达时。这些进程之一获取连接并返回到用户空间。其余的在内核中旋转并在他们发现没有连接时回到睡眠状态。这种旋转从用户区代码中隐藏了,但是仍然存在。这可能会导致与多套接字案例的非阻塞解决方案相同的负载高峰浪费行为。

由于这个原因,我们发现,即使序列化单个套接字的情况,许多体系结构的行为也“更漂亮”。因此,几乎在所有情况下,这实际上都是默认设置。在Linux上进行的粗略实验(双Pentium pro 166 w / 128Mb RAM上的2.0.30)表明,与未序列化的单插槽相比,单插槽的序列化导致每秒请求减少不到3%。但是未序列化的单路套接字在每个请求上显示了额外的100毫秒延迟。这种延迟可能是长途运输线路上的麻烦,而只是LAN上的一个问题。如果要覆盖单套接字序列化,则可以定义 SINGLE_LISTEN_UNSERIALIZED_ACCEPT,然后单套接字服务器将根本不会序列化。

徘徊关闭

如在 draft-ietf-http-connection-00.txt部分8中所讨论的,为了使HTTP服务器可靠地实现该协议,它需要独立关闭每个通信方向。(回想一下,TCP连接是双向的。每一半都彼此独立。)

当将此功能添加到Apache时,由于目光短浅,它在各种版本的Unix上引起了一系列问题。TCP规范没有声明该FIN_WAIT_2 状态有超时,但是没有禁止它。在没有超时的系统上,Apache 1.2会导致许多套接字永久停留在该FIN_WAIT_2状态。在许多情况下,可以通过简单地升级到供应商提供的最新TCP / IP修补程序来避免这种情况。在供应商从来没有发布补丁的情况下(,SunOS4 -虽然有源码许可人可以修补它自己),我们决定禁用此功能。

有两种方法可以完成此操作。一种是套接字选项SO_LINGER。但是,正如命运所愿,这在大多数TCP / IP堆栈中从未得到正确实现。即使在具有适当实现的堆栈( Linux 2.0.31)上,该方法(cputime)也比下一个解决方案更昂贵。

在大多数情况下,Apache通过一个名为lingering_close(in http_main.c)的函数来实现这一点。该函数大致如下所示:

        void lingering_close (int s)
        {
          char junk_buffer[2048];
          
          /* shutdown the sending side */
          shutdown (s, 1);

          signal (SIGALRM, lingering_death);
          alarm (30);

          for (;;) {
            select (s for reading, 2 second timeout);
            if (error) break;
            if (s is ready for reading) {
              if (read (s, junk_buffer, sizeof (junk_buffer)) <= 0) {
                break;
              }
              /* just toss away whatever is here */
            }
          }
          
          close (s);
        }

这自然会在连接结束时增加一些开销,但是这是可靠实现所必需的。随着HTTP / 1.1变得越来越普遍,并且所有连接都是持久的,这笔费用将在更多请求上摊销。如果您想玩火并禁用此功能,则可以定义 NO_LINGCLOSE,但是完全不建议这样做。特别是,随着HTTP / 1.1流水线持久连接的使用,这lingering_close是绝对必要的( 流水线连接速度更快,因此您要支持它们)。

记分板文件

Apache的父母和孩子通过称为记分板的方式相互交流。理想情况下,这应该在共享内存中实现。对于那些我们可以访问或已为其指定详细端口的操作系统,通常使用共享内存来实现。其余默认使用磁盘文件。磁盘上的文件不仅速度慢,而且不可靠(功能较少)。src/main/conf.h为您的体系结构仔细阅读 文件,然后查找USE_MMAP_SCOREBOARDUSE_SHMGET_SCOREBOARD。限定这两个中的一个(以及他们的同伴HAVE_MMAPHAVE_SHMGET分别)使提供的共享存储器中的代码。如果您的系统还有其他类型的共享内存,请编辑文件src/main/http_main.c并添加在Apache中使用它所需的钩子。(也请向我们发送补丁。)

历史记录:Apache的Linux端口直到Apache 1.2版才开始使用共享内存。这种疏忽导致Linux上早期版本的Apache的行为非常糟糕且不可靠。

DYNAMIC_MODULE_LIMIT

如果您不打算使用动态加载的模块(如果您正在阅读本文并针对每一个性能指标调整服务器,则可能不打算这样做),那么应该-DDYNAMIC_MODULE_LIMIT=0在构建服务器时添加 。这将节省仅用于支持动态加载模块的RAM。

最佳

附录:跟踪的详细分析

这是Solaris 8上具有工作程序MPM的Apache 2.0.38的系统调用跟踪。此跟踪是使用以下收集的:

truss -l -p httpd_child_pid.

-l选项告诉truss记录调用每个系统调用的LWP(轻量级进程-Solaris形式的内核级线程)的ID。

其他系统可能有不同的系统调用跟踪实用程序,如stracektracepar。它们都产生相似的输出。

在此跟踪中,客户端从httpd请求了10KB静态文件。非静态请求或具有内容协商的请求的痕迹看起来截然不同(在某些情况下非常难看)。

/67:    accept(3, 0x00200BEC, 0x00200C0C, 1) (sleeping...)
/67:    accept(3, 0x00200BEC, 0x00200C0C, 1)            = 9

在此跟踪中,侦听器线程在LWP#67中运行。

请注意缺少accept(2)序列化。在此特定平台上,工作程序MPM默认情况下使用未序列化的接受,除非它正在多个端口上侦听。
/65:    lwp_park(0x00000000, 0)                         = 0
/67:    lwp_unpark(65, 1)                               = 0

接受连接后,侦听器线程将唤醒工作线程以进行请求处理。在此跟踪中,将处理请求的工作线程映射到LWP#65。

/65:    getsockname(9, 0x00200BA4, 0x00200BC4, 1)       = 0

为了实现虚拟主机,Apache需要知道用于接受连接的本地套接字地址。在许多情况下(例如当没有虚拟主机或Listen使用没有通配符地址的指令时),可以消除此调用 。但是,尚未做出任何优化。

/65:    brk(0x002170E8)                                 = 0
/65:    brk(0x002190E8)                                 = 0

brk(2)呼叫从堆中分配内存。很少会在系统调用跟踪中看到这些内容,因为httpd 在大多数请求处理中都使用了自定义内存分配器(apr_poolapr_bucket_alloc)。在此跟踪中,httpd刚刚启动,因此必须调用malloc(3)以获取用于创建自定义内存分配器的原始内存块。

/65:    fcntl(9, F_GETFL, 0x00000000)                   = 2
/65:    fstat64(9, 0xFAF7B818)                          = 0
/65:    getsockopt(9, 65535, 8192, 0xFAF7B918, 0xFAF7B910, 2190656) = 0
/65:    fstat64(9, 0xFAF7B818)                          = 0
/65:    getsockopt(9, 65535, 8192, 0xFAF7B918, 0xFAF7B914, 2190656) = 0
/65:    setsockopt(9, 65535, 8192, 0xFAF7B918, 4, 2190656) = 0
/65:    fcntl(9, F_SETFL, 0x00000082)                   = 0

接下来,工作线程以非阻塞模式将与客户端的连接(文件描述符9)。在setsockopt(2)getsockopt(2)调用是Solaris的libc中如何把手的副作用fcntl(2)的插座。

/65:    read(9, " G E T   / 1 0 k . h t m".., 8000)     = 97

工作线程从客户端读取请求。

/65:    stat("/var/httpd/apache/httpd-8999/htdocs/10k.html", 0xFAF7B978) = 0
/65:    open("/var/httpd/apache/httpd-8999/htdocs/10k.html", O_RDONLY) = 10

此httpd已使用Options FollowSymLinks 和配置AllowOverride None。因此,它不需要到达 lstat(2)所需文件的路径中的每个目录,也不需要检查.htaccess文件。它只是调用stat(2)以验证文件:1)存在,并且2)是常规文件,而不是目录。

/65:    sendfilev(0, 9, 0x00200F90, 2, 0xFAF7B53C)      = 10269

在此示例中,httpd能够通过单个sendfilev(2) 系统调用发送HTTP响应标头和请求的文件。Sendfile语义在操作系统之间有所不同。在其他一些系统上,有必要在调用之前执行write(2)writev(2)调用以发送标头 sendfile(2)

/65:    write(4, " 1 2 7 . 0 . 0 . 1   -  ".., 78)      = 78

write(2)调用将请求记录在访问日志中。请注意,此跟踪中缺少的一件事是 time(2)调用。与Apache 1.3不同,Apache 2.x用于 gettimeofday(3)查找时间。在某些操作系统(如Linux或Solaris)上,gettimeofday它具有优化的实现,不需要像典型的系统调用那样大的开销。

/65:    shutdown(9, 1, 1)                               = 0
/65:    poll(0xFAF7B980, 1, 2000)                       = 1
/65:    read(9, 0xFAF7BC20, 512)                        = 0
/65:    close(9)                                        = 0

辅助线程会持续关闭连接。

/65:    close(10)                                       = 0
/65:    lwp_park(0x00000000, 0)         (sleeping...)

最后,工作线程关闭它刚刚传递的文件并阻塞,直到侦听器为它分配另一个连接。

/67:    accept(3, 0x001FEB74, 0x001FEB94, 1) (sleeping...)

同时,侦听器线程将连接分配给工作线程后,便能够接受另一个连接(受工作线程MPM中某些流控制逻辑的约束,如果所有可用工作线程都处于繁忙状态,则该流控制逻辑会限制侦听器)。尽管从此跟踪中看不出来,但下一个accept(2)罐(通常在高负载条件下也可以)与工作线程对刚刚接受的连接的处理并行发生。

可用语言: zh  |  fr  |  ko  |  TR 

最佳

注释

注意:
这不是“问答”部分。此处放置的评论应指向有关改进文档或服务器的建议,如果实施或被认为无效/偏离主题,我们的主持人可以将其删除。有关如何管理Apache HTTP Server的问题,应直接指向我们的IRC频道#httpd(位于Freenode上),或发送至我们的邮件列表
目前,此页面已禁用评论。