Terres dévastées

Vallée de montagne enneigée entre deux sommets rocheux, sous un ciel bleu

Catégorie : Informatique Page 1 of 2

Articles techniques, retours d’expérience et notes d’administration système, Linux et bases de données.

Dans les fichiers d’une base de données (1/3) : InnoDB, de MySQL à MariaDB

Une base de données relationnelle donne l’illusion de tables, de lignes et de colonnes. Sur le disque, il n’y a que des fichiers découpés en blocs de taille fixe. Comprendre comment ces blocs sont organisés explique beaucoup de comportements qui semblent mystérieux : pourquoi un fichier ne rétrécit pas après un DELETE, pourquoi une clé primaire en UUID ralentit les insertions, pourquoi un index secondaire coûte plus cher qu’on ne le pense, ou ce que protège vraiment le « doublewrite buffer ».

Cette série de trois billets ouvre le capot de trois moteurs : InnoDB (le moteur de stockage de MySQL et de MariaDB), PostgreSQL et Oracle. Le même fil conducteur les traverse : les fichiers, les pages, les lignes, et l’endroit où vivent les anciennes versions des données. Premier arrêt : InnoDB.

Le répertoire de données

Arborescence du datadir de MySQL 8
Les fichiers d’une instance MySQL 8 et leurs équivalents MariaDB.

Chaque fichier a un rôle précis :

  • ibdata1, le tablespace système. Historiquement, il contenait tout : tables, index, undo, dictionnaire. Aujourd’hui, il ne garde plus que le change buffer (sur MySQL) et, sur MariaDB, le doublewrite et parfois l’undo. Il ne rétrécit jamais : un ibdata1 de 50 Go gonflé par une vieille transaction le restera, et la seule façon de le réduire est un export complet suivi d’une réimportation ;
  • un fichier .ibd par table, grâce à innodb_file_per_table=ON (le défaut depuis MySQL 5.6). C’est ce qui permet de récupérer l’espace d’une table supprimée ou vidée (DROP, TRUNCATE), de déplacer une table seule, ou de restaurer un seul tablespace ;
  • les tablespaces d’undo (undo_001…) : les images d’avant des lignes modifiées, pour les ROLLBACK et pour la lecture cohérente des autres transactions ;
  • le journal redo : chaque modification de page y est décrite avant que la page elle-même soit écrite sur le disque. Après un crash, InnoDB rejoue ce journal ;
  • le doublewrite buffer, expliqué plus bas ;
  • les binlogs, qui n’appartiennent pas à InnoDB mais au serveur : ils décrivent les changements au niveau SQL, pour la réplication et la restauration à un instant donné.

Une base de données SQL (CREATE DATABASE shop) n’est rien d’autre qu’un répertoire. Les noms exacts des fichiers globaux varient : MySQL et MariaDB ont divergé sur le dictionnaire (MySQL 8 a remplacé les fichiers .frm par un dictionnaire transactionnel dans mysql.ibd, MariaDB a gardé les .frm), sur le redo et sur le doublewrite. Le format interne des pages, lui, est commun. Pour voir les tablespaces d’une instance :

-- MySQL 8
SELECT name, file_size, allocated_size FROM information_schema.INNODB_TABLESPACES;
-- MariaDB
SELECT name, file_size, allocated_size FROM information_schema.INNODB_SYS_TABLESPACES;

Pages, extents, segments

Hiérarchie tablespace, segments, extents, pages
Un tablespace est découpé en pages de 16 Ko, regroupées en extents de 1 Mo, attribués aux segments de chaque index.

L’unité de base est la page, de 16 Ko par défaut. Sa taille (innodb_page_size) est fixée à la création de l’instance et ne peut plus changer ensuite. Tout ce qu’InnoDB lit ou écrit, il le lit ou l’écrit par pages entières : lire une ligne de 100 octets, c’est charger 16 Ko en mémoire, dans le buffer pool.

Les pages sont regroupées en extents de 64 pages, soit 1 Mo. Allouer par extents plutôt que page par page garde les pages d’un même index physiquement proches, ce qui rend les lectures séquentielles efficaces.

Chaque index possède deux segments : un pour ses pages feuilles, un pour ses pages intermédiaires. Les séparer garde les feuilles (là où sont les données) contiguës, pour les parcours par plage. Pour ne pas réserver 1 Mo à chaque petite table, un segment reçoit d’abord jusqu’à 32 pages isolées, et ne passe aux extents complets qu’ensuite. C’est pourquoi une table vide occupe une centaine de kilo-octets, et pas plusieurs mégaoctets.

Les premières pages d’un .ibd sont réservées à la gestion de l’espace : la page 0 (FSP_HDR) décrit l’état des extents, la page 1 le bitmap du change buffer, la page 2 les « inodes » des segments. Sur MySQL 8, la page 3 contient la description de la table en JSON (SDI) et la racine de l’index cluster est en page 4. Sur MariaDB, qui garde des .frm, la racine est en page 3.

Anatomie d’une page

Structure d'une page d'index InnoDB de 16 Ko
Une page d’index : en-têtes, lignes, espace libre, répertoire et queue.

Chaque zone a une raison d’être :

  • Le FIL header est commun à toutes les pages, quel que soit leur type. Il contient la somme de contrôle, qui détecte une corruption à la lecture, et le LSN (Log Sequence Number) de la dernière modification. Après un crash, InnoDB compare ce LSN à celui de chaque entrée du redo : il ne rejoue que ce que la page n’a pas encore reçu. Les pointeurs vers les pages précédente et suivante relient toutes les pages d’un même niveau de l’arbre ;
  • l’INDEX header donne le niveau de la page dans l’arbre (0 pour une feuille), le nombre de lignes et l’identifiant de l’index auquel elle appartient ;
  • infimum et supremum sont deux fausses lignes, la plus petite et la plus grande possibles. Elles servent de début et de fin à la liste chaînée des lignes, ce qui simplifie le code d’insertion ;
  • les lignes sont écrites dans l’ordre où elles arrivent, mais chacune pointe vers la suivante dans l’ordre de la clé. Insérer au milieu ne déplace rien : il suffit de modifier deux pointeurs ;
  • le page directory part de la fin de la page et grandit vers le haut. Il contient un « slot » pour 4 à 8 lignes. Pour trouver une clé, InnoDB fait une recherche dichotomique dans ces slots, puis parcourt au plus quelques lignes de la liste chaînée ;
  • le FIL trailer répète une partie du LSN et de la somme de contrôle. Si le début et la fin de la page ne correspondent pas, la page n’a été écrite qu’à moitié.

Quand une page est pleine et qu’une ligne doit y entrer, InnoDB la coupe en deux (page split) et met à jour la page parente. Quand deux pages voisines descendent sous la moitié de leur remplissage, il peut les fusionner. Ces opérations sont coûteuses et laissent des pages à moitié vides : c’est la fragmentation.

Le doublewrite buffer : pourquoi écrire deux fois

Un disque garantit l’atomicité d’écriture de 512 octets ou 4 Ko, pas de 16 Ko. Si le serveur s’arrête au milieu de l’écriture d’une page, celle-ci peut se retrouver à moitié ancienne, à moitié nouvelle : une torn page. Le redo ne peut pas la réparer, car il décrit des modifications à appliquer sur une page cohérente. InnoDB écrit donc chaque page d’abord dans le doublewrite buffer, puis à son emplacement définitif. Après un crash, une page déchirée est remplacée par sa copie intacte, puis le redo s’applique. Sur un système de fichiers qui garantit lui-même des écritures atomiques de 16 Ko (ZFS, certains SSD), on peut le désactiver.

Une ligne

Format d'une ligne InnoDB DYNAMIC
Une ligne de l’index cluster et le détail de son en-tête.
  • Les colonnes cachées : DB_TRX_ID est l’identifiant de la dernière transaction qui a modifié la ligne, DB_ROLL_PTR pointe vers l’image précédente dans l’undo. Une transaction qui ne doit pas voir la modification suit ce pointeur pour reconstruire l’ancienne version ;
  • sans clé primaire, InnoDB utilise la première clé unique non nulle, ou à défaut ajoute une colonne cachée DB_ROW_ID de 6 octets, alimentée par un compteur global partagé par toutes ces tables. Définissez toujours une clé primaire ;
  • le bit « deleted » : un DELETE ne fait que marquer la ligne. Elle est réellement retirée plus tard par le purge thread, une fois qu’aucune transaction ne peut plus la voir ;
  • les NULL ne coûtent qu’un bit dans le bitmap : aucune place dans les données ;
  • les colonnes longues (TEXT, BLOB, gros VARCHAR) : une ligne doit tenir dans environ la moitié d’une page, pour qu’une page contienne au moins deux lignes. Au format DYNAMIC, une valeur trop longue part entière dans des pages de débordement, et la ligne ne garde qu’un pointeur de 20 octets.

L’index cluster : la table est un arbre

Index cluster et index secondaire InnoDB
Les feuilles de l’index PRIMARY contiennent les lignes ; un index secondaire contient la clé primaire.

C’est la décision de conception la plus importante d’InnoDB : la table est l’index de la clé primaire. Il n’existe pas de « tas » de lignes à côté : les lignes complètes sont stockées dans les feuilles d’un arbre B+ trié par clé primaire. Plusieurs conséquences pratiques en découlent :

  • une recherche par clé primaire descend l’arbre et trouve directement la ligne. Avec des pages de 16 Ko et une clé BIGINT, une page intermédiaire référence plus d’un millier de pages filles : trois niveaux suffisent pour des centaines de millions de lignes ;
  • une clé primaire croissante (AUTO_INCREMENT) ajoute toujours à droite de l’arbre : les pages se remplissent proprement, sans split au milieu. Une clé aléatoire (UUID v4) insère n’importe où, provoque des splits partout et laisse des pages à moitié pleines. Les UUID ordonnés dans le temps (UUID v7) évitent ce problème ;
  • un index secondaire ne contient pas l’adresse physique de la ligne mais sa clé primaire. Une recherche par index secondaire coûte donc deux descentes d’arbre. En contrepartie, déplacer une ligne lors d’un split ne demande pas de mettre à jour les index secondaires ;
  • une clé primaire longue est recopiée dans chaque index secondaire : une clé de 36 caractères multiplie la taille de tous les index ;
  • un index couvrant, qui contient toutes les colonnes dont la requête a besoin, évite la seconde descente : EXPLAIN affiche alors Using index.

Pourquoi le fichier ne rétrécit pas

Un DELETE massif libère de la place dans les pages, que les insertions suivantes réutiliseront, mais ne rend rien au système de fichiers. Pour récupérer l’espace, il faut reconstruire la table :

OPTIMIZE TABLE shop.orders;          -- équivaut, pour InnoDB, à ALTER TABLE … FORCE
-- MariaDB : vérifier l'espace réellement libérable avant
SELECT table_name, data_free/1024/1024 AS free_mb
FROM information_schema.tables WHERE table_schema='shop' ORDER BY data_free DESC;

La reconstruction copie toutes les lignes dans un nouveau fichier, compact, puis remplace l’ancien. Elle se fait en ligne sur les versions récentes, mais demande temporairement l’espace d’une seconde copie de la table.

Prochain billet : PostgreSQL, qui a fait le choix inverse sur presque tous ces points : une table en tas, des pages de 8 Ko, et des anciennes versions gardées dans la table elle-même.


Ce billet fait partie d’une série de notes d’administration système (tag « carnet d’admin »).
Série « Dans les fichiers d’une base de données », partie 1/3. · Billet suivant → (à paraître le 25/10) · English version

Le serveur qui ne revenait pas (1/3) : le symptôme

Un mardi soir, mise à jour classique du serveur de la maison : dnf update -y, une centaine de paquets dont un nouveau noyau et de nouveaux firmwares, puis reboot. D’habitude, la machine revient en moins d’une minute. Cette fois, rien. Pas de ping, pas de SSH, et surtout aucune réponse ARP sur le réseau local : vu du switch, la carte réseau n’existait plus.

Ce dernier détail compte. Une machine qui démarre mais dont un service plante répond toujours à l’ARP, car c’est le noyau qui répond, pas une application. L’absence d’ARP signifie que le noyau ne tourne pas, ou que la carte réseau n’est pas initialisée. Le problème est donc bas niveau : démarrage du noyau, initramfs, firmware de la carte mère, ou machine tout simplement éteinte.

Ce qu’on peut vérifier à distance

Avant de descendre devant la machine, j’ai rassemblé ce qui était visible depuis le reste du réseau :

arping -c 3 -I eth0 192.168.10.17     # aucune réponse : la carte réseau est muette
ip neigh show 192.168.10.17           # entrée FAILED dans la table ARP du voisin
  • Le SIEM (Wazuh) avait reçu un dernier événement de l’agent de la machine : « Wazuh agent stopped », à l’heure exacte du reboot. C’est le signe d’un arrêt propre, pas d’un crash. Un crash n’aurait laissé aucun message.
  • Les autres machines du réseau fonctionnaient normalement : le problème ne venait ni du switch ni du routeur.
  • La machine virtuelle hébergée sur ce serveur était tombée avec lui, ce qui est cohérent avec un hôte éteint.

Ce qu’il fallait voir à l’écran

Sans carte de gestion à distance (pas d’IPMI sur une carte mère grand public), la seule façon de savoir est de regarder l’écran. Voici la liste que je me suis préparée, de la cause la plus probable à la moins probable, pour ne pas improviser devant la console :

  • Bloqué dans GRUB ? Choisir le noyau précédent dans le menu. S’il démarre, le nouveau noyau ou son initramfs sont en cause. On le fixe ensuite avec grubby --set-default.
  • Shell d’urgence (dracut, emergency mode) ? journalctl -xb -p err montre pourquoi : volume LVM introuvable, entrée fstab invalide, module manquant dans l’initramfs.
  • Réétiquetage SELinux ou fsck en cours ? C’est long sur un gros disque. Il faut attendre, surtout ne pas couper.
  • Démarré mais sans réseau ? ip -br a et nmcli dev : une carte renommée ou « unmanaged » après une mise à jour arrive plus souvent qu’on ne croit.
  • Écran noir, ventilateurs qui tournent, rien ne bouge ? C’est le cas le plus déroutant. C’était le mien.

La machine a fini par repartir après une demi-heure, avec un appui long sur le bouton d’alimentation. Le système a démarré normalement sur le nouveau noyau, sans aucune erreur. Restait à comprendre ce qui s’était passé, alors que le journal système ne gardait que le démarrage en cours. C’est l’objet du billet suivant.


Ce billet fait partie d’une série de notes d’administration système (tag « carnet d’admin »).
Série « Le serveur qui ne revenait pas », partie 1/3. · Billet suivant → (à paraître le 25/10) · English version

Un /boot trop petit, des disques en miroir et des alertes : ménage de printemps… en octobre

Petite matinée de ménage sur le serveur de la maison (un Rocky Linux 10 sur une vieille carte mère ASRock). Au programme : une partition /boot devenue trop petite, des disques qui dormaient dans la machine et qu’il était temps de mettre en miroir, et des alertes Prometheus pour ne plus découvrir un disque mort par hasard. Retour d’expérience, commandes comprises.

Le problème : un /boot de 1 Go qui ne suffit plus

L’installeur de Rocky crée par défaut un /boot de 1 Go. Ça paraissait large… jusqu’à ce que je regarde ce qu’il contient vraiment :

$ ls -la --block-size=M /boot
152M initramfs-6.12.0-211.67.1.el10_2.x86_64.img
 39M initramfs-6.12.0-211.67.1.el10_2.x86_64kdump.img
 16M vmlinuz-6.12.0-211.67.1.el10_2.x86_64
159M initramfs-0-rescue-….img
 16M vmlinuz-0-rescue-…

Environ 217 Mo par noyau, plus 175 Mo pour l’image de secours. Avec installonly_limit=3 dans dnf.conf, on arrive à ~825 Mo sur 960. Et le piège : pendant une mise à jour, dnf installe le nouveau noyau avant de supprimer le plus ancien. Il y a donc brièvement quatre noyaux, et ça ne passe plus.

Pourquoi un initramfs de 152 Mo ? lsinitrd donne la réponse : une centaine de Mo de firmwares NVIDIA (GSP) tirés par le pilote nouveau, parce qu’il y a une GeForce GTX 1060 dans la machine. Je garde nouveau, donc la solution, c’est un /boot plus grand.

$ lsinitrd /boot/initramfs-$(uname -r).img | sort -k5 -n | tail -3
… 13371848 usr/lib/firmware/nvidia/tu102/gsp/gsp-570.144.bin.xz
… 25639648 usr/lib/firmware/nvidia/ga102/gsp/gsp-535.113.01.bin.xz
… 51324396 usr/lib/firmware/nvidia/ga102/gsp/gsp-570.144.bin.xz

Pourquoi ne pas simplement agrandir la partition ?

Parce que la partition qui suit /boot est le volume physique LVM du système, collé juste derrière. Et XFS ne sait pas rétrécir. Agrandir sur place voudrait dire déplacer tout le LVM (pvmove vers une nouvelle partition, supprimer l’ancienne, agrandir /boot dans le trou). Faisable à chaud, mais c’est beaucoup de manipulations sur le disque système d’une machine qui venait justement de rester plantée au redémarrage deux jours plus tôt.

Il restait plus de 300 Go libres en fin de disque. Plan plus simple : créer une nouvelle partition /boot de 2 Go dans cet espace libre, y copier l’ancien /boot, et réinstaller GRUB pour qu’il la prenne en compte. L’ancienne partition reste intacte et sert de filet de sécurité.

Migrer /boot vers une nouvelle partition (BIOS + GPT)

Le point important, c’est le mode de démarrage. Ici c’est du BIOS « legacy » sur une table GPT : GRUB loge son étage principal (core.img) dans la petite partition bios_grub de 1 Mo, et ce core.img contient en dur l’emplacement de /boot/grub2. Si on déplace /boot sans relancer grub2-install, GRUB continue de lire l’ancienne partition. En UEFI, ce serait le grub.cfg de l’ESP qu’il faudrait mettre à jour à la place.

$ parted -s /dev/sde unit MiB print free
Number  Start    End        Size       File system  Name  Flags
 1      1.00MiB  2.00MiB    1.00MiB                       bios_grub
 2      2.00MiB  1026MiB    1024MiB    xfs                bls_boot
 3      1026MiB  160406MiB  159380MiB                     lvm
        160406MiB  476940MiB  316534MiB  Free Space

À faire avec un accès à la console (écran/clavier ou IPMI), au cas où le premier redémarrage se passe mal.

1. Créer et formater la nouvelle partition

parted -s /dev/sde mkpart boot2 xfs 160406MiB 162454MiB   # 2 GiB -> sde4
mkfs.xfs -L boot2 /dev/sde4

2. Copier le contenu de /boot

mkdir -p /mnt/newboot
mount /dev/sde4 /mnt/newboot
cp -a /boot/. /mnt/newboot/      # -a conserve droits, liens et contextes SELinux
restorecon -R /mnt/newboot

3. Pointer /etc/fstab sur la nouvelle partition

cp -a /etc/fstab /etc/fstab.bak
blkid -s UUID -o value /dev/sde4          # nouvel UUID
# remplacer l'UUID de la ligne /boot par celui-ci, puis :
systemctl daemon-reload
umount /mnt/newboot
umount /boot && mount /boot
findmnt /boot                             # doit afficher /dev/sde4

4. Réinstaller GRUB et régénérer sa configuration

grub2-install /dev/sde                    # core.img pointe maintenant vers sde4
grub2-mkconfig -o /boot/grub2/grub.cfg

