Maison  >  Article  >  Opération et maintenance  >  Explorer l'utilisation des ressources de mémoire physique (ou RAM) dans la zone de mémoire partagée d'OpenResty et de Nginx ?

Explorer l'utilisation des ressources de mémoire physique (ou RAM) dans la zone de mémoire partagée d'OpenResty et de Nginx ?

青灯夜游
青灯夜游avant
2020-08-29 10:16:142849parcourir

Les serveurs

Explorer l'utilisation des ressources de mémoire physique (ou RAM) dans la zone de mémoire partagée d'OpenResty et de Nginx ?

OpenResty et Nginx sont généralement configurés avec des zones de mémoire partagée pour stocker les données partagées entre tous les processus de travail. Par exemple, les modules standard Nginx ngx_http_limit_req et ngx_http_limit_conn utilisent des zones de mémoire partagée pour stocker les données d'état afin de limiter le taux de requêtes utilisateur et la simultanéité des requêtes utilisateur sur tous les processus de travail. Le module ngx_lua d'OpenResty fournit un stockage de dictionnaire de données basé sur la mémoire partagée au code Lua de l'utilisateur via lua_shared_dict.

Cet article explore la façon dont ces zones de mémoire partagée utilisent les ressources de mémoire physique (ou RAM) à travers plusieurs exemples simples et indépendants. Nous explorons également l'impact de l'utilisation de la mémoire partagée sur les métriques de mémoire des processus au niveau du système, telles que ps et VSZ dans les résultats d'outils système comme RSS.

Similaire à presque tous les articles techniques de ce site de blog, nous utilisons OpenResty XRay Ce produit de suivi dynamique est utilisé sans modification Effectuer en profondeur analyse et visualisation des composants internes des serveurs et applications OpenResty ou Nginx. Parce quemodule OpenResty. Cela garantit que l'état interne du processus cible que nous voyons à travers l'outil d'analyse OpenResty XRay est complètement cohérent avec l'état sans observateurs.

Nous utiliserons le

lua_shared_dict du module ngx_lua dans la plupart des exemples, car ce module peut être programmé avec du code Lua personnalisé. Le comportement et les problèmes que nous démontrons dans ces exemples s'appliquent également à d'autres zones de mémoire partagée dans tous les modules Nginx standard et modules tiers.

Pages dalle et mémoire

Nginx et ses modules utilisent généralement l'

allocateur de dalle dans le noyau Nginx pour gérer l'espace dans la zone de mémoire partagée . Cet allocateur de dalle est conçu pour allouer et libérer des blocs de mémoire plus petits dans une zone de mémoire de taille fixe.

Sur la base de slab, la zone de mémoire partagée introduira des structures de données de niveau supérieur, telles que des arbres rouge-noir et des listes chaînées, etc.

Une dalle peut être aussi petite que quelques octets ou aussi grande qu'elle s'étend sur plusieurs pages de mémoire.

Le système d'exploitation gère la mémoire partagée (ou d'autres types de mémoire) du processus en unités de pages mémoire.

Dans
les systèmes Linux, la taille par défaut des pages mémoire est généralement de 4 Ko, mais la taille exacte dépend de l'architecture et de la configuration du noyau Linux. Par exemple, certains x86_64 systèmes Linux ont des tailles de page mémoire pouvant atteindre 64 Ko. Aarch64

Nous verrons les détails de la zone de mémoire partagée des processus OpenResty et Nginx au niveau de la page mémoire et au niveau de la dalle respectivement.

La mémoire allouée n'est pas nécessairement consommée

Contrairement aux ressources comme les disques durs, la mémoire physique (ou RAM) est toujours une ressource très précieuse.
La plupart des systèmes d'exploitation modernes ont mis en œuvre une technologie d'optimisation appelée Demand paging (demand-paging), qui est utilisée pour réduire la pression sur les ressources RAM par les applications utilisateur. Plus précisément, lorsque vous allouez un gros bloc de mémoire, le noyau du système d'exploitation différera l'allocation réelle des ressources RAM (ou des pages de mémoire physique) jusqu'à ce que les données de la page mémoire soient réellement utilisées. Par exemple, si un processus utilisateur se voit allouer 10 pages mémoire, mais n'utilise que 3 pages mémoire, le système d'exploitation peut avoir mappé uniquement ces 3 pages mémoire sur le périphérique RAM. Ce comportement s'applique également aux zones de mémoire partagée allouées dans les applications Nginx ou OpenResty. L'utilisateur peut configurer une énorme zone de mémoire partagée dans le fichier nginx.conf, mais il peut remarquer qu'après le démarrage du serveur, presque aucune mémoire supplémentaire n'est occupée. Après tout, presque aucune page de mémoire partagée n'est réellement utilisée lors du premier démarrage. .

Zone de mémoire partagée vide

Prenons le fichier nginx.conf suivant comme exemple. Ce fichier alloue une zone de mémoire partagée vide et ne l'utilise jamais :

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";
        }
    }
}

