阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

Nginx引入线程池 性能提升9倍

388次阅读
没有评论

共计 10772 个字符,预计需要花费 27 分钟才能阅读完成。

 

1. 引言

 

正如我们所知,NGINX 采用了异步、事件驱动的方法来处理连接。这种处理方式无需(像使用传统架构的服务器一样)为每个请求创建额外的专用进程或者线程,而是在一个工作进程中处理多个连接和请求。为此,NGINX 工作在非阻塞的 socket 模式下,并使用了 epoll 和 kqueue 这样有效的方法。

 

因为满负载进程的数量很少(通常每核 CPU 只有一个)而且恒定,所以任务切换只消耗很少的内存,而且不会浪费 CPU 周期。通过 NGINX 本身的实例,这种方法的优点已经为众人所知。NGINX 可以非常好地处理百万级规模的并发请求。

 

Nginx 引入线程池 性能提升 9 倍

 

每个进程都消耗额外的内存,而且每次进程间的切换都会消耗 CPU 周期并丢弃 CPU 高速缓存中的数据。

 

但是,异步、事件驱动方法仍然存在问题。或者,我喜欢将这一问题称为“敌兵”,这个敌兵的名字叫 阻塞(blocking)。不幸的是,很多第三方模块使用了阻塞调用,然而用户(有时甚至是模块的开发者)并不知道阻塞的缺点。阻塞操作可以毁掉 NGINX 的性能,我们必须不惜一切代价避免使用阻塞。

 

即使在当前官方的 NGINX 代码中,依然无法在全部场景中避免使用阻塞,NGINX1.7.11 中实现的线程池机制解决了这个问题。我们将在后面讲述这个线程池是什么以及该如何使用。现在,让我们先和我们的“敌兵”进行一次面对面的碰撞。

 

2. 问题

 

首先,为了更好地理解这一问题,我们用几句话说明下 NGINX 是如何工作的。

 

通常情况下,NGINX 是一个事件处理器,即一个接收来自内核的所有连接事件的信息,然后向操作系统发出做什么指令的控制器。实际上,NGINX 干了编排操作系统的全部脏活累活,而操作系统做的是读取和发送字节这样的日常工作。所以,对于 NGINX 来说,快速和及时的响应是非常重要的。

 

Nginx 引入线程池 性能提升 9 倍

 

工作进程监听并处理来自内核的事件

 

事件可以是超时、socket 读写就绪的通知,或者发生错误的通知。NGINX 接收大量的事件,然后一个接一个地处理它们,并执行必要的操作。因此,所有的处理过程是通过一个线程中的队列,在一个简单循环中完成的。NGINX 从队列中取出一个事件并对其做出响应,比如读写 socket。在多数情况下,这种方式是非常快的(也许只需要几个 CPU 周期,将一些数据复制到内存中),NGINX 可以在一瞬间处理掉队列中的所有事件。

 

Nginx 引入线程池 性能提升 9 倍

 

所有处理过程是在一个简单的循环中,由一个线程完成

 

但是,如果 NGINX 要处理的操作是一些又长又重的操作,又会发生什么呢?整个事件处理循环将会卡住,等待这个操作执行完毕。

 

因此,所谓“阻塞操作”是指任何导致事件处理循环显著停止一段时间的操作。操作可以由于各种原因成为阻塞操作。例如,NGINX 可能因长时间、CPU 密集型处理,或者可能等待访问某个资源(比如硬盘,或者一个互斥体,亦或要从处于同步方式的数据库获得相应的库函数调用等)而繁忙。关键是在处理这样的操作期间,工作进程无法做其他事情或者处理其他事件,即使有更多的可用系统资源可以被队列中的一些事件所利用。

 

我们来打个比方,一个商店的营业员要接待他面前排起的一长队顾客。队伍中的第一位顾客想要的某件商品不在店里而在仓库中。这位营业员跑去仓库把东西拿来。现在整个队伍必须为这样的配货方式等待数个小时,队伍中的每个人都很不爽。你可以想见人们的反应吧?队伍中每个人的等待时间都要增加这些时间,除非他们要买的东西就在店里。

 

