Archive of April 2010


Sat 24 Apr

Entendiendo y utilizando la Query Cache

La Query Cache nos permite almacenar el resultado de las query SELECT en una cache, de forma que si se piden los mismos datos repetidamente, únicamente tendrá que ejecutarlo una vez, devolviendo el resto de veces el resultado desde la memoria. Esto, como os podeis imaginar, mejora en gran medida el rendimiento de nuestro servidor. Pero hay que tener una serie detalles en cuenta al hacer uso de esta cache :)

  • Para mantener la consistencia en los resultados guarda una relación de las tablas a las cuales afectan la query, de forma que si una de esas tablas se ve modificada, la Query Cache se invalida.
  • La query se guarda tal y como la hemos escrito, esto es, para la Cache no sería lo mismo "SELECT Nom,Ap from t where id=2" que "SELECT nom,ap from T where id=2".
  • No se guardará el resultado de la query a no ser que esta no sera determinista. Por lo tanto, funciones como NOW(), CURRENT_DATE(), CURRENT_USER(), etc. no son candidatas a ser cacheadas.
  • La Query Cache añade overhead. Las queries de lectura deben leer o escribir de la cache y las de escritura deben borrar las caches asociadas a las tablas modificadas.
  • Durante una transacción, las caches asociadas a las tablas modificadas no se podrán usar hasta que no se haga COMMIT o ROLLBACK.

Podemos controlar como de eficiente es nuestra Cache mirando el estado de algunas variables de MySQL. Cuando una query se responde de la cache, el valor que aumenta es Qcache_hits. Por el contrario, si la query debe ejecutarse por no estar previamente cacheada, aumentaremos en uno el valor de Com_select. Por lo tanto, para conocer el ratio de hacierto podemos hacer uso de esta formula:

Qcache_hits / (Qcache_hits+Com_select)

Otra variable importante a tener en cuenta es Qcache_lowmem_prunes, que es un contador del número de queries sacadas de la caché por falta de memoria. Si el valor de esta variable sube demasiado a lo largo del tiempo, deberás ir pensando en aumentar el tamaño de la caché.

Los valores que debemos "tunear" en nuestro my.cf son los siguientes:

  • query_cache_type: puede tener el valor ON, OFF y DEMAND. Los dos primeros habilitan o deshabilitan la caché, mientras que el último cacheará una query siempre y cuando lleve el modificador SQL_CACHE

  • query_cache_size: es el tamaño de la caché. Debe ser un valor múltiplo de 1024 bytes

  • query_cache_min_res_unit: MySQL guarda las cachés en la memoria en pequeños bloques, como si de un sistema de ficheros se tratase. En un principio no sabe realmente el tamaño que va a tener el resultado de una query, por lo que según va enviando las filas al cliente, va cogiendo bloques. Los bloques tendrán como mínimo el tamaño aquí indicado. Este valor es importante para evitar la fragmentación de la memoria y así aprovecharla lo mejor posible

  • query_cache_limit: si un resultado supera el tamaño aquí indicado, no se cacheará. Pero recordad lo comentado en el punto anterior, MySQL no sabe a priori cuando ocupará, por lo que igualmente irá reservando bloques hasta llegar al query_cache_limit, momento en el cual los bloques escritos se liberarán de nuevo

Para evitar la fragmentación hay que elegir un valor correcto. Este no debe ser muy pequeño, ya que aunque evitaremos perder memoria, MySQL tendrá que ir cogiendo bloques constantemente. Ni muy grande, ya que si nuestras queries devuelven resultados pequeños tendremos bastante fragmentación. Una de las formas de tener un valor cercano al óptimo es saber la media de tamaño de las queries almacenadas. Para ello podemos aplicar la siguiente formula:

(query_cache_size – Qcache_free_memory) / Qcache_queries_in_cache

Esto es, la memoria usada entre el numero de queries en caché.

Para saber si realmente tienes la caché muy fragmentada, puedes hacerte una idea comprobando el número de bloques libres Qcache_free_blocks. Si el valor de esta variable está cercana a Qcache_total_blocks / 2, entonces tienes un grave problema de fragmentación.

MySQL también tiene su propio desfragmentador :) FLUSH QUERY CACHE moverá todos los bloques utilizados eliminando los espacios en blanco entre ellos.


Thu 15 Apr

Trasparencias del curso "Apache Avanzado"

  • Instalación desde código fuente
  • Instalación desde binarios
  • Directivas de configuración
  • SSL
  • Certificados de cliente
  • VirtualHost
  • NameVirtualHost
  • Balanceo de carga
  • Optimización del servicio
  • Mod_Cache
  • Mod_Rewrite
  • Mod_Security
  • Mod_Proxy
  • Apache Benchmark

Sat 10 Apr

Múltiples VirtualHost en SSL en una única IP (SNI)

Resumiendo mucho el funcionamiento de los VirtualHost en Apache, se puede decir que el cliente (nuestro navegador) envía al servidor el nombre del dominio al que deseamos acceder y Apache lo busca en sus configuraciones para entregarte la web. De esta forma en un solo servidor podemos tener alojados múltiples páginas web, cada una con su VirtualHost.

GET /blog/ HTTP/1.1
Host: miguelangelnieto.net
User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; es-ES; rv:1.9.0.6) Gecko/2009020911 Firefox/3.0.6
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: es,en-us;q=0.7,en;q=0.3
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive

Pero la cosa cambia si las webs deben ser transmitidas mediante HTTPS, esto es, estableciendo una conexión SSL. Gracias a esta tecnología es posible que todo el tráfico entre el servidor y nuestro navegador vaya cifrado y esta es la raíz del problema. Al tener todos los datos cifrados, el servidor no puede saber que dominio está pidiendo el navegador, por lo que los VirtualHost en base a nombres (dominios) pierden utilidad. Para paliar este problema, se ponían múltiples IPs en el servidor y se asignaba cada IP a un VirtualHost. De esta forma, cada web HTTPS tenia como destino una IP distinta y así el servidor era capaz de darte la web que estabas buscando. Esto es, se pasaba de tener VirtualHost por nombre a tenerlos por IP. Si tenías dos páginas web esto no era problema, pero si tenías 200... acelerarías la implantación de IPV6 y eso no es bueno ;)

Para solucionar este problema se publicó en 2006 el RFC 4366. En resumen, TLS pasaba a tener extensiones a nivel cliente y servidor. Una de las cuales permite que el cliente en el establecimiento de la conexión (antes de comenzar el cifrado) pueda indicar el dominio al que desea acceder. La que nos hace la magia es SNI. Para que esto funcione es necesario cumplir una serie de requisitos:

  • OpenSSL 0.9.8f o posterior con extensiones TLS (enable-tlsext)
  • Apache compilado con dicho OpenSSL
  • Navegadores Mozilla Firefox 2.0, Opera 8.0 Internet Explorer 7.0, Google Chome, Safari 3.2.1

Para activar esta extensión añadimos la siguiente línea a httpd.conf:

SSLStrictSNIVHostCheck on

Una vez hecho configuraríamos nuestros VirtualHost SSL como si fuesen los de toda la vida (sin SSL).

Listen 443
NameVirtualHost *:443
<VirtualHost *:443>
        ServerName test1.irontec.com
        ServerAlias test1.irontec.com
        DocumentRoot /var/www/test1
        Options FollowSymLinks
        <Directory /var/www/test1>
        AllowOverride All
        </Directory>
        ErrorLog /var/log/apache2/test1error.log
        CustomLog /var/log/apache2/test1access.log combined env=!client-ip-request
        SSLEngine on
        SSLCertificateFile /etc/ssl/test.pem
        SSLCertificateKeyFile /etc/ssl/test.key
</VirtualHost>
<VirtualHost *:443>
        ServerName test2.irontec.com 
        ServerAlias test2.irontec.com 
        DocumentRoot /var/www/test2
        Options FollowSymLinks
        <Directory /var/www/test2>
        AllowOverride All
        </Directory>
        ErrorLog /var/log/apache2/test2error.log
        CustomLog /var/log/apache2/test2access.log combined env=!client-ip-request
        SSLEngine on
        SSLCertificateFile /etc/ssl/test.pem
        SSLCertificateKeyFile /etc/ssl/test.key
</VirtualHost>

Si vemos el siguiente error en los logs de Apache es que nuestro navegador no es compatible:

[error] No hostname was provided via SNI for a name based virtual host

Y listo, ya puedes tener múltiples VirtualHost con SSL en una única IP :)