On configure une zone de mémoire partagée de 100 Mo nommée via la directive lua_shared_dictdogs . Et nous avons configuré 2 processus de travail pour ce serveur. Veuillez noter que nous ne touchons jamais à cette dogs zone dans la configuration, cette zone est donc vide.

Vous pouvez démarrer ce serveur via la commande suivante :

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/

Utilisez ensuite la commande suivante pour vérifier si le processus nginx est en cours d'exécution :

$ 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

La taille mémoire occupée par ceux-ci deux processus de travail sont très grands à proximité. Ci-dessous, nous nous concentrons sur le processus de travail avec le PID 9360. Dans l'interface graphique Web de la console OpenResty XRay, nous pouvons voir que ce processus occupe un total de 134,73 Mo de mémoire virtuelle et 1,88 Mo de mémoire résidente, ce qui est cohérent avec les résultats ci-dessus. ps Les résultats des commandes dans l'article sont exactement les mêmes :

Explorer lutilisation des ressources de mémoire physique (ou RAM) dans la zone de mémoire partagée dOpenResty et de Nginx ?

Comme notre autre article "Comment OpenResty et Nginx allouent et gèrent la mémoire" Tel qu'introduit dans , ce qui nous préoccupe le plus est l'utilisation de la mémoire résidente. La mémoire résidente mappe en fait les ressources matérielles aux pages de mémoire correspondantes (telles que la RAM 1). Nous voyons donc sur l'image que la quantité de mémoire réellement mappée aux ressources matérielles est très faible, seulement 1,88 Mo au total. La zone de mémoire partagée de 100 Mo configurée ci-dessus ne représente qu'une petite partie de cette mémoire résidente (voir la discussion suivante pour plus de détails).

Bien sûr, les 100 Mo de la zone de mémoire partagée contribuent toujours à la mémoire virtuelle totale du processus. Le système d'exploitation réservera un espace d'adressage de mémoire virtuelle pour cette zone de mémoire partagée. Cependant, il ne s'agit que d'un enregistrement comptable et n'occupe aucune ressource RAM ou autre ressource matérielle pour le moment.

VidePas Rien

Nous pouvons transmettre le diagramme "Utilisation de la mémoire au niveau de l'application du processus Détails de classification" pour vérifier si la zone de mémoire partagée vide occupe la mémoire résidente (ou physique).

Explorer lutilisation des ressources de mémoire physique (ou RAM) dans la zone de mémoire partagée dOpenResty et de Nginx ?

Fait intéressant, nous voyons un composant Nginx Shm Loaded non nul (mémoire partagée Nginx chargée) dans ce tracé. La partie est petite, seulement 612 Ko, mais elle apparaît néanmoins. La zone de mémoire partagée vide n’est donc pas vide. En effet, Nginx a placé certaines métadonnées dans la zone de mémoire partagée nouvellement initialisée à des fins de comptabilité. Ces métadonnées sont utilisées par l'allocateur de dalle de Nginx.

Pages mémoire chargées et déchargées

Nous pouvons visualiser le partage à travers le graphique suivant généré automatiquement par OpenResty XRay Le nombre de pages mémoire réellement utilisées (ou chargées) dans la zone mémoire.

Explorer lutilisation des ressources de mémoire physique (ou RAM) dans la zone de mémoire partagée dOpenResty et de Nginx ?

Nous avons constaté que la taille de la mémoire qui a été chargée (ou réellement utilisée) dans la zone dogs est de 608 Ko, et il existe un ngx_accept_mutex_ptr spécial qui est automatiquement alloué par le noyau Nginx Utilisé par la fonction accept_mutex.

La taille combinée de ces deux parties de mémoire est de 612 Ko, ce qui correspond exactement à la taille de Nginx Shm Loaded indiquée dans le diagramme circulaire ci-dessus.

如前文所述,dogs 区使用的 608 KB 内存实际上是 slab 分配器 使用的元数据。

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

关于进程的页表

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

空闲的和已使用的 slab

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

Explorer lutilisation des ressources de mémoire physique (ou RAM) dans la zone de mémoire partagée dOpenResty et de Nginx ?

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

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

Explorer lutilisation des ressources de mémoire physique (ou RAM) dans la zone de mémoire partagée dOpenResty et de Nginx ?

Explorer lutilisation des ressources de mémoire physique (ou RAM) dans la zone de mémoire partagée dOpenResty et de Nginx ?

我们可以看到这个空的共享内存区里,仍然有 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 生成了下面这张饼图:

Explorer lutilisation des ressources de mémoire physique (ou RAM) dans la zone de mémoire partagée dOpenResty et de Nginx ?

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

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

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

Explorer lutilisation des ressources de mémoire physique (ou RAM) dans la zone de mémoire partagée dOpenResty et de Nginx ?

已加载和未加载内存页

Maintenant, dans cette dogs zone de mémoire partagée, il y a beaucoup plus de pages mémoire chargées, et le nombre de pages mémoire déchargées a également été considérablement réduit :

