6 votes

fio 3.23 core dumps lors du benchmarking de nombreux petits fichiers

On m'a demandé de venir fio résultats du benchmark pour cet ensemble de données de test : 1048576x1MiB . Ainsi, la taille globale est de 1TiB . L'ensemble contient 2^20 1MiB fichiers. Le serveur fonctionne CentOS Linux release 7.8.2003 (Core) . Il dispose d'une mémoire vive suffisante :

[root@tbn-6 src]# free -g
              total        used        free      shared  buff/cache   available
Mem:            376           8         365           0           2         365
Swap:             3           2           1

En fait, ce n'est pas un serveur physique. Il s'agit plutôt d'un conteneur Docker avec le processeur suivant :

Architecture:          x86_64
CPU op-mode(s):        32-bit, 64-bit
Byte Order:            Little Endian
CPU(s):                48
On-line CPU(s) list:   0-47
Thread(s) per core:    2
Core(s) per socket:    12
Socket(s):             2
NUMA node(s):          2
Vendor ID:             GenuineIntel
CPU family:            6
Model:                 85
Model name:            Intel(R) Xeon(R) Gold 6146 CPU @ 3.20GHz
[...]

Pourquoi Docker ? Nous travaillons sur un projet qui évalue la pertinence d'utiliser des conteneurs au lieu de serveurs physiques. Retour à la fio question.

Je me souviens que j'avais des problèmes avec fio de traiter un ensemble de données composé de nombreux petits fichiers auparavant. J'ai donc effectué les vérifications suivantes :

[root@tbn-6 src]# ulimit -Hn
8388608
[root@tbn-6 src]# ulimit -Sn
8388608
[root@tbn-6 src]# cat /proc/sys/kernel/shmmax
18446744073692774399

Tout m'a semblé correct. J'ai aussi compilé, au moment où j'écris ces lignes le dernier fio 3.23 avec GCC 9.

[root@tbn-6 src]# fio --version
fio-3.23

Voici le fichier de travail :

[root@tbn-6 src]# cat testfio.ini 
[writetest]
thread=1
blocksize=2m
rw=randwrite
direct=1
buffered=0
ioengine=psync
gtod_reduce=1
numjobs=12
iodepth=1
runtime=180
group_reporting=1
percentage_random=90
opendir=./1048576x1MiB

Note : de ce qui précède, on peut retirer ce qui suit :

[...]
gtod_reduce=1
[...]
runtime=180
group_reporting=1
[...]

Le reste MUST être conservée. En effet, selon nous, le fichier de travail doit être configuré de manière à émuler le plus fidèlement possible les interactions de l'application avec le stockage, même si l'on sait que le fichier de travail n'a pas encore été créé. fio != the application .

J'ai fait la première manche comme ça

[root@tbn-6 src]# fio testfio.ini
smalloc: OOM. Consider using --alloc-size to increase the shared memory available.
smalloc: size = 368, alloc_size = 388, blocks = 13
smalloc: pool 0, free/total blocks 1/524320
smalloc: pool 1, free/total blocks 8/524320
smalloc: pool 2, free/total blocks 10/524320
smalloc: pool 3, free/total blocks 10/524320
smalloc: pool 4, free/total blocks 10/524320
smalloc: pool 5, free/total blocks 10/524320
smalloc: pool 6, free/total blocks 10/524320
smalloc: pool 7, free/total blocks 10/524320
fio: filesetup.c:1613: alloc_new_file: Assertion `0' failed.
Aborted (core dumped)

OK, il est donc temps d'utiliser le --alloc-size

[root@tbn-6 src]# fio --alloc-size=776 testfio.ini
smalloc: OOM. Consider using --alloc-size to increase the shared memory available.
smalloc: size = 368, alloc_size = 388, blocks = 13
smalloc: pool 0, free/total blocks 1/524320
smalloc: pool 1, free/total blocks 8/524320
smalloc: pool 2, free/total blocks 10/524320
smalloc: pool 3, free/total blocks 10/524320
smalloc: pool 4, free/total blocks 10/524320
smalloc: pool 5, free/total blocks 10/524320
smalloc: pool 6, free/total blocks 10/524320
smalloc: pool 7, free/total blocks 10/524320
smalloc: pool 8, free/total blocks 8/524288
smalloc: pool 9, free/total blocks 8/524288
smalloc: pool 10, free/total blocks 8/524288
smalloc: pool 11, free/total blocks 8/524288
smalloc: pool 12, free/total blocks 8/524288
smalloc: pool 13, free/total blocks 8/524288
smalloc: pool 14, free/total blocks 8/524288
smalloc: pool 15, free/total blocks 8/524288
fio: filesetup.c:1613: alloc_new_file: Assertion `0' failed.
Aborted (core dumped)

Retour à la case départ :(

Je dois manquer quelque chose. Toute aide est la bienvenue.

3voto

Tom Points 101

( TL;DR paramètre --alloc-size pour avoir un grand nombre aide)

Je parie que vous pouvez simplifier ce travail et continuer à reproduire le problème (ce qui sera utile pour quiconque se penchera sur cette question, car il y aura moins d'endroits où chercher). Je pense que l'essentiel est que opendir et le fait que vous dites que le répertoire contient "2^20 fichiers de 1MiB"...

Si vous lisez la documentation de --alloc-size vous remarquerez qu'il est mentionné :

Si vous exécutez des travaux importants avec randommap activé, fio peut manquer de mémoire.

Par défaut, fio distribue uniformément les E/S aléatoires à travers un fichier (chaque bloc est écrit une fois par passe) mais pour ce faire, il doit garder la trace des zones qu'il a écrites ce qui signifie qu'il doit garder une structure de données par fichier. OK vous pouvez voir où cela mène...

Des pools de mémoire réservés à certaines structures de données (car elles doivent être partagées entre les tâches). Au départ, il y a 8 pools ( https://github.com/axboe/fio/blob/fio-3.23/smalloc.c#L22 ) et par défaut, chaque pool a une taille de 16 mégaoctets ( https://github.com/axboe/fio/blob/fio-3.23/smalloc.c#L21 ).

Chaque fichier qui effectue des E/S aléatoires nécessite une structure de données pour l'accompagner. Sur la base de vos résultats, nous pouvons supposer que chaque fichier nécessite l'allocation d'une structure de données de 368 octets + l'en-tête ( https://github.com/axboe/fio/blob/fio-3.23/smalloc.c#L434 ), ce qui donne un total de 388 octets. Comme le pool fonctionne par allocations de 32 octets ( https://github.com/axboe/fio/blob/fio-3.23/smalloc.c#L70 ), cela signifie que nous prenons en fait une bouchée de 13 blocs (416 octets) d'un pool par fichier.

Par curiosité, je me pose les questions suivantes :

  • L'exécutez-vous dans un conteneur ?
  • Quelle est la taille maximale que votre /tmp peut être ?

Je ne pense pas que les éléments ci-dessus soient liés à votre problème, mais il serait bon de s'en assurer.

Mise à jour : par défaut, docker limite la quantité de mémoire partagée IPC (voir aussi son --shm-size option). Il n'est pas clair si cela a été un facteur dans ce cas particulier, mais voir le commentaire "le travail original ne s'est arrêté qu'à 8 piscines" ci-dessous.

Alors pourquoi le réglage --alloc-size=776 aide ? En regardant ce que vous avez écrit, il semble étrange que vos blocs par pool n'aient pas augmenté, non ? Je remarque que vos pools ont atteint le maximum de 16 ( https://github.com/axboe/fio/blob/fio-3.23/smalloc.c#L24 ) la deuxième fois. La documentation pour --alloc-size dit ceci :

--alloc-size= kb Allouer des pools smalloc internes additionnels de taille kb en KiB . [...] La taille du pool est par défaut égale à 16MiB . [accentuation ajoutée]

Vous avez utilisé --alloc-size=776 ... 776 KiB n'est-il pas plus petit que 16 MiB ? Cela rendrait chaque pool plus petit que celui par défaut et pourrait expliquer pourquoi il a essayé d'augmenter le nombre de pools jusqu'au maximum de 16 avant d'abandonner lors de votre seconde exécution.

(2 ** 20 * 416) / 8 / 1024 = 53248 (but see the update below)

L'arithmétique ci-dessus suggère que chaque pool doit avoir une taille d'environ 52 mégaoctets si vous en avez 8, pour un total d'environ 416 mégaoctets de RAM. Que se passe-t-il lorsque vous utilisez --alloc-size=53248 ?

Mise à jour le nombre calculé ci-dessus était trop faible. Dans un commentaire, l'auteur de la question rapporte que l'utilisation d'un réglage beaucoup plus élevé de --alloc-size=1048576 était nécessaire.

(Je suis un peu préoccupé par le fait que le travail original ne s'est arrêté qu'à 8 pools (128 MiB). Cela ne suggère-t-il pas qu'essayer de passer à un neuvième pool de 16 MiB était problématique) ?

Enfin, la documentation de fio semble indiquer que ces structures de données sont allouées lorsque vous demandez une distribution particulière des E/S aléatoires. Cela suggère que si les E/S sont séquentielles ou si les E/S utilisent des décalages aléatoires mais ne doivent pas adhérer à une distribution, alors peut-être que ces structures de données n'ont pas besoin d'être allouées... Que se passe-t-il si vous utilisez norandommap ?

(A propos : blocksize=2M mais vos fichiers font 1MiB - est-ce correct ?)

Cette question est trop importante et trop spécialisée pour une réponse occasionnelle à une question de défaut de serveur et pourrait trouver une meilleure réponse dans le projet fio lui-même (cf. https://github.com/axboe/fio/blob/fio-3.23/REPORTING-BUGS , https://github.com/axboe/fio/blob/fio-3.23/README#L58 ).

Bonne chance !

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X