Nginx 引入线程池 性能提升 9 倍

 

队伍中的每个人不得不等待第一个人的购买

 

在 NGINX 中会发生几乎同样的情况,比如当读取一个文件的时候,如果该文件没有缓存在内存中,就要从磁盘上读取。从磁盘(特别是旋转式的磁盘)读取是很慢的, 而当队列中等待的其他请求可能不需要访问磁盘时,它们也得被迫等待。导致的结果是,延迟增加并且系统资源没有得到充分利用。

 

Nginx 引入线程池 性能提升 9 倍

 

一个阻塞操作足以显著地延缓所有接下来的操作

 

一些操作系统为读写文件提供了异步接口,NGINX 可以使用这样的接口(见 AIO 指令)。FreeBSD 就是个很好的例子。不幸的是,我们不能在 Linux 上得到相同的福利。虽然 Linux 为读取文件提供了一种异步接口,但是存在明显的缺点。其中之一是要求文件访问和缓冲要对齐,但 NGINX 很好地处理了这个问题。但是,另一个缺点更糟糕。异步接口要求文件描述符中要设置 O_DIRECT 标记,就是说任何对文件的访问都将绕过内存中的缓存,这增加了磁盘的负载。在很多场景中,这都绝对不是最佳选择。

 

为了有针对性地解决这一问题,在 NGINX 1.7.11 中引入了线程池。默认情况下,NGINX+ 还没有包含线程池,但是如果你想试试的话,可以联系销售人员,NGINX+ R6 是一个已经启用了线程池的构建版本。

 

现在,让我们走进线程池,看看它是什么以及如何工作的。

 

3. 线程池

 

让我们回到那个可怜的,要从大老远的仓库去配货的售货员那儿。这回,他已经变聪明了(或者也许是在一群愤怒的顾客教训了一番之后,他才变得聪明的?),雇用了一个配货服务团队。现在,当任何人要买的东西在大老远的仓库时,他不再亲自去仓库了,只需要将订单丢给配货服务,他们将处理订单,同时,我们的售货员依然可以继续为其他顾客服务。因此,只有那些要买仓库里东西的顾客需要等待配货,其他顾客可以得到即时服务。

 

Nginx 引入线程池 性能提升 9 倍

 

传递订单给配货服务不会阻塞队伍

 

对 NGINX 而言,线程池执行的就是配货服务的功能。它由一个任务队列和一组处理这个队列的线程组成。
当工作进程需要执行一个潜在的长操作时,工作进程不再自己执行这个操作,而是将任务放到线程池队列中,任何空闲的线程都可以从队列中获取并执行这个任务。

 

Nginx 引入线程池 性能提升 9 倍

 

工作进程将阻塞操作卸给线程池

 

那么,这就像我们有了另外一个队列。是这样的,但是在这个场景中,队列受限于特殊的资源。磁盘的读取速度不能比磁盘产生数据的速度快。不管怎么说,至少现在磁盘不再延误其他事件,只有访问文件的请求需要等待。

 

“从磁盘读取”这个操作通常是阻塞操作最常见的示例,但是实际上,NGINX 中实现的线程池可用于处理任何不适合在主循环中执行的任务。

 

目前,卸载到线程池中执行的两个基本操作是大多数操作系统中的 read()系统调用和 Linux 中的 sendfile()。接下来,我们将对线程池进行测试(test)和基准测试(benchmark),在未来的版本中,如果有明显的优势,我们可能会卸载其他操作到线程池中。

 

4. 基准测试

 

现在让我们从理论过度到实践。我们将进行一次模拟基准测试(synthetic benchmark),模拟在阻塞操作和非阻塞操作的最差混合条件下,使用线程池的效果。

 

另外,我们需要一个内存肯定放不下的数据集。在一台 48GB 内存的机器上,我们已经产生了每文件大小为 4MB 的随机数据,总共 256GB,然后配置 NGINX,版本为 1.9.0。

 