Explorer lutilisation des ressources de mémoire physique (ou RAM) dans la zone de mémoire partagée dOpenResty et de Nginx ?

Dalles vides et utilisées

Maintenantdogs 300 000 dalles utilisées ont été ajoutées à la zone de mémoire partagée (sauf dans la zone de mémoire partagée vide. Ces 3 sont toujours pré- dalles allouées) :

Explorer lutilisation des ressources de mémoire physique (ou RAM) dans la zone de mémoire partagée dOpenResty et de Nginx ?

Évidemment, chaque paire clé-valeur dans la zone lua_shared_dict correspond en fait directement à une dalle.

Le nombre de slabs libres est exactement le même que précédemment dans la zone mémoire partagée vide, soit 157 slabs :

1Explorer lutilisation des ressources de mémoire physique (ou RAM) dans la zone de mémoire partagée dOpenResty et de Nginx ?

Fausses fuites de mémoire

Comme nous l'avons démontré ci-dessus, la zone de mémoire partagée ne consomme pas réellement de ressources de mémoire physique jusqu'à ce que l'application accède réellement aux pages mémoire qu'elle contient. Pour cette raison, les utilisateurs peuvent constater que la taille de la mémoire résidente du processus de travail Nginx semble continuer à croître, en particulier immédiatement après le démarrage du processus. Cela peut amener les utilisateurs à croire à tort qu’il existe une fuite de mémoire. L'image ci-dessous montre un exemple :

1Explorer lutilisation des ressources de mémoire physique (ou RAM) dans la zone de mémoire partagée dOpenResty et de Nginx ?

En regardant le graphique des détails d'utilisation de la mémoire au niveau de l'application généré par OpenResty XRay, nous pouvons clairement voir la mémoire partagée de Nginx La zone en fait occupe la majeure partie de l'espace mémoire résident :

1Explorer lutilisation des ressources de mémoire physique (ou RAM) dans la zone de mémoire partagée dOpenResty et de Nginx ?

Cette croissance de la mémoire est temporaire et s'arrêtera lorsque la zone de mémoire partagée sera remplie. Cependant, lorsque l'utilisateur configure la zone de mémoire partagée pour qu'elle soit extrêmement grande, si grande qu'elle dépasse la mémoire physique disponible dans le système actuel, il existe toujours un risque potentiel. Pour cette raison, nous devons prêter attention à l'histogramme d'utilisation de la mémoire au niveau de la page mémoire comme indiqué ci-dessous :

1Explorer lutilisation des ressources de mémoire physique (ou RAM) dans la zone de mémoire partagée dOpenResty et de Nginx ?

La partie bleue du graphique peut éventuellement être utilisée par le épuisement du processus (c'est-à-dire devient rouge), ce qui aura un impact sur le système actuel.

Rechargement HUP

Nginx prend en charge le signal HUP pour recharger la configuration du serveur sans quitter son processus maître (le processus de travail se terminera toujours normalement et redémarrera ). Habituellement, la zone de mémoire partagée Nginx héritera automatiquement des données d'origine après le rechargement du HUP. Par conséquent, les pages de mémoire physique initialement allouées pour les pages de mémoire partagée auxquelles vous avez accédé seront également conservées. Par conséquent, les tentatives visant à libérer l’espace mémoire résident dans la zone de mémoire partagée via le rechargement HUP échoueront. Les utilisateurs doivent plutôt utiliser l'opération de redémarrage ou de mise à niveau binaire de Nginx.

Il convient de rappeler qu'un certain module Nginx a toujours le droit de décider s'il doit conserver les données d'origine après le rechargement de HUP. Il peut donc y avoir des exceptions.

Conclusion

Nous avons expliqué ci-dessus que les ressources mémoire physique occupées par la zone mémoire partagée de Nginx peuvent être bien inférieures à la taille configurée dans le fichier nginx.conf. Ceci est possible grâce à la fonctionnalité Demand Paging des systèmes d'exploitation modernes. Nous avons démontré que certaines pages et dalles de mémoire seront toujours utilisées dans la zone de mémoire partagée vide pour stocker les métadonnées requises par l'allocateur de dalle lui-même. Grâce à l'analyseur avancé de OpenResty XRay, nous pouvons vérifier le processus de travail nginx en cours d'exécution en temps réel et afficher la mémoire réelle utilisée ou chargée dans la zone de mémoire partagée, y compris les deux différents niveaux de pages et de dalles de mémoire.

D'un autre côté, l'optimisation de la pagination à la demande entraînera également une croissance continue de la mémoire pendant un certain temps. Il ne s’agit pas réellement d’une fuite de mémoire, mais cela présente tout de même un certain risque. Nous avons également expliqué que l'opération de rechargement HUP de Nginx n'efface généralement pas les données existantes dans la zone de mémoire partagée

Tutoriel recommandé : Tutoriel nginx

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer