Connectez-vous via un FIFO, puis redirigez-vous vers un fichier?

8

J'ai une application qui doit enregistrer chaque transaction. Chaque message de journal est vidé car nous devons avoir un enregistrement de ce qui s'est produit avant un crash. Mes collègues et moi étions curieux de savoir comment obtenir les effets de mise en mémoire tampon sur les performances tout en garantissant que le message du journal avait quitté le processus.

Ce que nous avons trouvé est:

  • créer un FIFO sur lequel l'application peut écrire, et
  • rediriger le contenu de cette FIFO vers un fichier standard via cat.

Autrement dit, ce qui était ordinairement:

app --logfile logfile.txt

est maintenant:

mkfifo logfifo
cat logfifo &> logfile.txt &
app --logfile logfifo

Y a-t-il des pièges à cette approche? Cela a fonctionné lorsque nous l'avons testé, mais nous voulons être absolument sûrs que les messages trouveront leur chemin vers le fichier de redirection même si l'application d'origine se bloque.

(Nous n'avons pas le code source de l'application, donc les solutions de programmation sont hors de question. De plus, l'application n'écrira pas stdout, donc il syslogn'est pas possible de diriger directement vers une autre commande. Il n'est donc pas possible .)


Mise à jour: j'ai ajouté une prime. La réponse acceptée n'impliquera paslogger pour la simple raison que ce loggern'est pas ce que j'ai demandé. Comme l'indique la question d'origine, je ne cherche que des pièges en utilisant un FIFO.

chrisaycock
la source
Jusqu'à présent, il semble y avoir une immense confusion dans certaines des réponses. Comme je l'avais initialement souligné dans ma question, je recherche des pièges à l'approche de l'utilisation d'un FIFO comme intermédiaire de journalisation . Je ne suis pas intéressé par des suggestions alternatives qui n'explorent pas au moins les pièges de ma question d'origine.
chrisaycock
Si ma réponse à propos de la connexion à stdout n'est pas une direction qui vous intéresse, pourriez-vous peut-être supprimer "De plus, l'application n'écrira pas sur stdout, il est donc impossible de diriger directement vers une autre commande" de la question?
nickgrim

Réponses:

6

Notez qu'un fifo est généralement nécessaire dans la programmation où le montant écrit peut dépasser le montant lu.

En tant que tel, le fifo ne fonctionnera pas de manière parfaitement fluide comme vous le prévoyez mais résoudrait votre problème principal tout en en introduisant un autre.

Il y a trois mises en garde possibles.

  1. L'écriture dans le fifo est bloquée indéfiniment si rien ne lit l'autre extrémité à l'initialisation.
  2. Le fifo a une largeur fixe de 64 Ko. Si le tampon est rempli par ce point, les écritures supplémentaires se bloqueront jusqu'à ce que le lecteur ait rattrapé le retard.
  3. Le rédacteur de pipe sera tué par SIGPIPE si le lecteur meurt ou sort.

Cela signifie que votre problème (émuler des E / S tamponnées sur une écriture non tamponnée) sera résolu. En effet, la nouvelle «limite» de votre FIFO deviendra en fait la vitesse de l'utilitaire qui écrit ce qui se trouve dans le tube sur le disque (qui sera vraisemblablement mis en mémoire tampon d'E / S).