配置很简单:

 

worker_processes 16;

events {accept_mutex off;}

http {
    include mime.types;
    default_type application/octet-stream;

    access_log off;
    sendfile on;
    sendfile_max_chunk 512k;

    server {
        listen 8000;

        location / {root /storage;}
    }
}

 

如上所示,为了达到更好的性能,我们调整了几个参数:禁用了 logging 和 accept_mutex,同时,启用了 sendfile 并设置了 sendfile_max_chunk 的大小。最后一个指令可以减少阻塞调用 sendfile()所花费的最长时间,因为 NGINX 不会尝试一次将整个文件发送出去,而是每次发送大小为 512KB 的块数据。

 

这台测试服务器有 2 个 Intel Xeon E5645 处理器(共计:12 核、24 超线程)和 10-Gbps 的网络接口。磁盘子系统是由 4 块西部数据 WD1003FBYX 磁盘组成的 RAID10 阵列。所有这些硬件由 Ubuntu 服务器 14.04.1 LTS 供电。

 

Nginx 引入线程池 性能提升 9 倍

 

为基准测试配置负载生成器和 NGINX

 

客户端有 2 台服务器,它们的规格相同。在其中一台上,在 wrk 中使用 Lua 脚本创建了负载程序。脚本使用 200 个并行连接向服务器请求文件,每个请求都可能未命中缓存而从磁盘阻塞读取。我们将这种负载称作随机负载。

 

在另一台客户端机器上,我们将运行 wrk 的另一个副本,使用 50 个并行连接多次请求同一个文件。因为这个文件将被频繁地访问,所以它会一直驻留在内存中。在正常情况下,NGINX 能够非常快速地服务这些请求,但是如果工作进程被其他请求阻塞的话,性能将会下降。我们将这种负载称作恒定��载。

 

性能将由服务器上 ifstat 监测的吞吐率(throughput)和从第二台客户端获取的 wrk 结果来度量。

 

现在,没有使用线程池的第一次运行将不会带给我们非常振奋的结果:

 

% ifstat -bi eth2
eth2
Kbps in  Kbps out
5531.24  1.03e+06
4855.23  812922.7
5994.66  1.07e+06
5476.27  981529.3
6353.62  1.12e+06
5166.17  892770.3
5522.81  978540.8
6208.10  985466.7
6370.79  1.12e+06
6123.33  1.07e+06

 

如上所示,使用这种配置,服务器产生的总流量约为 1Gbps。从下面所示的 top 输出,我们可以看到,工作进程的大部分时间花在阻塞 I / O 上(它们处于 top 的 D 状态):

 

top - 10:40:47 up 11 days,  1:32,  1 user,  load average: 49.61, 45.77 62.89
Tasks: 375 total,  2 running, 373 sleeping,  0 stopped,  0 zombie
%Cpu(s):  0.0 us,  0.3 sy,  0.0 ni, 67.7 id, 31.9 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem:  49453440 total, 49149308 used,   304132 free,    98780 buffers
KiB Swap: 10474236 total,    20124 used, 10454112 free, 46903412 cached Mem

  PID USER     PR  NI    VIRT    RES     SHR S  %CPU %MEM    TIME+ COMMAND
 4639 vbart    20   0   47180  28152     496 D   0.7  0.1  0:00.17 nginx
 4632 vbart    20   0   47180  28196     536 D   0.3  0.1  0:00.11 nginx
 4633 vbart    20   0   47180  28324     540 D   0.3  0.1  0:00.11 nginx
 4635 vbart    20   0   47180  28136     480 D   0.3  0.1  0:00.12 nginx
 4636 vbart    20   0   47180  28208     536 D   0.3  0.1  0:00.14 nginx
 4637 vbart    20   0   47180  28208     536 D   0.3  0.1  0:00.10 nginx
 4638 vbart    20   0   47180  28204     536 D   0.3  0.1  0:00.12 nginx
 4640 vbart    20   0   47180  28324     540 D   0.3  0.1  0:00.13 nginx
 4641 vbart    20   0   47180  28324     540 D   0.3  0.1  0:00.13 nginx
 4642 vbart    20   0   47180  28208     536 D   0.3  0.1  0:00.11 nginx
 4643 vbart    20   0   47180  28276     536 D   0.3  0.1  0:00.29 nginx
 4644 vbart    20   0   47180  28204     536 D   0.3  0.1  0:00.11 nginx
 4645 vbart    20   0   47180  28204     536 D   0.3  0.1  0:00.17 nginx
 4646 vbart    20   0   47180  28204     536 D   0.3  0.1  0:00.12 nginx
 4647 vbart    20   0   47180  28208     532 D   0.3  0.1  0:00.17 nginx
 4631 vbart    20   0   47180    756     252 S   0.0  0.1  0:00.00 nginx
 4634 vbart    20   0   47180  28208     536 D   0.0  0.1  0:00.11 nginx
 4648 vbart    20   0   25232   1956    1160 R   0.0  0.0  0:00.08 top
