Gestión de logs con Solandra III

lun, 15 ago 2011 by Foron

Pasamos a la tercera parte de la serie, en la que ya vamos a ver un ejemplo concreto de lo que puede ser un sencillo interfaz para la gestión de logs usando Solandra. Como siempre, todo el código y los ficheros de configuración más importantes están en Github.

Recordemos los objetivos que nos hemos marcado:

  • Ser capaces de gestionar un volumen muy importante de logs, con la máxima escalabilidad y disponibilidad.
  • Poder añadir los logs en el sistema de una forma sencilla.
  • Tener un interfaz web desde el que poder visualizar los datos.

Ya hemos hablado sobre la escalabilidad de Cassandra en los posts anteriores, así que no vamos a volver a entrar en este punto. Veamos los otros dos:

Inserción de datos en el sistema

Solandra es básicamente una adaptación de Solr, por lo que en realidad vamos a tratar conceptos propios de esta aplicación en lo que queda de post. Cuando veamos algo específico de Solandra, lo señalaré.

Uno de los elementos más importantes de la configuración del sistema es el schema; que viene a ser el lugar en el que se definen los atributos que forman cada "documento" (correo en este caso) que se quiere indexar. Como veremos más adelante, una vez creada esta estructura de datos, usaremos el comando curl para insertarla en el cluster a través de una url determinada. Además, Solandra permite trabajar con varios schemas diferentes de manera simultanea.

Simplicando un poco, el schema está compuesto por dos grandes bloques: La definición de los tipos de datos y la lista de atributos que forman cada documento.

Solr ofrece muchos tipos de datos ya creados de antemano: numéricos, texto, fechas, .... Por si esto fuera poco, la aplicación permite definir nuevos tipos siempre que se considere necesario. Para la gestión de logs de correo, por ejemplo, nos podría venir bien un tipo específico para las direcciones email:

  ...
  <fieldType name="email" class="solr.TextField" >
     <analyzer>
        <tokenizer class="solr.PatternTokenizerFactory" pattern="@" />
        <filter class="solr.LowerCaseFilterFactory" />
        <filter class="solr.TrimFilterFactory" />
     </analyzer>
  </fieldType>
  ...

Este tipo se basa en el TextField clásico, pero forma los tokens alrededor de la "@". De esta manera, facilitaremos las búsquedas tanto en base a la parte local de las direcciones como al dominio. Además, elimina los espacios y convierte las mayúsculas en minúsculas.

El siguiente paso es la definición de los atributos que componen cada documento, y que por supuesto van a ser de alguno de los tipos disponibles en el schema.

  <fields>
      <field name="id" type="uuid" indexed="true" stored="true" required="true" />
      <field name="in_from" type="email" indexed="true" stored="true" />
      <field name="in_size" type="tint" indexed="false" stored="true" />
      <field name="in_fentrada" type="tdate" indexed="true" stored="true" />
      <field name="in_to" type="email" indexed="true" stored="true" />
      <field name="in_to_adicional" type="email" indexed="true" stored="true" multiValued="true" />
      <field name="in_fsalida" type="tdate" indexed="true" stored="true" multiValued="true" />
      <field name="in_estado" type="string" indexed="false" stored="true" multiValued="true" />

      <dynamicField name="*" type="ignored" multiValued="true" />
  </fields>

Casi no hace falta explicar nada. En este sencillo ejemplo tenemos un identificador, un origen, un tamaño, una fecha de entrada y una fecha de entrega. Además, con cada mensaje vamos a guardar el estado de entrega para cada destino (pueden haberse realizado varios intentos, por ejemplo a causa del greylisting), y la lista de destinatarios adicionales para los que iba dirigido.

Obviamente, es una estructura limitada. En un entorno real se debería guardar mucha más información (antivirus, antispam, expansión de aliases, ...).

Y con esto ya lo tenemos. Sólo queda volcar el schema en el cluster:

  curl http://ip_cluster:8983/solandra/schema/correo --data-binary @/root/schema_correo.xml -H 'Content-type:text/xml; charset=utf-8'

Como hemos dicho, al igual que un "/schema/correo", se podría definir un "/schema/web", por ejemplo, y usarlos simultáneamente.

El volcado de datos

