Dans l’article précédent, nous posions des bases et habitudes courantes pour se débrouiller avec Postfix quand on débute dans ce genre de pratique.

Aujourd’hui, on continue de parler de Postfix mais cette fois-ci nous abordons des notions un peu plus poussées, comme les démons et les files d’attente. Accrochez vous, c’est parti !

Comment ça fonctionne ?

Avant de s’amuser à traiter des files d’attente, il serait bon de comprendre comment sont orchestrées ces files et par qui.

Déjà, pour qu’on parle tous le même langage, je vous mets à disposition un diagramme des composants de Postfix et montrant leur manière de communiquer. On y retrouve le workflow presque complet. Presque, dans le sens où on a uniquement le service Postfix et pas de services secondaires comme un anti-spam ou un anti-virus:

Flux et composants de Postfix

Les rectangles bleus sont les services (ou démons), et les boites les files d’attente, au nombre de 5: hold, maildrop, deferred, active et incoming (non, on ne compte pas corrupt).

Globalement, ça se passe comme ça:

  1. Le script /usr/bin/postfix start lance le serveur.
  2. Puis le script lance /usr/libexec/postfix/master`, lui c’est le patron et il lancera les autres démons, uniquement si nécessaire.
  3. Les démons se terminent dès qu’ils ont fini ce qu’il ont à faire, sauf /usr/libexec/postfix/qmgr qui lui, reste actif tout le temps, il gère les différentes files d’attente.

On s’arrête un peu sur le patron de la file d’attente et les démons associés, j’ai nommé qmgr pour queue manager. Son patron à lui, c’est master, qui coordonne tous les démons de Postfix, il attend qu’une tâche arrive et les donne aux processus concernés, aussi, il effectue un contrôle sur le nombre d’instances qui s’exécutent concurremment (on revient sur la concurrence plus loin dans l’article).

Le démon qmgr

Le gardien des couloirs de Postfix. Il gère toutes les files d’attente de Postfix et orchestre le travail de chacun et notamment des démons local, smtp, lmtp et pipe en veillant à diverses choses comme la préservation des ressources et au maintien de la stabilité du système.

Par exemple, sur des messages dont le traitement n’aboutit pas, qmgr ordonne de placer ledit message dans la file deferred. Ainsi, en utilisant une file séparée, cela évite les incidences sur la file de délivrance des messages.

Le démon pickup

Il est responsable de la récupération des courriers locaux. En gros, sendmail pose les messages dans la file maildrop et pickup les récupère, effectue quelques vérifications et passe le message au démon cleanup.

Attention, pickup est mono-thread, il ne peut donc que livrer un message à la fois et sa vitesse se limite aux capacités de lecture/écriture du disque.

Le démon cleanup

Il fait les derniers traitements sur les messages, comme ajouter des entêtes manquants nécessaires, assurer les réécritures de l’enveloppe et des entêtes. Une fois fait, il met le résultat de tout ça dans la file incoming et indique au démon qmgr l’arrivée de nouveaux messages.

Les démons bouce et deferred

Eux, ils interviennent sur les messages qui n’ont pas pu être délivrés pour deux raisons possibles: une erreur non récupérable ou une destination inaccessible (même temporairement). Comme indiqué plus haut, ces erreurs sont reçues par qmgr qui ordonne par la suite le démon bounce et le démon defer (à ne pas confondre avec la liste !).

On va s’arrêter là pour les démons, ça devrait nous suffire pour comprendre la suite de l’article. Maintenant, on passe aux différentes files d’attente et ensuite on verra comment assurer la gestion de ces files via quelques outils.

La file Maildrop

Plus haut, nous avons parlé de pickup, ce gentil démon qui récupère les messages de la file maildrop pour les passer à son pote démon cleanup. Et bien la file maildrop sert à ça, elle met en attente les message soumis via sendmail mais pas encore déposés dans la file d’attente principale par pickup.

Si on regarde le diagramme plus haut, on voit qu’entre sendmail et maildrop, il y a postdrop. Il permet à n’importe quel utilisateur du système de soumettre un message dans la file d’attente maildrop, traité indifféremment des autres par pickup.

Si ça ne vous plait pas plus que ça, vous pouvez restreindre ce comportement grâce à une ligne de configuration nommée authorized_submit_users dans le fichier de configuration /etc/postfix/main.cf car par défaut, la valeur est à static:anyone.

Des messages peuvent être ajoutés à cette file même si Postfix ne fonctionne pas, il seront tout simplement pris en charge au prochain démarrage de Postfix.

La file active

En vert sur le diagramme plus haut. Accrochez vous, ça risque de piquer un peu !

La file active stocke les messages qui sont prêts à être envoyés. C’est qmgr qui gère la chose encore une fois. Seul un nombre réduit de messages est autorisé à entrer dans cette file par qmgr pour garder un taux de livraison stable. C’est l’algorithme du seau percé (leaky bucket en anglais) qui est appliqué pour garder ce taux constant. Son fonctionnement est très simple, surtout via cette analogie (d’où le nom de l’algorithme):

  • On considère un seau d’un volume quelconque (réduit, en ce qui concerne la file active)
  • La taille du seau correspond à la taille totale des informations qu’il peut contenir
  • Si le volume d’information dépasse la taille totale du seau, l’information en trop est rejetée. Dans notre cas, qmgr passera le message à l* file d’attente deferred

Forcément, si on remplit le seau autant qu’il se vide, c’est juste parfait, et le taux restera constant. Par contre, si on a une destination d’un message qui est considérée comme morte, et que la file s’allonge beaucoup trop (ce qu’on nomme congestion), qmgr enlèvera de la file tous les message ayant cette destination. Si cette destination est juste ralentie, qmgr garde les mails, mais la file se remplira plus vite qu’elle ne se vide. Dans ce cas, la seule manière de décongestionner la file est soit de réduire ce qui entre dans la file, soit d’accélérer ce qui en sort en agissant sur la latence (donc on a un peu de mal à agir dessus) ou en agissant sur la concurrence...

Pour faire simple, la concurrence c’est quand plusieurs entités souhaitent accéder à une ressource unique. En informatique générale c’est quand plusieurs processus souhaitent accéder à une ressource en même temps, le principe de l’exclusion mutuelle permet d’éviter de mettre des processus en concurrence via différents moyens, comme des verrous sur les ressources utilisées par exemple.

Pour Postfix, la concurrence se règle dans les fichiers de configuration. Par exemple (et je n’en donnerais qu’un car il y a énormément de paramétrages de ce type dans Postfix) la ligne de configuration local_destination_concurrency_limit qui est fixée par défaut à 2 indique le nombre maximum de livraisons parallèles via le transport local au même destinataire ou le nombre maximum de livraisons parallèles au même domaine local si la ligne local_destination_recipient_limit est supérieur à 1 (1 par défaut).

Ça va, ça suit ?

La file incoming (entrante)

Aussi nommée file entrante. On l’a rapidement abordé quand on parlait du démon cleanup, il réécrit ce qu’il faut (enveloppe et entêtes) et transmet à la file entrante. Le fichier est créé par l’utilisateur postfix (utilisateur système hein) avec des droits d’accès 0600, cleanup fait son boulot, et quand c’est prêt, il change les droits en 0700 et dit à son patron qmgr qu’il y a un nouveau venu dans la file incoming. Tant que les droits du fichier ne sont pas à 0700, qmgr, borné, part du principe que le fichier est encore en traitement par cleanup et par conséquent ne s’en occupe pas.

qmgr garde un oeil sur la file entrante et transmet les nouveaux messages à la file active uniquement si la limite de la file active n’est pas dépassée (20k messages). Si toutefois qmgr a trop de boulot, cleanup attendra la valeur du paramètre in_flow_delay dont la valeur par défaut est 1. Pour la désactiver il faut indiquer 0. Vous pouvez monter jusqu’à 10 secondes si vraiment la situation est mauvaise.

La file deferred (retardée)

Si à un instant T la livraison échoue pour une raison temporaire, le message est placé dans la file deferred. Cette file est guettée relativement souvent par qmgr. Quand je dis "souvent" c’est relatif, mais surtout lié au paramètre queue_run_relay initialisé à 300s par défaut (1000 dans Postfix 2.4).

Si toutefois qmgr est amené à scruter la file incoming et la file deferred en même temps, il respecte son principe d’économie de ressources mais d’efficacité, il scrute les deux en appliquant l’algorithme d’ordonnancement round-robin.

Le round-robin est un algorithme d’ordonnancement sans priorité. qmgr s’occupera de la file incoming pendant N temps puis de la file deferred pendant N temps et ainsi de suite, sans appliquer aucune priorité ou distinction.

Aussi, vous pouvez jouer avec le paramètre maximal_backoff_time qui, par défaut, attend 4000s entre deux tentatives de livraison d’un message présent dans la file deferred.

La file hold

Celle ci est un peu particulière dans le sens où c’est vous qui positionnez les messages dedans en mettant en place dans votre configuration de Postfix différentes politiques d’accès ou d’examens supplémentaire des entêtes ou du corps des messages par cleanup.

Cette file est un peu particulière car elle ne sera pas examinée pour essayer de livrer les messages qu’elle contient. Il faut que ça soit obligatoirement l’administrateur qui traite ces messages.

Bon, maintenant qu’on sait ce que sont les files d’attente, on va voir divers outils et commandes pour les traiter !

Commandes de traitement des files

Elles sont logiques, donc je ne vais pas lister tous les cas de figures, mais vous montrer des exemples que vous pouvez adapter simplement pour trouver ce que vous voulez:

Pour compter le nombre de mails dans la file active, on préférera utiliser la commande find, couplée à un wc comme ceci (à lancer en root):

find /var/spool/postfix/active -type f | wc -l

Pour compter deux files, comme la deferred et la hold, il suffit de cumuler les emplacements dans la commande comme ceci:

find /var/spool/postfix/deferred /var/spool/postfix/hold -type f | wc -l

L'outil Qshape

Inutile de le chercher, cet outil vient en installant Postfix. Cet outil montre une vue de la file d’attente sous forme de tableau (le temps en horizontal et les domaines de destination en vertical (ou les domaines d’expédition avec l’option -s)) et dispose de quelques options.

Pour voir le tableau de la file active:

qshape active

Je vous conseille de piper ces commandes avec des head (qui affiche 10 entrées par défaut) ou less. Par exemple, pour les 10 premières entrées de la file deferred, c’est comme ça:

qshape deferred | head

Postfix permet de base de visualiser la file d’attente via cette commande:

postqueue -e

L’avantage, c’est qu’elle vous donne l’ID des mails utilisé dans les commandes suivantes.

Postsuper

Lui, il gère les files d’attentes et peut interagir sur un mail en utilisant son ID de queue. Quelques exemples:

Effacer un mail actuellement dans une des queues:

postsuper -d ID_DU_MAIL

Déplacer un mail dans la file hold:

postsuper -h ID_DU_MAIL

Supprimer tous les mails de toutes les files d’attente (utilisé très rarement, tous les mails seront perdus définitivement).

postsuper -d ALL

Fin

Voilà en ce qui concerne les démons et les files d’attente ! Nous n’avons pas tout abordé car ça serait vraiment trop long, mais qui sait, peut-être dans un prochain article !

Article suivant Article précédent