25921 vbart    20   0  121956   2232    1056 S   0.0  0.0  0:01.97 sshd
25923 vbart    20   0   40304   4160    2208 S   0.0  0.0  0:00.53 zsh

 

在这种情况下,吞吐率受限于磁盘子系统,而 CPU 在大部分时间里是空闲的。从 wrk 获得的结果也非常低:

 

Running 1m test @ http://192.0.2.1:8000/1/1/1
  12 threads and 50 connections
  Thread Stats   Avg    Stdev     Max  +/- Stdev
    Latency     7.42s  5.31s   24.41s   74.73%
    Req/Sec     0.15    0.36     1.00    84.62%
  488 requests in 1.01m, 2.01GB read
Requests/sec:      8.08
Transfer/sec:     34.07MB

 

请记住,文件是从内存送达的!第一个客户端的 200 个连接创建的随机负载,使服务器端的全部的工作进程忙于从磁盘读取文件,因此产生了过大的延迟,并且无法在合理的时间内处理我们的请求。

 

现在,我们的线程池要登场了。为此,我们只需在 location 块中添加 aio threads 指令:

 

location / {
    root /storage;
    aio threads;
}

 

接着,执行 NGINX reload 重新加载配置。

 

然后,我们重复上述的测试:

 

% ifstat -bi eth2
eth2
Kbps in  Kbps out
60915.19  9.51e+06
59978.89  9.51e+06
60122.38  9.51e+06
61179.06  9.51e+06
61798.40  9.51e+06
57072.97  9.50e+06
56072.61  9.51e+06
61279.63  9.51e+06
61243.54  9.51e+06
59632.50  9.50e+06

 

现在,我们的服务器产生的流量是9.5Gbps,相比之下,没有使用线程池时只有约 1Gbps!

 

理论上还可以产生更多的流量,但是这已经达到了机器的最大网络吞吐能力,所以在这次 NGINX 的测试中,NGINX 受限于网络接口。工作进程的大部分时间只是休眠和等待新的时间(它们处于 top 的 S 状态):

 

