viernes, 30 de mayo de 2008

Compresión HTTP

[Actualizado Oct'08 para corregir la parte de XML de configuración de Glassfish, el editor de Blogger me había cortado algunas cosas... :-(]

Es increíble que a día de hoy, año 2008, todavía un gran porcentaje de sitios y servicios web no tengan implementada ni la optimización más básica de todas: compresión de los contenidos servidos para aligerar las comunicaciones.

¿Por qué Google es el buscador más rápido? ¿por qué eBankinter es la banca online más rápida? Por mil cosas, y una de ellas es esta, claro. Y otra es la correcta gestión de las cabeceras de expiración de contenidos, pero eso puede que sea objeto de otra entrada... :-)

El protocolo HTTP lo soporta desde "casi siempre" y los navegadores también, incluso aquellos Netscape 4 e internet Explorer 4 de los que ya no nos acordamos y que tantos quebraderos de cabeza nos dieron hace unos añitos... Y el protocolo FTP también lo soporta (el llamado "Z Mode").

No voy a entrar en las posibilidades o particularidades, o en qué situaciones es más perjudicial que beneficioso porque al fin y al cabo consumimos recursos de procesamiento tanto en cliente como en servidor (por lo general en aplicaciones de Intranet en las que el ancho de banda es realmente alto). Pero, por lo general un fichero HTML normalito tiene una tasa de compresión con GZIP de entre 5:1 y 15:1. O lo que es lo mismo, una página de 200 KByes puede suponer que en realidad al navegador transmitamos sólo 20 KBytes. Y eso no sólo es importante en términos de visitantes unitarios, sino en términos de ancho de banda servidor en situaciones de concurrencia importante.

El protocolo HTTP, por ejemplo, define un diálogo muy sencillo entre el cliente (navegador) y el servidor, para el primero informe al segundo de sus "capacidades" y el segundo informe al primero de si el contenido está comprimido o no. Se hace a través de las cabeceras HTTP. Por ejemplo:

Header en la petición:
Accept-Encoding: gzip, deflate
Headers en la respuesta:
Vary: Accept-Encoding
Content-Encoding: gzip

¿Mola? Pues es trivial de implementar. Tanto el IIS como Apache Web Server (a través de mod_deflate o mod_gzip) como Glassfish, Tomcat, Orion, etc, etc, lo soportan.

Algunos ejemplos sencillos.

En Tomcat basta con añadir al tag <Connector> del fichero server.xml:
compression="on"
compressableMimeType="text/html,text/xml,text/css,text/javascript,text/plain,application/x-javascript,text/unknown,text/*"

En Glassfish basta con añadir lo equivalente en el domain.xml, dentro de las secciones <http-listener> que deseemos:
<property name="compression" value="on"/>
<property name="compressableMimeType" value="text/html,text/xml,text/css,text/javascript,text/plain,application/x-javascript,application/force-download,application/pdf,text/unknown,text/*"/>
En Apache es también trivial; por ejemplo en Apache 2.2 con mod_deflate la configuración sería:
AddOutputFilterByType DEFLATE text/html text/xml text/css text/javascript text/plain application/x-javascript application/force-download application/pdf text/unknown text/*
En iPlanet idem, además se permite tanto la carga de archivos "precomprimidos" y la compresión al vuelo. Para la compresión dinámica:
Output fn="insert-filter" filter="http-compression" type="text/*" vary="on"
Output fn="insert-filter" filter="http-compression" type="application/x-javascript" vary="on"
Output fn="insert-filter" filter="http-compression" type="application/force-download" vary="on"
Output fn="insert-filter" filter="http-compression" type="application/pdf" vary="on"
Y para soporte a archivos precomprimidos en iPlanet (deben existir las dos versiones, por ejemplo "prueba.js" y "prueba.js.gz"). Aquí habrá que hacerlo por cada extensión o similar (no es un filtro de salida sino un procesamiento previo, por ejemplo para aplicarlos a ficheros .js:
<Object ppath="*/*.js">
    PathCheck fn="find-compressed" check-age="on" vary="on"
</Object>


Hay unas cuantas opciones que considerar (como el tamaño mínimo de un fichero para que lo comprima, o si debe ignorar algunos navegadores) e instrucciones a los proxy caches para indicarle que este contenido es una variante (es decir que envíe la cabecera Vary: Accept-Encoding), pero básicamente ahí está...

Además de compresión por software, se puede utilizar hardware de aceleración especializado para ello, pero eso también será objeto de otra entrada...

Algunos links de interés:

Disclaimers


EN NINGUNO DE LOS CASOS LAS OPINIONES EXPRESADAS REFLEJAN LA POSICIÓN DE MI EMPRESA O DE NINGUNA DE LAS ORGANIZACIONES PARA LAS QUE COLABORE O HAYA COLABORADO. Los ejemplos o situaciones descritas son absolutamente inventadas y cualquier parecido con la realidad es mera coincidencia. (Siempre quise decir esa frase)

Este blog no tiene ningún fin lucrativo o comercial, sino meramente de bitácora y divulgativo. En las entradas del mismo pueden mencionarse -sin intención publicitaria ni vinculación alguna con sus propietarios- productos y/o marcas comerciales registradas por sus propietarios. Si en algún caso dicho propietario entiende que se están vulnerando sus derechos o prefiere que se elimine alguna referencia o comentario, ruego se pongan en contacto conmigo.

Del mismo modo, algunas de las imágenes incluidas pueden tener derechos de autor, de modo que de nuevo ruego a sus propietarios que se pongan en contacto conmigo si se desea retirar alguna de ellas.

Introducción

Bienvenido a mi espacio de reflexiones.

Mi objetivo con este blog es publicar mis reflexiones anónimas sobre mis áreas de interés, conforme vaya surgiendo la oportunidad dentro de mis responsabilidades profesionales.

Llevo unos cuantos años relacionado profesionalmente de una forma u otra con tecnologías internet, y fui uno de los pioneros en España en el uso de Java en general (JDK 1.0 y 1.1 allá por 1997) y de los EJB 1.0 en particular (allá por finales de 1999). Eso son más de 11 años a día de hoy.

Actualmente lidero un equipo técnico dedicado al desarrollo de soluciones servidor en Java EE, abarcando distintas líneas de actuación. A lo largo del tiempo van surgiendo nuevos problemas (o se van reitiendo patrones antiguos) relacionados con el rendimiento de los servidores, de la base de datos, del propio desarrollo Java EE, de HTTP/S, de SOAP, de los nuevos paradigmas RIA/AJAX... de modo que mi objetivo es ir recogiendo a modo de bitácora esos elementos.

Por experiencias pasadas, no pienso comprometerme a escribir con regularidad ni a hacerlo en profundidad. He tomado mucho de otros gracias a la gran telaraña, si además de servir de memoria personal estas reflexiones pueden servirles a otros, bienvenido sea!!!

Me encantaría escribir las entradas también en inglés, pero mis limitaciones hacen que lo haga sólo en el idioma de Cervantes...

Saludos,
--Server performance