Les entrées de démarrage BLS (/boot/loader/entries/*.conf) donnent des chemins relatifs à la partition /boot. Elles fonctionnent donc telles quelles, et grubenv (le noyau par défaut) a été copié avec le reste.

5. Redémarrer et vérifier

reboot
findmnt /boot            # /dev/sde4
df -h /boot              # ~2 Go
grubby --default-kernel  # toujours le bon noyau

Retour arrière : l’ancienne partition sde2 n’a pas été touchée. Si GRUB tombe sur son invite de secours, on peut la réutiliser à la main :

grub rescue> set prefix=(hd0,gpt2)/grub2
grub rescue> set root=(hd0,gpt2)
grub rescue> insmod normal
grub rescue> normal

Ensuite, on remet l’ancien UUID dans /etc/fstab et on relance grub2-install /dev/sde. Une fois la nouvelle partition validée sur plusieurs redémarrages et mises à jour du noyau, l’ancienne n’est plus qu’un giga perdu, ce qui n’a rien de grave.

Au passage : mettre /data en miroir… quand il manque 4 Mo

La machine avait aussi des disques qui ne servaient à rien. J’en profite pour mettre en miroir /data (931 Go, bases de données, dépôts, sauvegardes) avec LVM RAID1. Sur le papier, c’est une seule commande, sans interruption :

lvconvert --type raid1 -m1 data/lvol0 /dev/sdd

En pratique, elle échoue. Un LV RAID1 a besoin, sur chaque disque, d’une petite zone de métadonnées (rmeta, une extent de 4 Mo) en plus de la copie des données. Or le LV d’origine occupait toutes les extents du premier disque (238 467 sur 238 467), et le second disque est exactement de la même taille. Il manque donc 4 Mo de chaque côté. Comme XFS ne rétrécit pas, impossible d’en libérer.

La solution consiste à faire le chemin dans l’autre sens :

  • créer sur le nouveau disque un LV une extent plus petit, le formater, et y copier /data à chaud (rsync -aHAXS --numeric-ids, qui conserve liens durs, ACL, xattrs/SELinux et fichiers creux) ;
  • arrêter les services qui utilisent /data (MariaDB, PostgreSQL, Forgejo…), faire un dernier rsync --delete, renommer les LV pour que le nouveau prenne le nom de l’ancien (le fstab n’a pas besoin de changer), puis redémarrer les services. Comptez un quart d’heure d’interruption ;
  • garder l’ancien LV un jour comme filet de sécurité, puis le supprimer et lancer lvconvert --type raid1 -m1 vers l’ancien disque, qui a maintenant la place pour sa zone rmeta. La synchronisation se fait en arrière-plan.

Leçon retenue : quand on crée un LV qu’on voudra peut-être mettre en miroir un jour, laisser quelques extents libres (-l 99%FREE plutôt que 100%FREE) évite tout ce détour.

Pour deux autres vieux disques identiques, sans données, c’est beaucoup plus simple. On crée directement un volume miroir et LVM réserve lui-même la place des métadonnées :

vgcreate bulk /dev/sda /dev/sdb
lvcreate --type raid1 -m1 -l 100%FREE -n lvol0 bulk
mkfs.xfs /dev/bulk/lvol0
# dans /etc/fstab, nofail : un vieux disque qui lâche ne doit pas bloquer le démarrage
/dev/bulk/lvol0  /bulk  xfs  defaults,nofail  0 0

Surveiller les miroirs avec Prometheus

Un miroir dont personne ne remarque qu’il a perdu un disque n’apporte pas grand-chose. Par défaut, LVM se contente d’écrire un avertissement dans les journaux, et node_exporter ne sait rien du RAID LVM (son collecteur mdadm ne couvre que md). J’ai donc ajouté un petit script, lancé toutes les deux minutes par un timer systemd, qui écrit l’état des LV RAID dans le répertoire du collecteur textfile de node_exporter (--collector.textfile.directory) :

lvs --noheadings --nosuffix --separator ';' \
    -o vg_name,lv_name,lv_health_status,raid_sync_action,copy_percent,raid_mismatch_count \
    --select 'segtype=~raid'

On obtient des métriques du genre lvm_raid_healthy (0 dès que lv_health_status n’est plus vide, par exemple partial quand un disque manque), lvm_raid_sync_percent et lvm_raid_mismatch_count. Le fichier est écrit dans un fichier temporaire puis renommé avec mv, pour qu’un scrape ne tombe jamais sur un fichier à moitié écrit. Quatre alertes s’appuient dessus :

- alert: LvmRaidDegraded        # un disque manque ou lâche
  expr: lvm_raid_healthy == 0
  for: 5m
- alert: LvmRaidNotInSync       # resynchronisation qui ne finit pas
  expr: lvm_raid_sync_percent < 100
  for: 12h
- alert: LvmRaidMismatches      # le dernier scrub a trouvé des différences
  expr: lvm_raid_mismatch_count > 0
- alert: LvmRaidMetricsStale    # le script lui-même ne tourne plus
  expr: time() - lvm_raid_textfile_last_run_seconds > 900

Côté matériel, des disques WD de 1, 2 et 3 To attendent sur l’étagère. Le jour où une alerte se déclenche : on remplace le disque, puis pvcreate, vgextend et lvconvert --repair, et LVM reconstruit le miroir à chaud.

En résumé

  • Un /boot de 1 Go, c’est juste dès qu’un pilote embarque de gros firmwares dans l’initramfs. Vérifiez avec lsinitrd.
  • Déplacer /boot vers une nouvelle partition est plus simple et moins risqué que d’agrandir l’existante. En BIOS/GPT, il ne faut pas oublier grub2-install.
  • LVM RAID1 a besoin d’une extent libre par disque pour ses métadonnées. Un LV en 100%FREE sur deux disques identiques ne peut pas être converti sur place.
  • Un miroir sans alerte, c’est une panne qui attend son heure. Le collecteur textfile de node_exporter se prête très bien à ce genre de petit ajout.

Ce billet ouvre une série de notes d’administration système (tag « carnet d’admin »).
English version

Hardening systemd services is hard.

Especially when you want to harden php-pm services with jit enabled and with nextcloud running… More infos later

php-fpm jit selinux opcache issue

I had issues when trying to enable jit for php-fpm, segfault, core dumpt etc…:
php-fpm[10021]: segfault at 55ad7b400600 ip 000055ad7b400600 sp 00007ffc04059b30 error 15 in zero (deleted)[55ad3b400000+80000000] likely on CPU 4 (core 0, socket 0)
php-fpm[27109]: mprotect() failed [13] Permission denied

After searching on google I found nothing really useful. But digging more made me find this:
https://github.com/php/php-src/issues/13400
Only for MacOS, still not useful

But the mprotect thing led me to that: https://lkml.org/lkml/2023/12/14/436
Interesting.
And to that: https://bugzilla.kernel.org/show_bug.cgi?id=218258
But THIS: https://bugzilla.redhat.com/show_bug.cgi?id=1380930
Yes, tried and it wxas the answer !!!!

so: setsebool -P httpd_execmem 1
systemctl restart php-fpm
issue solved !
#php-fpm #selinux #opcache #jit

Migration oracle

J’ai fini mon plus gros projet de l’année avant hier, je suis contente !

Optimiser php-fpm

https://geekflare.com/php-fpm-optimization/

ssmtp & letsencrypt

Problème:

Impossible d’envoyer des emails de mon mid vers mon back (serveur de mail) depuis que j’ai configuré le smtp avec un certificat letsencrypt.

En debug l’erreur est SSL not working: certificate verify failed (20)

un check des certificats donne ça:

openssl s_client -connect smtp.neurozone.fr:587 -starttls smtp -servername smtp.neurozone.fr
CONNECTED(00000003)
depth=0 CN = smtp.neurozone.fr
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0 CN = smtp.neurozone.fr
verify error:num=21:unable to verify the first certificate
verify return:1

La solution:

copier dans /etc/pki/ca-trust/source/anchors le certificat fullchain (chain.pem) de letsencrypt puis update-ca-trust extract

Plus d’erreur

Ce qu’un recruteur ne doit pas faire

Je viens d’avoir l’exemple type de ce qu’un recruteur/cabinet/chasseur de tête ne doit PAS faire pour approcher des personnes sur Viadeo ou LinkedIn:

Je reçois une proposition le 23 mars d’un cabinet de recrutement, où la personne dit: « J’ai regardé avec attention votre profil. Je ne sais pas si vous êtes à l’écoute du marché mais si vous l’êtes, j’aimerais pouvoir en discuter avec vous. Les profils Viadeo étant rarement à jour ou très incomplets, si vous avez un CV, il facilitera notre échange. »

Ce qui est dommage c’est que si cette personne avait réellement lu mon profil avec attention, elle aurait vu que :

– Je ne suis pas en recherche

– Je le dis très clairement à la troisième ligne – Mon profil est mis à jour régulièrement

– J’ai changé de travail l’année dernière.

Le message aurait pu encore passer, je peux comprendre que la plupart des recruteurs travaillent uniquement par mots clés. Simplement j’ai répondu le même jour que je n’étais pas intéressée, que je ne donnerais pas suite, etc. Rebondissement, aujourd’hui, je reçois le MÊME message, un copier-coller. Ce qui veut dire que non seulement elle n’a toujours pas pris la peine de lire mon profil mais qu’en plus elle n’a pas lu ma réponse.

Un cluster réparé !

Un cluster oracle qui avait explosé en vol, tout fonctionne maintenant mais ça a pris un mois !

Page 1 of 2

Propulsé par WordPress & Thème par Anders Norén