top - 10:43:17 up 11 days,  1:35,  1 user,  load average: 172.71, 93.84, 77.90
Tasks: 376 total,  1 running, 375 sleeping,  0 stopped,  0 zombie
%Cpu(s):  0.2 us,  1.2 sy,  0.0 ni, 34.8 id, 61.5 wa,  0.0 hi,  2.3 si,  0.0 st
KiB Mem:  49453440 total, 49096836 used,   356604 free,    97236 buffers
KiB Swap: 10474236 total,    22860 used, 10451376 free, 46836580 cached Mem

  PID USER     PR  NI    VIRT    RES     SHR S  %CPU %MEM    TIME+ COMMAND
 4654 vbart    20   0  309708  28844     596 S   9.0  0.1  0:08.65 nginx
 4660 vbart    20   0  309748  28920     596 S   6.6  0.1  0:14.82 nginx
 4658 vbart    20   0  309452  28424     520 S   4.3  0.1  0:01.40 nginx
 4663 vbart    20   0  309452  28476     572 S   4.3  0.1  0:01.32 nginx
 4667 vbart    20   0  309584  28712     588 S   3.7  0.1  0:05.19 nginx
 4656 vbart    20   0  309452  28476     572 S   3.3  0.1  0:01.84 nginx
 4664 vbart    20   0  309452  28428     524 S   3.3  0.1  0:01.29 nginx
 4652 vbart    20   0  309452  28476     572 S   3.0  0.1  0:01.46 nginx
 4662 vbart    20   0  309552  28700     596 S   2.7  0.1  0:05.92 nginx
 4661 vbart    20   0  309464  28636     596 S   2.3  0.1  0:01.59 nginx
 4653 vbart    20   0  309452  28476     572 S   1.7  0.1  0:01.70 nginx
 4666 vbart    20   0  309452  28428     524 S   1.3  0.1  0:01.63 nginx
 4657 vbart    20   0  309584  28696     592 S   1.0  0.1  0:00.64 nginx
 4655 vbart    20   0  30958   28476     572 S   0.7  0.1  0:02.81 nginx
 4659 vbart    20   0  309452  28468     564 S   0.3  0.1  0:01.20 nginx
 4665 vbart    20   0  309452  28476     572 S   0.3  0.1  0:00.71 nginx
 5180 vbart    20   0   25232   1952    1156 R   0.0  0.0  0:00.45 top
 4651 vbart    20   0   20032    752     252 S   0.0  0.0  0:00.00 nginx
25921 vbart    20   0  121956   2176    1000 S   0.0  0.0  0:01.98 sshd
25923 vbart    20   0   40304   3840    2208 S   0.0  0.0  0:00.54 zsh

 

如上所示,基准测试中还有大量的 CPU 资源剩余。

 

wrk 的结果如下:

 

Running 1m test @ http://192.0.2.1:8000/1/1/1
  12 threads and 50 connections
  Thread Stats   Avg      Stdev     Max  +/- Stdev
    Latency   226.32ms  392.76ms   1.72s   93.48%
    Req/Sec    20.02     10.84    59.00    65.91%
  15045 requests in 1.00m, 58.86GB read
Requests/sec:    250.57
Transfer/sec:      0.98GB

 

服务器处理 4MB 文件的平均时间从 7.42 秒降到 226.32 毫秒(减少了 33 倍),每秒请求处理数提升了 31 倍(250 vs 8)!

 

对此,我们的解释是请求不再因为工作进程被阻塞在读文件,而滞留在事件队列中,等待处理,它们可以被空闲的进程处理掉。只要磁盘子系统能做到最好,就能服务好第一个客户端上的随机负载,NGINX 可以使用剩余的 CPU 资源和网络容量,从内存中读取,以服务于上述的第二个客户端的请求。

 

5. 依然没有银弹

 

在抛出我们对阻塞操作的担忧并给出一些令人振奋的结果后,可能大部分人已经打算在你的服务器上配置线程池了。先别着急。

 

实际上,最幸运的情况是,读取和发送文件操作不去处理缓慢的硬盘驱动器。如果我们有足够多的内存来存储数据集,那么操作系统将会足够聪明地在被称作“页面缓存”的地方,缓存频繁使用的文件。

 

“页面缓存”的效果很好,可以让 NGINX 在几乎所有常见的用例中展示优异的性能。从页面缓存中读取比较快,没有人会说这种操作是“阻塞”。而另一方面,卸载任务到一个线程池是有一定开销的。

 

因此,如果内存有合理的大小并且待处理的数据集不是很大的话,那么无需使用线程池,NGINX 已经工作在最优化的方式下。

 

卸载读操作到线程池是一种适用于非常特殊任务的技术。只有当经常请求的内容的大小,不适合操作系统的虚拟机缓存时,这种技术才是最有用的。至于可能适用的场景,比如,基于 NGINX 的高负载流媒体服务器。这正是我们已经模拟的基准测试的场景。

 

