¿Iniciar sesión a través de un FIFO, luego redirigir a un archivo?

8

Tengo una aplicación que debe registrar cada transacción. Cada mensaje de registro se vacía porque necesitamos tener un registro de lo que ocurrió antes de un bloqueo. Mis colegas y yo teníamos curiosidad acerca de cómo lograr los efectos de rendimiento del almacenamiento en búfer al tiempo que garantizamos que el mensaje de registro había abandonado el proceso.

Lo que se nos ocurrió es:

  • hacer un FIFO en el que la aplicación pueda escribir, y
  • redirigir el contenido de ese FIFO a un archivo normal a través de cat.

Es decir, lo que normalmente era:

app --logfile logfile.txt

es ahora:

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

¿Hay alguna trampa en este enfoque? Funcionó cuando lo probamos, pero queremos asegurarnos de que los mensajes lleguen al archivo de redireccionamiento incluso si la aplicación original falla.

(No tenemos el código fuente de la aplicación, por lo que las soluciones de programación están fuera de la cuestión. Además, la aplicación no escribirá en ella stdout, por lo que no se puede canalizar directamente a un comando diferente. Por sysloglo tanto, no es una posibilidad .)


Actualización: he añadido una recompensa. La respuesta aceptada no involucrará loggerpor la simple razón de que nologger es lo que he preguntado. Como dice la pregunta original, solo estoy buscando trampas al usar un FIFO.

chrisaycock
fuente
Parece haber una gran confusión en algunas de las respuestas hasta ahora. Como había destacado originalmente en mi pregunta, estoy buscando problemas con el enfoque de utilizar un FIFO como intermediario de registro . No estoy interesado en sugerencias alternativas que al menos no exploren las trampas de mi pregunta original.
chrisaycock
Si mi respuesta sobre el inicio de sesión en stdout no es una dirección que le interese, ¿podría eliminar "la aplicación también no escribirá en stdout, por lo que la tubería directamente a un comando diferente está fuera de la pregunta"?
nickgrim

Respuestas:

6

Tenga en cuenta que generalmente es necesario un quince en la programación donde la cantidad escrita puede superar la cantidad leída.

Como tal, una quinceañera no funcionará sin problemas como anticipa, pero resolvería su problema principal al presentar otra.

Hay tres posibles advertencias.

  1. Escribir en el fifo se bloquea indefinidamente si nada lee el otro extremo en la inicialización.
  2. El fifo tiene un ancho fijo de 64K por el cual si el búfer se llena en ese punto, las escrituras adicionales se bloquearán hasta que el lector se haya puesto al día.
  3. El guionista será asesinado con SIGPIPE si el lector muere o sale.

Esto significará que su problema (emular E / S con búfer en una escritura sin búfer) se resolverá. Esto se debe a que el nuevo 'límite' en su FIFO se convertirá en efecto en la velocidad de cualquier utilidad que escriba lo que está en la tubería al disco (que presumiblemente será una E / S almacenada).

Sin embargo, el escritor se vuelve dependiente de su lector de registros para funcionar. Si el lector deja de leer repentinamente, el escritor bloqueará. Si el lector sale repentinamente (digamos que se queda sin espacio en disco en su destino), el escritor SIGPIPE y probablemente salga.

Otro punto a mencionar es que si el servidor entra en pánico y el núcleo deja de responder, puede perder hasta 64k de datos que estaban en ese búfer.

Otra forma de solucionar esto será escribir registros en tmpfs (/ dev / shm en linux) y ajustar la salida a una ubicación de disco fija. Hay límites menos restrictivos en la asignación de memoria para hacer esto (¡no 64K, típicamente 2G!) Pero podría no funcionar para usted si el escritor no tiene una forma dinámica de volver a abrir archivos de registro (tendría que limpiar periódicamente los registros de tmpfs). Si el servidor entra en pánico en este método, podría perder MUCHOS más datos.

Matthew Ife
fuente
Esa es una buena información al respecto /dev/shm. También lo habíamos considerado, aunque se me había olvidado usarlo tail -f.
chrisaycock
4
mkfifo logfifo
cat logfifo &> logfile.txt &
app --logfile logfifo

¿Qué sucede cuando su cat logfifoproceso muere, alguien lo mata por accidente o alguien accidentalmente lo señala a la ubicación incorrecta?

Mi experiencia es que apprápidamente se bloqueará y colgará. He intentado esto con Tomcat, Apache y algunas pequeñas aplicaciones de construcción casera, y me encontré con el mismo problema. Nunca investigué muy lejos, porque una loggersimple redirección de E / S hizo lo que quería. Por lo general, no necesito la integridad del registro, que es lo que está tratando de perseguir. Y como dices, no quieres registrador.

