ホームページ  >  記事  >  運用・保守  >  OpenResty と Nginx の共有メモリ領域での物理メモリ リソース (または RAM) の使用を検討しますか?

OpenResty と Nginx の共有メモリ領域での物理メモリ リソース (または RAM) の使用を検討しますか?

青灯夜游
青灯夜游転載
2020-08-29 10:16:142876ブラウズ

OpenResty と Nginx の共有メモリ領域での物理メモリ リソース (または RAM) の使用を検討しますか?

OpenResty サーバーと Nginx サーバーは通常、すべてのワーカー プロセス間で共有されるデータを保存する共有メモリ領域を使用して構成されます。たとえば、Nginx 標準モジュール ngx_http_limit_reqngx_http_limit_conn は、共有メモリ領域を使用して状態データを保存し、すべてのワーカー プロセスにわたるユーザー リクエスト レートとユーザー リクエストの同時実行を制限します。 OpenResty の ngx_lua モジュールは、lua_shared_dict を通じてユーザーの Lua コードに共有メモリベースのデータ ディクショナリ ストレージを提供します。

この記事では、いくつかの単純で独立した例を通じて、これらの共有メモリ領域が物理メモリ リソース (または RAM) をどのように使用するかを説明します。また、ps などのシステム ツールの結果における VSZRSS などのシステム レベルのプロセス メモリ メトリックに対する共有メモリ使用量の影響も調査します。インジケーター。

この ブログ サイトのほぼすべての技術記事と同様に、私たちは OpenResty XRay を使用します。この 動的トラッキング 製品は変更せずに使用されます。詳細な分析を実行します。 OpenResty または Nginx サーバーとアプリケーションの内部の視覚化。 OpenRestyモジュールだからです。これにより、OpenResty XRay 分析ツールを通じて確認できるターゲット プロセスの内部状態が、オブザーバーなしの状態と完全に一致することが保証されます。

このモジュールはカスタム Lua コードでプログラムできるため、ほとんどの例では

ngx_lua モジュールの lua_shared_dict を使用します。これらの例で示す動作と問題は、すべての標準 Nginx モジュールおよびサードパーティ モジュールの他の共有メモリ領域にも当てはまります。

スラブとメモリ ページ

Nginx とそのモジュールは通常、Nginx コアの

スラブ アロケータ を使用して、共有メモリ領域のスペースを管理します。 。このスラブ アロケータは、固定サイズのメモリ領域内で小さなメモリ ブロックを割り当て、解放するように設計されています。

スラブに基づいて、共有メモリ領域には赤黒ツリーやリンク リストなどのより高いレベルのデータ構造が導入されます。

slab は、数バイトほど小さい場合もあれば、複数のメモリ ページにまたがるほど大きい場合もあります。

オペレーティング システムは、プロセスの共有メモリ (または他のタイプのメモリ) をメモリ ページの単位で管理します。


x86_64 Linux システムでは、デフォルトのメモリ ページ サイズは通常 4 KB ですが、正確なサイズは Linux カーネルのアーキテクチャと構成によって異なります。たとえば、一部の Aarch64 Linux システムのメモリ ページ サイズは 64 KB にもなります。

OpenResty プロセスと Nginx プロセスの共有メモリ領域の詳細を、それぞれメモリ ページ レベルとスラブ レベルで見ていきます。

割り当てられたメモリは必ずしも消費されるわけではありません

ハードディスクなどのリソースとは異なり、物理メモリ (または RAM) は常に非常に貴重なリソースです。
最新のオペレーティング システムでは、デマンド ページング (デマンド ページング) と呼ばれる最適化テクノロジが実装されており、ユーザー アプリケーションによる RAM リソースへの負荷を軽減するために使用されます。具体的には、大きなメモリ ブロックを割り当てると、オペレーティング システム カーネルは、メモリ ページ内のデータが実際に使用されるまで、RAM リソース (または物理メモリ ページ) の実際の割り当てを延期します。たとえば、ユーザー プロセスに 10 メモリ ページが割り当てられているが、3 メモリ ページしか使用していない場合、オペレーティング システムはこれら 3 メモリ ページのみを RAM デバイスにマップしている可能性があります。この動作は、Nginx または OpenResty アプリケーションに割り当てられた共有メモリ領域にも適用されます。ユーザーは nginx.conf ファイルで巨大な共有メモリ領域を構成できますが、サーバーの起動後は追加のメモリがほとんど占有されていないことに気づくかもしれません。最初に開始され、メモリ ページが実際に使用されます。

