Nginx スレッド プールとパフォーマンス分析
リリース: 2016-08-08 09:19:43
ご存知のとおり、NGINX は接続の処理に非同期のイベント駆動型アプローチを採用しています。このアプローチでは、(従来のサーバーのように) リクエストごとに追加の専用プロセスまたはスレッドを作成する必要がなくなり、複数の接続とリクエストが 1 つのワーカー プロセスで処理されます。この目的を達成するために、NGINX はノンブロッキング ソケット モードで動作し、epoll や kqueue などの効果的なメソッドを使用します。 完全にロードされたプロセスの数は少なく (通常は CPU コアあたり 1 つだけ) 一定であるため、タスクの切り替えによるメモリ消費は非常に少なく、CPU サイクルを無駄にしません。このアプローチの利点は、NGINX 自体の使用を通じてすでによく知られています。 NGINX は、数百万の同時リクエストを非常にうまく処理できます。
各プロセスは追加のメモリを消費し、プロセス間の切り替えごとに CPU サイクルが消費され、CPU キャッシュ内のデータが破棄されます。
しかし、非同期のイベント駆動型のアプローチには依然として問題があります。あるいは、私がこの問題を「敵の兵士」と呼びたいのですが、敵の兵士の名前はブロッキングです。残念ながら、多くのサードパーティ モジュールはブロッキング呼び出しを使用していますが、ユーザー (場合によってはモジュール開発者さえ) はブロッキングの欠点に気づいていません。ブロック操作は NGINX のパフォーマンスを損なう可能性があるため、絶対に回避する必要があります。 現在の公式 NGINX コードでも、すべてのシナリオでブロックを回避することはまだ不可能です。NGINX 1.7.11 に実装されたスレッド プール メカニズムは、この問題を解決します。このスレッド プールとは何か、およびその使用方法については後ほど説明します。さあ、「敵兵」と正面衝突してみましょう。 2. 質問 まず、この問題をよりよく理解するために、NGINX がどのように機能するかをいくつかの文で説明しましょう。 通常、NGINX はイベント ハンドラー、つまりカーネルからすべての接続イベントに関する情報を受け取り、オペレーティング システムに何をすべきか指示を発行するコントローラーです。実際、NGINX は、バイトの読み取りと送信という日常的な作業を行うオペレーティング システムを調整するという汚い作業をすべて実行します。したがって、NGINX にとって、迅速かつタイムリーな対応は非常に重要です。
ワーカープロセスは、カーネルからのイベントをリッスンして処理します
イベントには、タイムアウトの通知、ソケットの読み取りと書き込みの準備完了、またはエラーの通知が含まれます。 NGINX は大量のイベントを受信し、それらを次々に処理して必要な操作を実行します。したがって、すべての処理は、スレッド内のキューを介した単純なループで実行されます。 NGINX はキューからイベントを取得し、ソケットの読み取りや書き込みなど、それに応答します。ほとんどの場合、このアプローチは非常に高速で (おそらく、一部のデータをメモリにコピーするのに数 CPU サイクルが必要なだけです)、NGINX はキュー内のすべてのイベントをフラッシュで処理できます。
すべての処理は1つのスレッドによる単純なループで行われます
ただし、NGINXが処理する操作がある程度長くて重い場合はどうなりますか手術が行われた場合?イベント処理ループ全体が、この操作が完了するまで待機したままになります。 したがって、「ブロック操作」とは、イベント処理ループを一定期間大幅に停止させる操作のことです。操作はさまざまな理由でブロック操作になる可能性があります。たとえば、NGINX は長時間にわたる CPU 集中型の処理でビジー状態であるか、リソース (ハードディスクやミューテックスなど) へのアクセス、または同期モードでデータベースから対応するライブラリ関数呼び出しを取得するのを待機している可能性があります。等。)。重要なのは、キュー内の一部のイベントで利用できるシステム リソースがさらに多くても、そのような操作の処理中、ワーカー プロセスは他のことを行ったり、他のイベントを処理したりすることはできないということです。 例えて言えば、店員は目の前に並んでいる顧客の長い列に対応しなければなりません。列に並んだ最初の顧客は、店内ではなく倉庫にある商品を求めていました。販売員は商品を取りに倉庫に走った。現在、チーム全体がこの種の配布を何時間も待たなければならず、チーム全員が不満を抱いています。人々の反応は想像できますよね?これらの時間は、購入したい商品が店内にない限り、列に並んでいる全員の待ち時間に追加されます。
列に並んでいる人は全員、最初の人が購入するのを待たなければなりません
ファイルを読み取るとき、ファイルがキャッシュされていない場合など、NGINX でもほぼ同じ状況が発生します。メモリの場合は、ディスクから読み取る必要があります。ディスク (特に回転ディスク) からの読み取りは遅く、キュー内で待機している他のリクエストは、ディスクにアクセスする必要がない場合でも待機することになります。その結果、遅延が増加し、システム リソースが十分に活用されなくなります。
一部のオペレーティング システムでは、ファイルの読み取りと書き込みが可能です
同期インターフェース、NGINXなどインターフェイスを使用できます (AIO の説明を参照)。 FreeBSD が良い例です。残念ながら、Linux では同じ利点が得られません。 Linux はファイルを読み取るための非同期インターフェイスを提供しますが、明らかな欠点があります。その 1 つは、ファイル アクセスとバッファリングを調整する必要があることですが、NGINX はこれを非常にうまく処理します。ただし、もう 1 つの欠点はさらに悪いことです。非同期インターフェイスでは、ファイル記述子に O_DIRECT フラグを設定する必要があります。これは、ファイルへのアクセスがメモリ内キャッシュをバイパスすることを意味し、ディスクの負荷が増加します。これが決して最善の選択肢ではないシナリオは数多くあります。 この問題を的を絞った方法で解決するために、NGINX 1.7.11 でスレッド プールが導入されました。デフォルトでは、NGINX+ にはまだスレッド プールが含まれていませんが、試してみたい場合は、NGINX+ R6 がスレッド プールを有効にしたビルドであるため、営業にお問い合わせください。 それでは、スレッド プールに足を踏み入れて、それが何なのか、どのように機能するのかを見てみましょう。 3. スレッドプール商品を配布するために倉庫からわざわざ行かなければならない哀れな販売員の話に戻りましょう。今回、彼は賢くなり(あるいは怒っている顧客の集団からの講義を受けて賢くなったのでしょうか?)、フルフィルメントサービスチームを雇いました。今では、遠く離れた倉庫にある商品を購入したい場合でも、直接倉庫に行く必要はなくなり、注文をフルフィルメント サービスに送るだけで、フルフィルメント サービスが注文を処理します。同時に、当社の営業担当者は引き続き他の顧客へのサービスを提供できます。したがって、倉庫から商品を購入したい顧客だけが流通を待つ必要があり、他の顧客はすぐにサービスを受けることができます。
オーダーを配信サービスに送信してもキューはブロックされません
NGINXの場合、スレッドプールが配信サービスの機能を実行します。これは、タスク キューと、このキューを処理する一連のスレッドで構成されます。 ワーカー プロセスが潜在的に長い操作を実行する必要がある場合、ワーカー プロセスは操作自体を実行するのではなく、タスクをスレッド プール キューに入れ、アイドル状態のスレッドはキューからタスクを取得して実行できます。ワーカープロセスはブロック操作をスレッドプールにオフロードします
つまり、別のキューがあるようなものです。はい、ただしこのシナリオでは、キューは特別なリソースに限定されます。ディスクがデータを生成できる速度よりも速くディスクを読み取ることはできません。とにかく、少なくとも現在では、ディスクは他のイベントを遅らせることはなくなり、ファイルへのアクセス要求だけを待つ必要があります。 通常、「ディスクからの読み取り」操作はブロック操作の最も一般的な例ですが、実際には、NGINX に実装されたスレッド プールを使用して、メイン ループに収まらないタスクを処理できます。 現在、スレッド プールにオフロードされている 2 つの基本操作は、ほとんどのオペレーティング システムの read() システム コールと Linux の sendfile() です。次に、スレッド プールのテストとベンチマークを行い、明らかな利点がある場合は、他の操作をスレッド プールにオフロードする可能性があります。 4. ベンチマーク
それでは、理論から実践に移りましょう。ブロッキング操作と非ブロッキング操作の最悪の場合の組み合わせでスレッド プールを使用した場合の影響をシミュレートする合成ベンチマークを実行します。 さらに、間違いなくメモリに収まらないデータセットが必要です。 48 GB のメモリを搭載したマシンで、ファイル サイズがそれぞれ 4 MB、合計 256 GB のランダム データを生成し、バージョン 1.9.0 で NGINX を構成しました。 設定は簡単です: 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;
}
}
} 上に示すように、より良いパフォーマンスを達成するために、いくつかのパラメータを調整しました: ロギングと accept_mutex を無効にし、同時に sendfile を有効にし、sendfile_max_chunk のサイズを設定しました。この最後のディレクティブは、NGINX がファイル全体を一度に送信しようとせず、毎回 512KB のチャンクでデータを送信するため、sendfile() への呼び出しのブロックに費やされる最大時間を短縮します。 このテスト サーバーには、2 つの Intel Xeon E5645 プロセッサ (合計: 12 コア、24 ハイパースレッド) と 10 Gbps ネットワーク インターフェイスが搭載されています。ディスク サブシステムは 4 台の Western Digital WD1003FBYX で構成されています。
ディスクの RAID10 アレイ。このハードウェアはすべて Ubuntu Server 14.04.1 LTS を搭載しています。
ベンチマーク用にロード ジェネレーターと NGINX を構成する クライアントには 2 台のサーバーがあり、それらは同じ仕様です。そのうちの 1 つでは、ロード プログラムは 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_z
use_temp_path=off;
proxy_cache_path /mnt/disk2 levels=1:2 keys_z
use_temp_path=off;
proxy_cache_path /mnt/disk3 levels=1:2 keys_z
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 と互換性がありませんでした。独自のノンブロッキング プロトタイピング ライブラリの開発に多くの時間とリソースを費やすこともできますが、それだけの価値は常にあるのでしょうか?現在、スレッド プールを使用すると、これらのモジュールのパフォーマンスに影響を与えることなく、これらのライブラリを比較的簡単に使用できるようになります。
以上、Nginx のスレッドプールとパフォーマンス分析をその側面も含めて紹介しましたが、PHP チュートリアルに興味のある友人に役立つことを願っています。
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
著者別の最新記事
-
2024-10-22 09:46:29
-
2024-10-13 13:53:41
-
2024-10-12 12:15:51
-
2024-10-11 22:47:31
-
2024-10-11 19:36:51
-
2024-10-11 15:50:41
-
2024-10-11 15:07:41
-
2024-10-11 14:21:21
-
2024-10-11 12:59:11
-
2024-10-11 12:17:31