Existe cierta discusión sobre este problema en Linux sin bloqueo de Fifo (registro bajo demanda) .

Stefan Lasiewski
fuente
Interesante. ¿Entonces la aplicación podría bloquearse de todos modos? Estamos pensando en tirar la toalla y ordenar Fusion IO en este momento.
chrisaycock
Darle una oportunidad. Para mí, este resultado sucedió rápidamente (en un entorno de prueba en hardware de baja especificación). Esto fue en Ubuntu y RedHat 5. No estoy seguro si FreeBSD, etc. tienen un comportamiento similar.
Stefan Lasiewski
2

Sus opciones están bastante limitadas por la aplicación, pero lo que ha probado funcionará.

Hacemos algo similar con barniz y varnishncsa para obtener registros en algún lugar útil para nosotros. Tenemos un quince y solo leímoslo con syslog-ng y lo enviamos a donde lo necesitamos. Manejamos alrededor de 50 GB y hasta ahora no hemos encontrado ningún problema con este enfoque.

cosa muy pegajosa
fuente
Genial, me alegra saber que no somos los únicos en pensar en esto.
chrisaycock
2

El entorno es CentOS y la aplicación escribe en un archivo ...

En lugar de enviar a un archivo normal, enviaría la salida a syslog y me aseguraría de que los mensajes de syslog se envíen a un servidor central, así como a nivel local.

Debería poder usar un script de shell como este:

logger -p daemon.notice -t app < fifo

También puede tomar la entrada (a logger) desde cato tail -fhacia una tubería:

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

El único problema es que no se diferencia en función de la importancia del mensaje de registro (todo es AVISO ), pero al menos se registra y también se envía fuera del host a un servidor central.

La configuración de syslog depende del servidor que esté utilizando. Hay rsyslogy syslog-ng(ambos muy capaces).

EDITAR : Revisado después de obtener más información del póster.

Mei
fuente
Los mensajes de registro se escriben en un archivo que podemos seleccionar, pero la aplicación no escribirá stdout. El sistema operativo es CentOS (había etiquetado la pregunta como Linux , pero supongo que es fácil pasarla por alto). Todos los mensajes son de igual importancia, por lo que no hay diferencia entre un aviso y un error en esta aplicación.
chrisaycock
¿No hay diferencia entre un aviso y un error? Oh enserio ? No hay diferencia entre Slow query detectedy Database halted?
Mei
(Actualicé la publicación.)
Mei
1

Usted escribe:

Además, la aplicación no escribirá en stdout...

¿Intentaste iniciar sesión en el "archivo" /dev/stdout? Eso podría permitirle hacer algo como:

app --logfile /dev/stdout | logger -t app
nickgrim
fuente
¿Es eso diferente de un FIFO? ¿Qué son las gotchas? No estoy buscando una alternativa, per se ; Estoy buscando información sobre si el enfoque que he enumerado es sólido. Eso es todo lo que me interesa.
chrisaycock
1
Sí, es diferente a un FIFO; Es esencialmente un archivo que está conectado a STDOUT. Entonces puede usar eso para iniciar sesión en STDOUT, y desde allí para syslog o similar. Está pensado como una solución a su problema original, pero es de esperar que sea más robusto que un FIFO debido a que tiene menos piezas móviles.
nickgrim
1

No tiene sentido escribir en un quince y luego hacer que otro proceso lo escriba en un archivo. Simplemente escriba directamente en el archivo normalmente y una vez que write()regrese, estará en manos del núcleo; aún lo escribirá en el disco si la aplicación falla.

psusi
fuente
Cada mensaje de registro se vacía : se trata de escrituras de bloqueo. No tenemos ningún control sobre eso ya que no tenemos el código fuente de la aplicación.
chrisaycock
@ chrisaycock, cierto ... entonces, ¿dónde está el problema?
psusi
Mis colegas y yo teníamos curiosidad acerca de cómo lograr los efectos de rendimiento del almacenamiento en búfer al tiempo que garantizamos que el mensaje de registro había abandonado el proceso.
chrisaycock
@chrisaycock, ohh, ¿entonces la aplicación actualmente usa O_SYNC o fsync()esperar a que cada escritura llegue al disco y NO QUIERES que eso suceda (arriesgando la pérdida en caso de un bloqueo del sistema)?
psusi
1
@chrisaycock, no tiene nada que ver con la interfaz de la unidad, normalmente solo significa que el núcleo lo ha copiado en la caché del sistema de archivos (y fuera de la aplicación). Como dije en mi respuesta originalmente, una vez que write()ha regresado, la aplicación puede bloquearse todo lo que quiera: los datos llegarán al disco siempre que el núcleo no se bloquee.
psusi