我们如果可以改进卸载读操作到线程池,将会非常有意义。我们只需要知道所需的文件数据是否在内存中,只有不在内存中时,读操作才应该卸载到一个单独的线程中。

 

再回到售货员那个比喻的场景中,这回,售货员不知道要买的商品是否在店里,他必须要么总是将所有的订单提交给配货服务,要么总是亲自处理它们。

 

人艰不拆,操作系统缺少这样的功能。第一次尝试是在 2010 年,人们试图将这一功能添加到 Linux 作为 fincore()系统调用,但是没有成功。后来还有一些尝试,是使用 RWF_NONBLOCK 标记作为 preadv2()系统调用来实现这一功能(详情见 LWN.net 上的非阻塞缓冲文件读取操作和异步缓冲读操作)。但所有这些补丁的命运目前还不明朗。悲催的是,这些补丁尚没有被内核接受的主要原因,貌似是因为旷日持久的撕逼大战(bikeshedding)。

 

另一方面,FreeBSD 的用户完全不必担心。FreeBSD 已经具备足够好的读文件取异步接口,我们应该用这个接口而不是线程池。

 

6. 配置线程池

 

所以,如果你确信在你的场景中使用线程池可以带来好处,那么现在是时候深入了解线程池的配置了。

 

线程池的配置非常简单、灵活。首先,获取 NGINX 1.7.11 或更高版本的源代码,使用–with-threads 配置参数编译。在最简单的场景中,配置看起来很朴实。我们只需要在 http、server,或者 location 上下文中包含 aio threads 指令即可:

 

aio threads;

 

这是线程池的最简配置。实际上的精简版本示例如下:

 

thread_pool default threads=32 max_queue=65536;
aio threads=default;

 

这里定义了一个名为“default”,包含 32 个线程,任务队列最多支持 65536 个请求的线程池。如果任务队列过载,NGINX 将输出如下错误日志并拒绝请求:

 

thread pool "NAME" queue overflow: N tasks waiting

 

错误输出意味着线程处理作业的速度有可能低于任务入队的速度了。你可以尝试增加队列的最大值,但是如果这无济于事,那么这说明你的系统没有能力处理如此多的请求了。

 

正如你已经注意到的,你可以使用 thread_pool 指令,配置线程的数量、队列的最大值,以及线程池的名称。最后要说明的是,可以配置多个独立的线程池,将它们置于不同的配置文件中,用做不同的目的:

 

http {
    thread_pool one threads=128 max_queue=0;
    thread_pool two threads=32;

    server {
        location /one {aio threads=one;}

        location /two {aio threads=two;}
    }
…
}

 

如果没有指定 max_queue 参数的值,默认使用的值是 65536。如上所示,可以设置 max_queue 为 0。在这种情况下,线程池将使用配置中全部数量的线程,尽可能地同时处理多个任务;队列中不会有等待的任务。

 

现在,假设我们有一台服务器,挂了 3 块硬盘,我们希望把该服务器用作“缓存代理”,缓存后端服务器的全部响应信息。预期的缓存数据量远大于可用的内存。它实际上是我们个人 CDN 的一个缓存节点。毫无疑问,在这种情况下,最重要的事情是发挥硬盘的最大性能。

 

我们的选择之一是配置一个 RAID 阵列。这种方法毁誉参半,现在,有了 NGINX,我们可以有其他的选择:

 

# 我们假设每块硬盘挂载在相应的目录中:/mnt/disk1、/mnt/disk2、/mnt/disk3

proxy_cache_path /mnt/disk1 levels=1:2 keys_zone=cache_1:256m max_size=1024G
                 use_temp_path=off;
proxy_cache_path /mnt/disk2 levels=1:2 keys_zone=cache_2:256m max_size=1024G
                 use_temp_path=off;
proxy_cache_path /mnt/disk3 levels=1:2 keys_zone=cache_3:256m max_size=1024G
                 use_temp_path=off;

