Accedi tramite un FIFO, quindi reindirizza a un file?


8

Ho un'applicazione che deve registrare ogni transazione. Ogni messaggio di registro viene scaricato perché dobbiamo avere una registrazione di ciò che è accaduto che ha portato a un arresto anomalo. I miei colleghi e io eravamo curiosi di sapere come ottenere gli effetti sulle prestazioni del buffering, garantendo al contempo che il messaggio di log avesse lasciato il processo.

Quello che ci è venuto in mente è:

  • creare un FIFO su cui l'applicazione può scrivere e
  • reindirizzare il contenuto di quel FIFO su un file normale tramite cat.

Cioè, ciò che era normalmente:

app --logfile logfile.txt

è ora:

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

Ci sono problemi a questo approccio? Ha funzionato quando lo abbiamo testato, ma vogliamo assolutamente assicurarci che i messaggi trovino la strada per il file di reindirizzamento anche se l'applicazione originale si arresta in modo anomalo.

(Non abbiamo il codice sorgente per l'applicazione, quindi le soluzioni di programmazione sono fuori questione. Inoltre, l'applicazione non scriverà stdout, quindi eseguire il piping direttamente a un comando diverso è fuori questione. Quindi syslognon è possibile .)


Aggiornamento: ho aggiunto una taglia. La risposta accettata non coinvolgerà loggerper il semplice motivo che nonlogger è quello che ho chiesto. Come afferma la domanda originale, sto solo cercando dei trucchi per usare un FIFO.


Sembra esserci un'immensa confusione in alcune delle risposte finora. Come avevo inizialmente evidenziato nella mia domanda, sto cercando dei metodi per utilizzare un FIFO come intermediario di registrazione . Non sono interessato a suggerimenti alternativi che non esplorino almeno i gotcha della mia domanda originale.
chrisaycock,

Se la mia risposta sulla registrazione a stdout non è una direzione che ti interessa, potresti forse rimuovere "Inoltre, l'applicazione non scriverà su stdout, quindi eseguire il piping direttamente a un comando diverso è fuori questione" dalla domanda?
Nickgrim,

Risposte:


6

Si noti che un quo è in genere necessario nella programmazione in cui la quantità scritta può superare la quantità letta.

Come tale un FIFO non funzionerà completamente senza problemi come previsto, ma risolverebbe il tuo problema principale mentre ne introduresti un altro.

Ci sono tre possibili avvertenze.

  1. La scrittura nel Fifo viene bloccata indefinitamente se nulla viene letto dall'altra parte durante l'inizializzazione.
  2. Il fifo ha una larghezza fissa di 64 KB, per cui se il buffer è riempito da quel punto, ulteriori scritture si bloccheranno fino a quando il lettore non ha raggiunto.
  3. Lo scrittore di pipe verrà ucciso con SIGPIPE se il lettore muore o esce.

