miércoles, 19 de febrero de 2014

Agrupando el log de rails con rsyslog

En teowaki el servicio de API lo tenemos balanceado entre dos servidores. Los objetivos principales de balancearlo, más que la carga, han sido la protección ante fallos y la posibilidad de hacer pruebas con diferentes configuraciones en los servidores.

Por ejemplo, inicialmente teníamos ruby 2.0 y unicorn en ambos servidores. En Navidad se publicó la versión 2.1, la instalamos en uno de los servidores y durante unas semanas tuvimos las dos versiones conviviendo en produccion. Las conclusiones fueron que más o menos el tiempo de respuesta bajaba un  20% y el consumo de memoría subía tambien sobre un 20%, así que decidimos instalarlo en las dos máquinas.

De la misma forma queremos hacer la prueba más adelante de usar diferentes servidores de aplicaciones simultáneamante (passenger / unicorn / puma) para ver cual funciona mejor. Tambien tenemos la intención de probar JRuby 9K en cuanto esté listo para producción.

El problema del balanceo es que el log queda distribuido y es imposible seguir una petición. Afortunadamente hay una solución muy simple usando rsyslog.

El primer paso es cambiar la configuración de rails para que use syslog, que viene por defecto en ruby, por lo que no es necesario instalar ninguna gema. Tan simple como añadir una línea en config/production.rb, donde 'teowaki-api' en nuestro caso indica el nombre que usaremos para la configuración de rsyslog.

$ more config/production.rb 
...
config.logger = Syslog::Logger.new 'teowaki-api'

A partir de ahora, el log en modo production lo procesará rsyslog.

Para configurar rsyslog, primero de todo editamos /etc/rsyslog.conf en el servidor que recibirá los logs (misc en nuestro caso), permitiendo acceso por TCP en el puerto 10514 y dando permiso de escritura solo a los servidores de API.

En la configuración por defecto de rsyslog el puerto de TCP es 514, pero en ubuntu hay un problema de privilegios al usar puertos por debajo del 1024, así que he usado el 10514

$ more /etc/rsyslog.conf
....
# provides TCP syslog reception
$ModLoad imtcp
$InputTCPServerRun 10514
...
$AllowedSender TCP, api01, api02

Ahora creamos el fichero de configuración cada servidor de API, donde le decimos que guarde el log en /var/log en local y que tambien lo mande al servidor misc al puerto 10514


$ more /etc/rsyslog.d/40-teowaki-api.conf 
if $programname == 'teowaki-api' then /var/log/rails/teowaki-api.log 
if $programname == 'teowaki-api' then @@misc:10514 
& ~  

Y finalmente, en el servidor misc le decimos que guarde el log, que le llegará desde los servidores de API, en /var/log

$ more /etc/rsyslog.d/40-teowaki-api.conf 
if $programname == 'teowaki-api' then /var/log/rails/teowaki-api.log 
& ~  

El número 40 indica la prioridad del fichero, para que se ejecute antes que el fichero 50-default.conf, tal y como explican en este blog, que fue el que me dio la idea para esta configuración

Y esto es todo, así de simple y ya tenemos la configuración completa.

La instalación en producción la he hecho con un par de roles de ansible, uno para los servidores de API y otro para el servidor que recibe los logs y además le he añadido logrotate, pero bueno, de ansible ya hablaremos en otro post...

Más adelante quiero probar otras soluciones más potentes como Kibana y logstash, pero por ahora ya tenemos el log centralizado, que era el objetivo inicial.



3 comentarios:

  1. Yo en breve me voy a poner a trastear con Kibana y logstash :)

    ResponderEliminar
  2. Diego, ¿que formato tienen tus logs de producción y como los procesas?

    ResponderEliminar
    Respuestas
    1. Formato estándar de rails, ahora mismo no los procesamos, solo los agrupamos.

      Para controlar errores y rendimiento usamos rollbar y newrelic.

      Eliminar