thread_pool pool_1 threads=16;
thread_pool pool_2 threads=16;
thread_pool pool_3 threads=16;

split_clients $request_uri $disk {
    33.3%     1;
    33.3%     2;
    *         3;
}

location / {
    proxy_pass http://backend;
    proxy_cache_key $request_uri;
    proxy_cache cache_$disk;
    aio threads=pool_$disk;
    sendfile on;
}

 

在这份配置中,使用了 3 个独立的缓存,每个缓存专用一块硬盘,另外,3 个独立的线程池也各自专用一块硬盘。

 

缓存之间(其结果就是磁盘之间)的 负载均衡 使用 split_clients 模块,split_clients 非常适用于这个任务。

 

在 proxy_cache_path 指令中设置 use_temp_path=off,表示 NGINX 会将临时文件保存在缓存数据的同一目录中。这是为了避免在更新缓存时,磁盘之间互相复制响应数据。

 

这些调优将带给我们磁盘子系统的最大性能,因为 NGINX 通过单独的线程池并行且独立地与每块磁盘交互。每块磁盘由 16 个独立线程和读取和发送文件专用任务队列提供服务。

 

我敢打赌,你的客户喜欢这种量身定制的方法。请确保你的磁盘也持有同样的观点。

 

这个示例很好地证明了 NGINX 可以为硬件专门调优的灵活性。这就像你给 NGINX 下了一道命令,让机器和数据用最佳姿势来搞基。而且,通过 NGINX 在用户空间中细粒度的调优,我们可以确保软件、操作系统和硬件工作在最优模式下,尽可能有效地利用系统资源。

 

7. 总结

 

综上所述,线程池是一个伟大的功能,将 NGINX 推向了新的性能水平,除掉了一个众所周知的长期危害——阻塞——尤其是当我们真正面对大量内容的时候。

 

甚至,还有更多的惊喜。正如前面提到的,这个全新的接口,有可能没有任何性能损失地卸载任何长期阻塞操作。NGINX 在拥有大量的新模块和新功能方面,开辟了一方新天地。许多流行的库仍然没有提供异步非阻塞接口,此前,这使得它们无法与 NGINX 兼容。我们可以花大量的时间和资源,去开发我们自己的无阻塞原型库,但这么做始终都是值得的吗?现在,有了线程池,我们可以相对容易地使用这些库,而不会影响这些模块的性能。

 

本文永久更新链接地址:http://www.linuxidc.com/Linux/2015-08/121535.htm

正文完
星哥玩云-微信公众号
post-qrcode
 0
星锅
版权声明:本站原创文章,由 星锅 于2022-01-20发表,共计10772字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
阿里云-最新活动爆款每日限量供应
评论(没有评论)
验证码
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中

星哥玩云

星哥玩云
星哥玩云
分享互联网知识
用户数
4
文章数
19351
评论数
4
阅读量
7991156
文章搜索
热门文章
星哥带你玩飞牛NAS-6:抖音视频同步工具,视频下载自动下载保存

星哥带你玩飞牛NAS-6:抖音视频同步工具,视频下载自动下载保存

星哥带你玩飞牛 NAS-6:抖音视频同步工具,视频下载自动下载保存 前言 各位玩 NAS 的朋友好,我是星哥!...
星哥带你玩飞牛NAS-3:安装飞牛NAS后的很有必要的操作

星哥带你玩飞牛NAS-3:安装飞牛NAS后的很有必要的操作

星哥带你玩飞牛 NAS-3:安装飞牛 NAS 后的很有必要的操作 前言 如果你已经有了飞牛 NAS 系统,之前...
我把用了20年的360安全卫士卸载了

我把用了20年的360安全卫士卸载了

我把用了 20 年的 360 安全卫士卸载了 是的,正如标题你看到的。 原因 偷摸安装自家的软件 莫名其妙安装...
再见zabbix!轻量级自建服务器监控神器在Linux 的完整部署指南