Néanmoins, l'écrivain dépend de votre lecteur de journaux pour fonctionner. Si le lecteur arrête soudainement la lecture, l'écrivain se bloque. Si le lecteur se ferme soudainement (disons que vous manquez d'espace disque sur votre cible), le graveur SIGPIPE et probablement se fermera.

Un autre point à mentionner est que si le serveur panique et que le noyau cesse de répondre, vous risquez de perdre jusqu'à 64 Ko de données qui étaient dans ce tampon.

Une autre façon de résoudre ce problème sera d'écrire des journaux dans tmpfs (/ dev / shm sous linux) et de limiter la sortie à un emplacement de disque fixe. Il existe des limites moins restrictives sur l'allocation de mémoire pour ce faire (pas 64 Ko, généralement 2 G!), Mais pourrait ne pas fonctionner pour vous si le rédacteur n'a aucun moyen dynamique de rouvrir les fichiers journaux (vous devrez nettoyer régulièrement les journaux de tmpfs). Si le serveur panique dans cette méthode, vous pourriez perdre BEAUCOUP plus de données.

Matthew Ife
la source
Voilà quelques bonnes informations concernant /dev/shm. Nous avions également envisagé cela, même si cela m'avait glissé l'esprit tail -f.
chrisaycock
4
mkfifo logfifo
cat logfifo &> logfile.txt &
app --logfile logfifo

Que se passe-t-il lorsque votre cat logfifoprocessus meurt, que quelqu'un le tue par accident ou que quelqu'un le pointe accidentellement au mauvais endroit?

D'après mon expérience, la appvolonté se bloque et se bloque rapidement. J'ai essayé cela avec Tomcat, Apache et quelques petites applications maison et j'ai rencontré le même problème. Je n'ai jamais enquêté très loin, car loggerune simple redirection d'E / S a fait ce que je voulais. Je n'ai généralement pas besoin de l'exhaustivité de la journalisation, c'est ce que vous essayez de poursuivre. Et comme vous le dites, vous ne voulez pas d'enregistreur.

Il y a une discussion sur ce problème à Linux non bloquant fifo (journalisation à la demande) .

Stefan Lasiewski
la source
Intéressant. Donc, l'application pourrait bloquer de toute façon? Nous pensons à jeter l'éponge et à commander Fusion IO à ce stade.
chrisaycock
Essaie. Pour moi, ce résultat est arrivé rapidement (dans un environnement de test sur du matériel de faible spécification). C'était sur Ubuntu et RedHat 5. Je ne sais pas si FreeBSD, etc. ont un comportement similaire.
Stefan Lasiewski
2

Vos options sont assez limitées par l'application, mais ce que vous avez testé fonctionnera.

Nous faisons quelque chose de similaire avec vernis et varnishncsa aux journaux get quelque part qui nous sont utiles. Nous avons un fifo et lisons-le avec syslog-ng et l'envoyons où nous en avons besoin. Nous gérons environ 50 Go et n'avons rencontré aucun problème avec cette approche jusqu'à présent.

goo
la source
Cool, heureux d'apprendre que nous ne sommes pas les seuls à proposer cela.
chrisaycock
2

L'environnement est CentOS et l'application écrit dans un fichier ...

Au lieu d'envoyer dans un fichier normal, j'enverrais la sortie vers syslog et m'assurer que les messages syslog sont envoyés à un serveur central ainsi que localement.

Vous devriez pouvoir utiliser un script shell comme celui-ci:

logger -p daemon.notice -t app < fifo

Vous pouvez également prendre des entrées (vers logger) depuis catou depuis tail -fun tuyau:

tail -f fifo | logger ...
cat fifo | logger ...

Le seul problème est qu'il ne se différencie pas en fonction de l'importance du message de journal (tout est AVIS ) mais au moins il est enregistré et également envoyé hors hôte vers un serveur central.

La configuration de syslog dépend du serveur que vous utilisez. Il y a rsysloget syslog-ng(tous deux très capables).

EDIT : Révisé après avoir obtenu plus d'informations de l'affiche.

Mei
la source
Les messages du journal sont écrits dans un fichier que nous pouvons sélectionner, mais l'application n'y écrit pas stdout. Le système d'exploitation est CentOS (j'avais marqué la question sous Linux , mais je suppose que c'est facile à manquer). Tous les messages sont d'égale importance, il n'y a donc pas de différence entre un avis et une erreur dans cette application.
chrisaycock
Aucune différence entre un avis et une erreur? Oh vraiment ? Aucune différence entre Slow query detectedet Database halted?
Mei
(J'ai mis à jour le post.)
Mei
1

Vous écrivez:

De plus, l'application n'écrira pas sur stdout...

Avez-vous essayé de vous connecter au "fichier" /dev/stdout? Cela pourrait vous permettre de faire quelque chose comme:

app --logfile /dev/stdout | logger -t app
nickgrim
la source
Est-ce différent d'un FIFO? Quels sont les pièges? Je ne cherche pas d'alternative en soi ; Je cherche à savoir si l'approche que j'ai énumérée est robuste. C'est tout ce qui m'intéresse.
chrisaycock
1
Oui, c'est différent d'un FIFO; c'est essentiellement un fichier connecté à STDOUT. Vous pouvez donc l'utiliser pour vous connecter à STDOUT, et de là à syslog ou similaire. Il est conçu comme une solution à votre problème d'origine, mais, espérons-le, plus robuste qu'un FIFO en raison du nombre réduit de pièces mobiles.
nickgrim
1

Il ne sert à rien d'écrire dans un fifo et de demander à un autre processus de l'écrire dans un fichier. Il suffit d'écrire directement dans le fichier normalement et une fois le write()retour effectué, il est entre les mains du noyau; il l'écrira toujours sur le disque si l'application plante.

psusi
la source
Chaque message de journal est vidé : ce sont des écritures bloquantes. Nous n'avons aucun contrôle sur cela car nous n'avons pas le code source de l'application.
chrisaycock
@chrisaycock, c'est vrai ... alors où est le problème?
psusi
Mes collègues et moi étions curieux de savoir comment obtenir les effets de mise en mémoire tampon sur les performances tout en garantissant que le message du journal avait quitté le processus.
chrisaycock
@chrisaycock, ohh, donc l'application utilise actuellement O_SYNC ou fsync()pour attendre que chaque écriture atteigne le disque, et vous NE VOULEZ PAS que cela se produise (risque de perte en cas de panne du système)?
psusi
1
@chrisaycock, cela n'a rien à voir avec l'interface du lecteur, cela signifie normalement que le noyau l'a copié dans le cache du système de fichiers (et hors de l'application). Comme je l'ai dit dans ma réponse à l'origine, une fois que le write()est revenu, l'application peut planter tout ce qu'elle aime - les données arriveront sur le disque tant que le noyau ne plantera pas.
psusi