Ciò significa che il problema (emulare l'I / O bufferizzato su una scrittura non bufferizzata) verrà risolto. Questo perché il nuovo 'limite' sul tuo FIFO diventerà in effetti la velocità di qualunque utilità stia scrivendo ciò che è nella pipe su disco (che presumibilmente sarà I / O bufferizzato).

Tuttavia, lo scrittore diventa dipendente dal lettore di log per funzionare. Se il lettore interrompe la lettura improvvisamente, lo scrittore bloccherà. Se il lettore esce improvvisamente (supponiamo che tu abbia esaurito lo spazio su disco sul tuo target) lo scrittore SIGPIPE e probabilmente uscirà.

Un altro punto da menzionare è se il server si blocca e il kernel smette di rispondere, potresti perdere fino a 64k di dati che si trovavano in quel buffer.

Un altro modo per risolvere questo problema sarà scrivere i log su tmpfs (/ dev / shm su linux) e adattare l'output a una posizione fissa del disco. Esistono limiti meno restrittivi per l'allocazione della memoria in questo modo (non 64 KB, in genere 2G!) Ma potrebbe non funzionare per te se il writer non ha un modo dinamico per riaprire i file di registro (dovresti pulire periodicamente i registri da tmpfs). Se il server va in panico con questo metodo, potresti perdere MOLTO più dati.


Ecco alcune buone informazioni in merito /dev/shm. Anche noi lo avevamo considerato, anche se mi era sfuggito di mente tail -f.
Chrisaycock,

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

Cosa succede quando il tuo cat logfifoprocesso muore, qualcuno lo uccide per sbaglio o qualcuno lo indirizza in una posizione sbagliata?

La mia esperienza è che appsi bloccherà e si bloccherà rapidamente. Ho provato questo con Tomcat, Apache e alcune piccole applicazioni integrate e ho riscontrato lo stesso problema. Non ho mai studiato molto lontano, perché loggero il semplice reindirizzamento I / O ha fatto quello che volevo. Di solito non ho bisogno della completezza della registrazione, che è ciò che stai cercando di perseguire. E come dici tu, non vuoi logger.

C'è qualche discussione su questo problema in Fifo Linux non bloccante (registrazione su richiesta) .


Interessante. Quindi l'app potrebbe bloccarsi comunque? Stiamo pensando di gettare la spugna e ordinare Fusion IO a questo punto.
chrisaycock,

Provaci. Per me, questo risultato si è verificato rapidamente (in un ambiente di test su hardware con specifiche basse). Questo era su Ubuntu e RedHat 5. Non sono sicuro che FreeBSD, ecc. Abbia un comportamento simile.
Stefan Lasiewski,

2

Le tue opzioni sono abbastanza limitate dall'app, ma ciò che hai testato funzionerà.

Facciamo qualcosa di simile con vernice e varnishncsa per ottenere i registri in qualche posto a noi utili. Abbiamo un fifo e ne abbiamo appena letto con syslog-ng e lo inviamo dove ci serve. Gestiamo circa 50 GB e finora non abbiamo riscontrato problemi con questo approccio


Bello, felice di sentire che non siamo i soli a inventare questo.
chrisaycock,

2

L'ambiente è CentOS e l'applicazione scrive in un file ...

Invece di inviare a un file normale, invierei l'output a syslog e mi assicurerei che i messaggi syslog vengano inviati a un server centrale e localmente.

Dovresti essere in grado di usare uno script di shell come questo:

logger -p daemon.notice -t app < fifo

Puoi anche prendere input (to logger) da cato da tail -fin una pipe:

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

L'unico problema è che non si differenzia in base all'importanza del messaggio di registro (tutto è AVVISO ) ma almeno viene registrato e inviato anche off-host a un server centrale.

La configurazione di syslog dipende dal server in uso. C'è rsysloge syslog-ng(entrambi molto capaci).

EDIT : rivisto dopo aver ottenuto ulteriori informazioni dal poster.


I messaggi di registro sono scritti in un file che possiamo selezionare, ma l'applicazione non scriverà stdout. Il sistema operativo è CentOS (avevo etichettato la domanda come linux , ma credo sia facile da perdere). Tutti i messaggi sono di uguale importanza, quindi non vi è alcuna differenza tra un avviso e un errore in questa applicazione.
Chrisaycock,

Nessuna differenza tra un avviso e un errore? Oh davvero ? Nessuna differenza tra Slow query detectede Database halted?
Mei,

(Ho aggiornato il post.)
Mei,

1

Scrivi:

Inoltre, l'applicazione non scriverà su stdout...

Hai provato ad accedere al "file" /dev/stdout? Ciò potrebbe consentirti di fare qualcosa del tipo:

app --logfile /dev/stdout | logger -t app

È diverso da un FIFO? Quali sono i gotcha? Non sto cercando un'alternativa, di per sé ; Sto cercando di capire se l'approccio che ho elencato è solido. Questo è tutto ciò che mi interessa.
Chrisaycock,

1
Sì, è diverso da un FIFO; è essenzialmente un file collegato a STDOUT. Quindi puoi usarlo per accedere a STDOUT, e da lì a syslog o simili. È inteso come soluzione al problema originale, ma si spera più robusto di un FIFO a causa del minor numero di parti mobili.
Nickgrim,

1

Non ha senso scrivere su un FIFO e quindi fare in modo che un altro processo lo scriva in un file. Basta scrivere direttamente sul file normalmente e, una volta write()restituito, è nelle mani del kernel; lo scriverà comunque sul disco se l'applicazione si blocca.


Ogni messaggio di registro viene cancellato : si tratta di scritture bloccanti. Non abbiamo alcun controllo su questo poiché non abbiamo il codice sorgente dell'applicazione.
chrisaycock,

@chrisaycock, giusto ... quindi dov'è il problema?
psusi,

I miei colleghi e io eravamo curiosi di sapere come ottenere gli effetti sulle prestazioni del buffering, garantendo al contempo che il messaggio di log avesse lasciato il processo.
chrisaycock,

@chrisaycock, ohh, quindi l'applicazione attualmente utilizza O_SYNC o fsync()per attendere che ogni scrittura colpisca il disco e non vuoi che ciò accada (rischiando la perdita in caso di crash del sistema)?
psusi,

1
@chrisaycock, non ha nulla a che fare con l'interfaccia del disco, normalmente significa che il kernel lo ha copiato nella cache del filesystem (e fuori dall'applicazione). Come ho detto nella mia risposta originariamente, una volta che write()è tornata, l'app può arrestare in modo anomalo tutto ciò che gli piace: i dati arriveranno sul disco finché il kernel non si arresta in modo anomalo.
psusi,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.