空の共有メモリ領域

次の nginx.conf ファイルを例として取り上げます。このファイルは空の共有メモリ領域を割り当て、決して使用しません:

master_process on;
worker_processes 2;

events {
    worker_connections 1024;
}

http {
    lua_shared_dict dogs 100m;

    server {
        listen 8080;

        location = /t {
            return 200 "hello world\n";
        }
    }
}

lua_shared_dict ディレクティブ Dogs を通じて、 という名前の 100 MB の共有メモリ領域を構成します。そして、このサーバーに対して 2 つのワーカー プロセスを構成しました。構成内のこの dogs 領域には決して触れないため、この領域は空であることに注意してください。

次のコマンドを使用してこのサーバーを起動できます:

mkdir ~/work/
cd ~/work/
mkdir logs/ conf/
vim conf/nginx.conf  # paste the nginx.conf sample above here
/usr/local/openresty/nginx/sbin/nginx -p $PWD/

次に、次のコマンドを使用して、nginx プロセスが実行されているかどうかを確認します:

$ ps aux|head -n1; ps aux|grep nginx
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
agentzh   9359  0.0  0.0 137508  1576 ?        Ss   09:10   0:00 nginx: master process /usr/local/openresty/nginx/sbin/nginx -p /home/agentzh/work/
agentzh   9360  0.0  0.0 137968  1924 ?        S    09:10   0:00 nginx: worker process
agentzh   9361  0.0  0.0 137968  1920 ?        S    09:10   0:00 nginx: worker process

これらによって占有されるメモリ サイズ2 つのワーカー プロセスが近くに非常に大きいです。以下では、PID 9360 を使用した作業プロセスに焦点を当てます。 OpenResty XRay コンソールの Web グラフィカル インターフェイスでは、このプロセスが合計 134.73 MB の仮想メモリと 1.88 MB の常駐メモリを占有していることがわかりますが、これは上記と一致しています。記事内の ps コマンド出力はまったく同じ結果になります:

OpenResty と Nginx の共有メモリ領域での物理メモリ リソース (または RAM) の使用を検討しますか?

他の記事

「OpenResty と Nginx がメモリを割り当て、管理する方法」で紹介したとおり, 私たちが最も懸念しているのは、常駐メモリの使用量です。常駐メモリは、実際にはハードウェア リソースを対応するメモリ ページ (RAM 1 など) にマップします。この図から、ハードウェア リソースに実際にマッピングされているメモリの量は非常に少なく、合計でわずか 1.88MB であることがわかります。上記で構成された 100 MB の共有メモリ領域は、この常駐メモリのほんの一部にすぎません (詳細については、次の説明を参照してください)。

もちろん、共有メモリ領域の 100 MB はすべて、プロセスの合計仮想メモリに寄与します。オペレーティング システムは、この共有メモリ領域用に仮想メモリ アドレス空間を予約しますが、これは単なる記録であり、現時点では RAM リソースやその他のハードウェア リソースを占有することはありません。

EmptyNot Nothing

「プロセスのアプリケーション レベルのメモリ使用量の分類の詳細」図を渡すことができます。空の共有メモリ領域が常駐 (または物理) メモリを占有しているかどうかを確認します。

OpenResty と Nginx の共有メモリ領域での物理メモリ リソース (または RAM) の使用を検討しますか?

興味深いことに、このグラフにはゼロ以外の

Nginx Shm Loaded (ロードされた Nginx 共有メモリ) コンポーネントが表示されます。この部分はわずか 612 KB と小さいですが、それでも表示されます。したがって、空の共有メモリ領域は空ではありません。これは、Nginx が簿記の目的で、新しく初期化された共有メモリ領域にメタデータを配置したためです。これらのメタデータは、Nginx のスラブ アロケーターによって使用されます。

ロードおよびアンロードされたメモリ ページ

OpenResty XRay によって自動的に生成された次のグラフで共有を確認できます。メモリ領域で実際に使用されている (またはロードされている) メモリ ページの数。

OpenResty と Nginx の共有メモリ領域での物理メモリ リソース (または RAM) の使用を検討しますか?

dogs 領域にロードされている (または実際に使用されている) メモリ サイズは 608 KB であり、特別な # があることがわかりました。 ##ngx_accept_mutex_ptr Nginx コアによって accept_mutex 関数用に自動的に割り当てられます。 これら 2 つのメモリ部分を合わせたサイズは 612 KB で、これは上の円グラフに示されている