再见zabbix!轻量级自建服务器监控神器在Linux 的完整部署指南

再见 zabbix!轻量级自建服务器监控神器在 Linux 的完整部署指南 在日常运维中,服务器监控是绕不开的...
飞牛NAS中安装Navidrome音乐文件中文标签乱码问题解决、安装FntermX终端

飞牛NAS中安装Navidrome音乐文件中文标签乱码问题解决、安装FntermX终端

飞牛 NAS 中安装 Navidrome 音乐文件中文标签乱码问题解决、安装 FntermX 终端 问题背景 ...
阿里云CDN
阿里云CDN-提高用户访问的响应速度和成功率
随机文章
仅2MB大小!开源硬件监控工具:Win11 无缝适配,CPU、GPU、网速全维度掌控

仅2MB大小!开源硬件监控工具:Win11 无缝适配,CPU、GPU、网速全维度掌控

还在忍受动辄数百兆的“全家桶”监控软件?后台偷占资源、界面杂乱冗余,想查个 CPU 温度都要层层点选? 今天给...
在Windows系统中通过VMware安装苹果macOS15

在Windows系统中通过VMware安装苹果macOS15

在 Windows 系统中通过 VMware 安装苹果 macOS15 许多开发者和爱好者希望在 Window...
如何安装2026年最强个人助理ClawdBot、完整安装教程

如何安装2026年最强个人助理ClawdBot、完整安装教程

如何安装 2026 年最强个人助理 ClawdBot、完整安装教程 一、前言 学不完,根本学不完!近期,一款名...
安装Black群晖DSM7.2系统安装教程(在Vmware虚拟机中、实体机均可)!

安装Black群晖DSM7.2系统安装教程(在Vmware虚拟机中、实体机均可)!

安装 Black 群晖 DSM7.2 系统安装教程(在 Vmware 虚拟机中、实体机均可)! 前言 大家好,...
星哥带你玩飞牛 NAS-9:全能网盘搜索工具 13 种云盘一键搞定!

星哥带你玩飞牛 NAS-9:全能网盘搜索工具 13 种云盘一键搞定!

星哥带你玩飞牛 NAS-9:全能网盘搜索工具 13 种云盘一键搞定! 前言 作为 NAS 玩家,你是否总被这些...

免费图片视频管理工具让灵感库告别混乱

一言一句话
-「
手气不错
仅2MB大小!开源硬件监控工具:Win11 无缝适配,CPU、GPU、网速全维度掌控

仅2MB大小!开源硬件监控工具:Win11 无缝适配,CPU、GPU、网速全维度掌控

还在忍受动辄数百兆的“全家桶”监控软件?后台偷占资源、界面杂乱冗余,想查个 CPU 温度都要层层点选? 今天给...
恶意团伙利用 PHP-FPM 未授权访问漏洞发起大规模攻击

恶意团伙利用 PHP-FPM 未授权访问漏洞发起大规模攻击

恶意团伙利用 PHP-FPM 未授权访问漏洞发起大规模攻击 PHP-FPM(FastCGl Process M...
安装并使用谷歌AI编程工具Antigravity(亲测有效)

安装并使用谷歌AI编程工具Antigravity(亲测有效)

  安装并使用谷歌 AI 编程工具 Antigravity(亲测有效) 引言 Antigravity...
星哥带你玩飞牛NAS硬件 01:捡垃圾的最爱双盘,暴风二期矿渣为何成不老神话?

星哥带你玩飞牛NAS硬件 01:捡垃圾的最爱双盘,暴风二期矿渣为何成不老神话?

星哥带你玩飞牛 NAS 硬件 01:捡垃圾的最爱双盘,暴风二期矿渣为何成不老神话? 前言 在选择 NAS 用预...
手把手教你,购买云服务器并且安装宝塔面板

手把手教你,购买云服务器并且安装宝塔面板

手把手教你,购买云服务器并且安装宝塔面板 前言 大家好,我是星哥。星哥发现很多新手刚接触服务器时,都会被“选购...