10 trucos sobre ficheros para mejorar y acelerar tu web

Hoy vamos a hablar un poco de los ficheros. Dejaremos para otro día las bases de datos, los sistemas de caché de memoria, gestión de colas..etc. Hoy toca ficheros. De lo fácil y lo difícil. ¿Contradictorio? No, querido lector. En absoluto. Lo veremos ahora. Muchas noches de investigación sobre este asunto merecen una entrada en el blog.

Qué facil resulta tener una estructura de ficheros donde tener el código, donde poder subir nuestras imágenes y poder ser accedido desde nuestras aplicaciones, donde poder dejar los vídeos, textos, configuraciones, los ficheros de log, otras aplicaciones, semáforos, sesiones... etc. Los ficheros lo soportan todo unificado. Y fácil de hacer. No nos preocupamos. En algún sitio estarán…

Usar ficheros es fácil y funciona bien, pero, con control!

Podemos complicarlo… ficheros que hacen de bloqueo, ficheros que solo pueden ser escritos por un proceso, ficheros compartidos.. ficheros..ficheros..ficheros. Casi todo es fichero.

Sin embargo, los ficheros puede ser el culpable silencioso de una falta de rendimiento. Una degradación que se propagará según se amplíe tu sistema. Un cáncer que debe ser atrapado a tiempo pues puede ser inevitable o muy caro de solucionar.

 

¿Ejemplos?

Un caso llamativo fue una compañía de reservas online de vuelos (enorme!) que sufrió semanas de fallos intermitentes en su web a la hora de reservar vuelos en una determinada fecha muy importante. Después de unos diez días un amigo que trabajaba allí nos consultó por casualidad (a cambio de unas sidras posteriores) si le podíamos echar una mano.

Las pistas existen, sólo hay que saber buscar

Nos conectamos remotamente y no tardamos mucho en encontrar el culpable. Un fichero de LOG que excedía el tamaño máximo soportado por el filesystem. Dicho log solo se activaba cuando la consulta a la BBDD excedía un tiempo (comúnmente llamado «slow query«). La operación interna daba error, y se propagó hacia el cliente en forma de «Operación no disponible» , pero con código http 200.

Ni sus compañeros de la compañía aérea, ni la gran consultora  que desarrolló el backoffice, ni nadie en aproximadamente 10 días pudo encontrar que pasaba. Pues bien, nosotros lo hicimos en poco mas de tres horas.

No fue fácil, pero un par de pistas ayudaron. La reserva que fallaba siempre eran del mismo tipo y en tiempos bajos de carga del sistema la reserva que no fallaba era muy rápida. Enmascarar el error 503 de origen a un error 200 para poder pintar la página corporativa de error nos retrasó un poco mas, y por supuesto, despistó al equipo original. Vaciar el fichero lo solucionó casi todo (las querys seguían tardando…)

Otro ejemplo lo encontramos al compartir sesiones de usuario. Aunque otro dia hablaremos de NFS -que es la maravilla hecha protocolo para compartir-, hay que tener mucho cuidado en dónde y cómo se generan.  Puedes encontrarte con un directorio de cientos de miles de ficheros en una única carpeta, y que el session start falle.

Un nombre de fichero bueno auto-descriptivo , para estar en una ruta de disco tal que /2013/01/02/ . Cuantos ficheros podra haber ahi? Si una rutina de codigo ha de localizar en disco ese fichero, sólo necesitará una traducción

 

¿ Entonces es mejor no usar ficheros ?

Al reves. «Simpliticy is the ultimate sophistication», decia da Vinci. «Cuanto mas simple mejor». Pero sin pasarse. Todo controlado. Es fácil si queremos hacerlo, y nos comerá en el futuro si somos indolentes. Sobre todo en sistemas de alto rendimiento o mucho volumen.

¿ Que podemos hacer en casos como éste ?

Aquí van nuestras recomendaciones fruto de la experiencia:

  1. Establecer políticas de LOG adecuadas y centralizadas:  Que todos los logs puedan dirigirse a un único sitio y manejados por una clase y configuración única. Eso nos permitirá no perder el control del crecimiento de ficheros.
  2. Controlar ficheros enormes: A que no nos cuesta nada tener un cron que revise el filesystem cada cierto tiempo buscando ficheros enormes? Esta chorrada puede servirnos de mucho en el futuro
  3. Pensar en estructuras eficientes: Dependiendo de lo que vayamos a almacenar, pensar en estructuras de varios niveles de profundidad (por ejemplo, año/mes/dia) que permitan su escalabilidad , el acceso rapido y la separación en caso de querer «congelar» ese contenido. También mejorará el backup (de esto hablaremos otro día)
  4. Ojo a las sesiones: ¿Necesitas las sesiones? Preguntatelo una vez mas. Quizás tu framework las esté usando sin que lo sepas. Si es asi, sobreescribe la clase y mira donde dejas esos ficheros. Recíclalas manualmente. ¿Por que? (ver punto siguiente..)
  5. Cuidado con los Garbages Collectors: Varios intérpretes, como PHP, dependiendo del framework tienen capacidad de borrar sesiones antiguas de forma autónoma. Eso implica que el proceso se leerá todos los ficheros para comprobar su edad. ¿Es necesario? No. ¿Y si tienes miles de ficheros en las carpetas? Tu proceso se resentirá. Y mucho.
  6. Vigila las rutas: Cada «stat» que hace tu proceso para localizar un fichero que devuelva un ENOENT (-1) son unos preciosos milisegundos que se pierden. Multiplica eso por cientos de veces que tienen las librerías. Cientos de milisegundos multiplicados ¿cuantos segundos son?
  7. Usa caché. Siempre que puedas vigila el nivel del caching del filesystem. Usa memcached. Usa eAccelerator. Todo en memoria irá mas rápido.
  8. ¿Otros sistemas no filesystem?. Has pensado en ReDIS? Quizás haya cosas que puedas poner ahí.
  9. Filesystem en memoria: ¿Has oido hablar del «tmpfs«?
  10. Vigila el storage: Los discos son los que se mueven cuando accedemos a los ficheros. A más ficheros más spin de disco. Si el disco hace tope , tú haces tope. Da igual que sea un sistema de almacenamiento enorme. Se puede saturar. Vigila las IOPS, haz tuning de los inodos y vigila las copias de seguridad.

Que os parece? Habéis tenido problemas similares?

¿Comentamos?

Carlos