Nginx Shm Loaded

のサイズとまったく同じです。 <p>如前文所述,<code>dogs 区使用的 608 KB 内存实际上是 slab 分配器 使用的元数据。

未加载的内存页只是被保留的虚拟内存地址空间,并没有被使用过。

关于进程的页表

我们没有提及的一种复杂性是,每一个 nginx 工作进程其实都有各自的页表。CPU 硬件或操作系统内核正是通过查询这些页表来查找虚拟内存页所对应的存储。因此每个进程在不同共享内存区内可能有不同的已加载页集合,因为每个进程在运行过程中可能访问过不同的内存页集合。为了简化这里的分析,OpenResty XRay 会显示所有的为任意一个工作进程加载过的内存页,即使当前的目标工作进程从未碰触过这些内存页。也正因为这个原因,已加载内存页的总大小可能(略微)高于目标进程的常驻内存的大小。

空闲的和已使用的 slab

如上文所述,Nginx 通常使用 slabs 而不是内存页来管理共享内存区内的空间。我们可以通过 OpenResty XRay 直接查看某一个共享内存区内已使用的和空闲的(或未使用的)slabs 的统计信息:

OpenResty と Nginx の共有メモリ領域での物理メモリ リソース (または RAM) の使用を検討しますか?

如我们所预期的,我们这个例子里的大部分 slabs 是空闲的未被使用的。注意,这里的内存大小的数字远小于上一节中所示的内存页层面的统计数字。这是因为 slabs 层面的抽象层次更高,并不包含 slab 分配器针对内存页的大小补齐和地址对齐的内存消耗。

我们可以通过OpenResty XRay进一步观察在这个 dogs 区域中各个 slab 的大小分布情况:

OpenResty と Nginx の共有メモリ領域での物理メモリ リソース (または RAM) の使用を検討しますか?

OpenResty と Nginx の共有メモリ領域での物理メモリ リソース (または RAM) の使用を検討しますか?

我们可以看到这个空的共享内存区里,仍然有 3 个已使用的 slab 和 157 个空闲的 slab。这些 slab 的总个数为:3 + 157 = 160个。请记住这个数字,我们会在下文中跟写入了一些用户数据的 dogs 区里的情况进行对比。

写入了用户数据的共享内存区

下面我们会修改之前的配置示例,在 Nginx 服务器启动时主动写入一些数据。具体做法是,我们在 nginx.conf 文件的 http {} 配置分程序块中增加下面这条 init_by_lua_block 配置指令:

init_by_lua_block {
    for i = 1, 300000 do
        ngx.shared.dogs:set("key" .. i, i)
    end
}

这里在服务器启动的时候,主动对 dogs 共享内存区进行了初始化,写入了 300,000 个键值对。

然后运行下列的 shell 命令以重新启动服务器进程:

kill -QUIT `cat logs/nginx.pid`
/usr/local/openresty/nginx/sbin/nginx -p $PWD/

新启动的 Nginx 进程如下所示:

$ ps aux|head -n1; ps aux|grep nginx
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
agentzh  29733  0.0  0.0 137508  1420 ?        Ss   13:50   0:00 nginx: master process /usr/local/openresty/nginx/sbin/nginx -p /home/agentzh/work/
agentzh  29734 32.0  0.5 138544 41168 ?        S    13:50   0:00 nginx: worker process
agentzh  29735 32.0  0.5 138544 41044 ?        S    13:50   0:00 nginx: worker process

虚拟内存与常驻内存

针对 Nginx 工作进程 29735,OpenResty XRay 生成了下面这张饼图:

OpenResty と Nginx の共有メモリ領域での物理メモリ リソース (または RAM) の使用を検討しますか?

显然,常驻内存的大小远高于之前那个空的共享区的例子,而且在总的虚拟内存大小中所占的比例也更大(29.6%)。

虚拟内存的使用量也略有增加(从 134.73 MB 增加到了 135.30 MB)。因为共享内存区本身的大小没有变化,所以共享内存区对于虚拟内存使用量的增加其实并没有影响。这里略微增大的原因是我们通过 init_by_lua_block 指令新引入了一些 Lua 代码(这部分微小的内存也同时贡献到了常驻内存中去了)。

应用层面的内存使用量明细显示,Nginx 共享内存区域的已加载内存占用了最多常驻内存:

OpenResty と Nginx の共有メモリ領域での物理メモリ リソース (または RAM) の使用を検討しますか?

已加载和未加载内存页

現在、この dogs 共有メモリ領域には、ロードされたメモリ ページがさらに多くなり、アンロードされたメモリ ページの数も大幅に減少しました:

OpenResty と Nginx の共有メモリ領域での物理メモリ リソース (または RAM) の使用を検討しますか?

空のスラブと使用済みのスラブ

Nowdogs 共有メモリ領域に 300,000 の使用済みスラブが追加されました (ただし、常に事前に割り当てられる空の共有メモリ領域):

OpenResty と Nginx の共有メモリ領域での物理メモリ リソース (または RAM) の使用を検討しますか?

明らかに、各 lua_shared_dict 領域のキーと値のペアは、実際には、スラブ。

空きスラブの数は、空の共有メモリ領域にある前の数とまったく同じ、つまり 157 スラブです:

1OpenResty と Nginx の共有メモリ領域での物理メモリ リソース (または RAM) の使用を検討しますか?

誤ったメモリ リーク

上で説明したように、アプリケーションが実際にその内部のメモリ ページにアクセスするまで、共有メモリ領域は実際には物理メモリ リソースを消費しません。このため、ユーザーは、Nginx ワーカー プロセスの常駐メモリ サイズが、特にプロセスの開始直後に増加し続けているように見える場合があります。これにより、ユーザーはメモリ リークがあると誤って信じてしまう可能性があります。以下の図はそのような例を示しています:

1OpenResty と Nginx の共有メモリ領域での物理メモリ リソース (または RAM) の使用を検討しますか?

OpenResty XRay によって生成されたアプリケーションレベルのメモリ使用量の詳細グラフを見ると、Nginx の共有メモリ領域が明確にわかります。実際には、常駐メモリ領域の大部分を占有します。

1OpenResty と Nginx の共有メモリ領域での物理メモリ リソース (または RAM) の使用を検討しますか?

#このメモリの増加は一時的なもので、共有メモリ領域がいっぱいになると停止します。ただし、ユーザーが共有メモリ領域を非常に大きく構成し、現在のシステムで利用可能な物理メモリを超える場合には、依然として潜在的なリスクが存在します。このため、以下に示すように、メモリ ページ レベルでのメモリ使用量のヒストグラムに注意を払う必要があります。

1OpenResty と Nginx の共有メモリ領域での物理メモリ リソース (または RAM) の使用を検討しますか?

グラフの青い部分は、最終的にはプロセスが枯渇すると (つまり、赤色に変わり)、現在のシステムに影響を与えます。

HUP リロード

Nginx は、マスター プロセスを終了せずにサーバーの設定を リロードするための HUP シグナルの使用をサポートしています (ワーカー プロセスは引き続き正常に終了します)そして再起動します)。通常、Nginx 共有メモリ領域は、HUP のリロード後に元のデータを自動的に継承します。したがって、アクセスされた共有メモリ ページに元々割り当てられていた物理メモリ ページも保持されます。したがって、HUP のリロードによって共有メモリ領域の常駐メモリ空間を解放しようとすると失敗します。ユーザーは、代わりに Nginx の再起動または バイナリ アップグレード 操作を使用する必要があります。

特定の Nginx モジュールには、HUP がリロードされた後も元のデータを維持するかどうかを決定する権利があることを思い出してください。したがって例外もあるかもしれません。

結論

Nginx の共有メモリ領域が占有する物理メモリ リソースは、

nginx.conf## よりもはるかに小さい可能性があることを上で説明しました。ファイルで設定されます。これは、最新のオペレーティング システムの Demand Paging 機能のおかげです。一部のメモリ ページとスラブは、スラブ アロケータ自体に必要なメタデータを格納するために空の共有メモリ領域で引き続き使用されることを実証しました。 OpenRestyの高度なアナライザーを通じて一方、オンデマンド ページングの最適化により、メモリは一定期間増加し続けます。これは実際にはメモリ リークではありませんが、それでも一定のリスクが伴います。また、Nginx の HUP リロード操作では、通常、共有メモリ領域内の既存のデータが消去されないことについても説明しました。

推奨チュートリアル:

nginx チュートリアル

以上がOpenResty と Nginx の共有メモリ領域での物理メモリ リソース (または RAM) の使用を検討しますか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はsegmentfault.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。