El volcado de datos se puede hacer de varias formas, pero vamos a limitarnos al uso de ficheros xml. Lo mejor es ver un ejemplo:

 <add allowDups="false">
    <doc>
       <field name="in_from">origenspam@example.com</field>
       <field name="id">b309842a-1cf7-11e0-9759-f896edbeae14</field>
       <field name="in_fentrada">2011-04-30T00:17:24Z</field>
       <field name="in_size">941</field>
       <field name="in_to">destino1@target.example.net</field>
       <field name="in_fsalida">2011-04-30T00:17:25Z</field>
       <field name="in_estado">0 - 192.168.10.24_accepted_message./Remote_host_said:_250_2.0.0_Ok:_queued_as_DF2BD74CA71/</field>
       <field name="in_to_adicional">destino1@target.example.net</field>
       <field name="in_to_adicional">destino2@target.example.net</field>
       <field name="in_to_adicional">destino3@target.example.net</field>
       <field name="in_to_adicional">destino4@target.example.net</field>
    </doc>
    <doc>
       <field name="in_from">origenspam@example.com</field>
       <field name="id">b30991b7-1cf7-11e0-9759-e819bb7f7b58</field>
       <field name="in_fentrada">2011-04-30T00:17:24Z</field>
       <field name="in_size">941</field>
       <field name="in_to">destino2@target.example.net</field>
       <field name="in_fsalida">2011-04-30T00:17:24Z</field>
       <field name="in_estado">0 - 192.168.10.24_accepted_message./Remote_host_said:_250_2.0.0_Ok:_queued_as_A945A21CD6B/</field>
       <field name="in_to_adicional">destino1@target.example.net</field>
       <field name="in_to_adicional">destino2@target.example.net</field>
       <field name="in_to_adicional">destino3@target.example.net</field>
       <field name="in_to_adicional">destino4@target.example.net</field>
    </doc>
    <doc>
       <field name="in_from">cliente1@example.net</field>
       <field name="id">b43de232-1cf7-11e0-9759-d71ac36a357f</field>
       <field name="in_fentrada">2011-04-30T00:04:41Z</field>
       <field name="in_size">6077</field>
       <field name="in_to">greylister@example.com</field>
       <field name="in_fsalida">2011-04-30T00:07:27Z</field>
       <field name="in_estado">0 - 172.16.0.14_does_not_like_recipient./Remote_host_said:_450_4.7.1_<cliente1@example.net>:
          _Sender_address_rejected:_Message_delayed_now.Retry_later,_please./Giving_up_on_172.16.0.14./</field>
       <field name="in_fsalida">2011-04-30T00:12:38Z</field>
       <field name="in_estado">1 - 172.16.0.14_does_not_like_recipient./Remote_host_said:_450_4.7.1_<cliente1@example.net>:
          _Sender_address_rejected:_Message_delayed_now._Retry_later,_please./Giving_up_on_172.16.0.14./</field>
       <field name="in_fsalida">2011-04-30T00:31:53Z</field>
       <field name="in_estado">2 - 172.16.0.14_does_not_like_recipient./Remote_host_said:_451_4.3.0_<greylister@example.com>:
          _Temporary_lookup_failure/Giving_up_on_172.16.0.14./</field>
       <field name="in_fsalida">2011-04-30T01:04:43Z</field>
       <field name="in_estado">3 - 172.16.0.14_accepted_message./Remote_host_said:_250_2.0.0_Ok:_queued_as_CB6A3D4A217/</field>
       <field name="in_to_adicional">greylister@example.com</field>
    </doc>
 </add>

El volcado, otra vez, es muy sencillo.

  curl http://ip_cluster:8983/solandra/correo/update -F stream.file=/tmp/volcado.xml

La conversión de logs desde el más que probable modo texto de syslog a xml, y de ahí al cluster de Solandra, queda fuera de esta serie de posts. De hecho, un servidor piensa que esto es lo realmente importante y difícil para llevar este proyecto a la práctica de una manera "seria".

El Interfaz

¿Qué mejor que un interfaz web para mostrar los datos que hemos almacenado en Solandra? ¡Sorpresa! la gente detŕas del proyecto ajax-solr ya ha hecho la mayoría del trabajo, así que sólo nos queda modificar un puñado de ficheros, algo de código JavaScript, y ya lo tendremos: Demo

Un detalle más: No queremos permitir el acceso directo a Solandra desde la web, así que necesitamos un proxy que filtre las consultas y las redirija al puerto de Solandra (tcp/8983 por defecto), y que en mi laboratorio escucha en localhost. En este caso, como casi siempre que quiero programar algún tipo de servicio para Internet sin dedicarle mucho tiempo, he usado node.js. Para este ejemplo, y por jugar un poco con GeoIP, he escrito un sencillo proxy que permite conexiones sólo si tienen como referer forondarena.net y si vienen desde Europa o América del Norte. Como no podría ser de otra forma, el código de este proxy también está disponible en Github.

(Nota: Esta demo es un Solr normal, pero el funcionamiento es idéntico al de Solandra).

Conclusiones

El "mercado" está lleno de soluciones de todo tipo que nos pueden ayudar en la gestión de logs. Hay aplicaciones comerciales, como Splunk, sistemas basados en software libre, como Solr, tecnología que nos puede permitir crecer "ilimitadamente", como Cassandra, Hadoop o Hbase, pero que requieren algo de trabajo; y también tenemos los mágnificos sistemas de bases de datos, como Mysql o Postgresql. ¿Cuál elegir?

En una primera fase, una buena base de datos con un sencillo interfaz web o un Solr estándar pueden servir perfectamente para gestionar todo tipo de logs. De hecho, tanto Mysql como Solr ofrecen alternativas para el particionado que pueden permitir este esquema en la segunda, tercera o cuarta fase.

Un buen consejo que escuche hace tiempo es el de "no arreglar lo que no está roto". Sólo deberíamos plantearnos el uso de tecnología que probablemente no conozcamos tan bien como las anteriores cuando realmente sea necesario. Llegado ese momento, adelante. Como siempre, la comunidad detrás del software libre es activa y está dispuesta a ayudar. Por si esto fuera poco, cada vez son más comunes las empresas que ofrecen servicios alrededor de este tipo de soluciones, y que pueden asesorarnos llegado el caso.


Comments