Postgres Transaction Wraparound

The short story

Si has llegado hasta aquí buscando el mensaje anterior, ya deberías saber que tienes un problema de los gordos, o sea que no te voy a entretener mucho.

Tu base de datos no ha perdido información, pero no acepta escrituras por lo que, probablemente, tu aplicación tiene una funcionalidad muy limitada. No te preocupes, no has perdido nada.

En resumen, te has encontrado con lo que se conocer como transaction wraparound. Básicamente, estás borrando o modificando tuplas de alguna tabla mucho más rápidamente de lo que el autovacuum de postgres puede limpiar. O quizás tienes el autovacuum desactivado.

Tienes dos alternativas evidentes: Ejecutar ese vacuum, como te indica el mensaje de error, o bien arrancar otra base de datos limpia con una copia de la actual. Personalmente te recomiendo la opción del backup. Mi propuesta es:

  1. Exportar la base de datos actual via pg_dump.
  2. Crear una base de datos nueva con los mismos roles y extensiones que la original.
  3. Restaurar la nueva base de datos usando pg_restore, con el volcado del paso 1.
  4. Configurar tu aplicación para que use la nueva base de datos.
  5. Configurar autovacuum correctamente para evitar el mismo problema en el futuro.

Una vez empiezas con el punto 3), quizás puedas seguir el consejo de postgres y ejecutar el vacuum en single mode. En nuestro caso, no funcionó. Usamos un servicio cloud que no nos permite arrancar en single mode pero, además, nuestra tabla problemática era tan grande que no había manera de pasar el vacuum. Simplemente, no acaba.

Enlaces interesantes:

Preventing Transaction ID Wraparound Failures
pg_dump
pg_restore

The long story

Continuará…


Probando Docker en Windows 10

Hoy quería ponerme con un pequeño proyecto para mejorar una de mis webs. He decidido montarlo como un microservicio separado, ya que se trata de una funcionalidad fácilmente separable y me ha aparecido un pequeño problema logístico. Tengo Windows 10 instalado en casa. Generalmente virtualizo máquinas con vmware player para estas cosas, pero como en Waynabox llevamos un tiempo usando Docker  y le he cogido el gustillo, he pensado que podría probar la nueva implementación de Docker para Windows 10.

Y aquí tenéis mis primeras experiencias en lo que sería una guía para novatos, escrita por un novato.

Lo primero, la documentación oficial

Por algún lado hay que empezar, y lo mejor es leerse la página oficial de Docker al respecto, Getting Started with Docker for Windows.

Aquí encontramos algunas advertencias sobre la versión de Windows necesaria y la necesidad de activar Microsoft Hyper-V. De momento voy a ignorar estos avisos, (mi windows está a la última), espero que no explote en la cara dentro de unos minutos.

Paso 1: Instalando Docker

Lo típico, Descargar docker del enlace oficial, botón siguiente, siguiente, etc… Docker instalado y un aviso de que de Hyper-V no está instalado en mi ordenador y la pregunta de si quiero que Docker lo active por mi… Hasta ahora muy limpio todo, si señor.

hyper-v-not-installed-by-docker

Reinicio el ordenador y vuelvo en un minutos…. ¡Fantástico! Docker está instalado y tengo un icono en la bandeja del sistema que me dice que está corriendo.

De momento el invento funciona muy bien.

Paso 2: Probando Docker en Windows

Seguimos con la guía de instalación, abro una consola de sistema (Recordatorio: He de probar bash para Windows,…) y ejecuto docker run hello-word.

¡Genial! Parece que todo funciona. Ha sido tan fácil que incluso me da vergüenza estar escribiendo este tutorial.

Probaremos algo más ambicioso, descargar un ubuntu y ejecutar bash en modo interactivo dentro de ese ubuntu.

Docker se descargará una imagen de ubuntu en pocos segundos y ejecutará bash dentro de el. Hacemos un ls y en efecto, funciona, exactamente igual que en linux. Estoy corriendo en un windows un container docker que tiene un bash corriendo en ubuntu perfectamente funcional. Para cerrarlo, simplemente ejecutamos exit, lo que cerrará el bash. Al estar en modo interactivo ( parámetro -it), el contenedor de docker se cerrará. Si volvemos a lanzarlo veremos que arranca infinitamente más rápido, ya que ahora no necesita descargar la imagen de ubuntu.

¡Docker mola mucho!

Paso 3: Montando contenedores docker

Bueno.. a partir de ahora habría que seguir por lo obvio, exactamente igual que en linux, crear un archivo de configuración con los contenedores que nos interesen, compartir una unidad de disco entre el contenedor y el host si queremos tocar código de manera fácil, o exportar los logs, mapear los puertos internos y externos, etc..

De todo eso se trata en la propia guía de docker Get Started with Docker y se escapa un poco de lo que pretendía ser este artículo.

Por lo que a mi respecta, me voy a buscar una buena imagen para correr apache con php7 y posiblemente otra para un mongodb o un redis (aún no tengo claro) y crearé un docker compose que me lance las 2 y las configure adecuadamente.

Acelerando WordPress con Varnish

Es sabido que WordPress no es un CMS especialmente rápido. Su inmenso ecosistema de plugins y la amplia posibilidad de personalización que permiten sus temas hace que muchas instalaciones de wordpress tiendan fácilmente a generar un elevado número de peticiones a la base de datos y/o a ejecutar mucho código php en cada petición.

Por suerte, WordPress cuenta con un sistema muy decente de cacheo que permite evita realizar cálculos idempotentes en cada una de las peticiones. Y algunos de esos plugins, incluso permiten comunicarse con proxies inversos como varnish que permiten cachear el resultado de las páginas.

En este artículo os vamos a explicar como configurar un varnish con WordPress. Para ello usaremos el plugin w3 total cache, aunque existen otras opciones posibles.

Instalando W3 total Cache

W3 Total Cache es uno de los plugins que siempre tengo en todos mis wordpress. Se integra perfectamente en WordPress y es capaz de realizar multitud de operaciones, por ejemplo cachear las consultas a la base de datos o los objetos internos de wordpress en diferentes contenedores de cache, por ejemplo disco, APC o un memcache o similar.

También es capaz de minizar el código o combinar javascripts y css.

Es un plugin muy recomendable aunque no vayamos a usar varnish.  Lo que lo hace muy interesante de cara a varnish es que es capaz de lanzar comandos «purge» contra nuestro varnish cuando lo considere conveniente. De esa manera, cuando añadamos una nueva entrada, por ejemplo, W3 Total Cache se encargará de hablar con nuestro varnish y decirle que páginas debe dejar de cachear.

Paso 1: Descargar y activar W3 Total Cache.

Ningún secreto aquí. Hay que ir a la sección de plugins, pulsar el botón «Añadir plugin», buscar «w3 total cache» en el buscador y pulsar el botón instalar. Como cualquier otro plugin.

Paso 2: Configurar w3 total cache, por el momento, sin varnish

De momento, vamos a configurar el plugin sin usar varnish aún. El plugin de por si tiene bastantes configuraciones y algunas como el minimizado de HTML pueden romper la apariencia con algunos temas. Por tanto, primero nos vamos a asegurar que todo funciona sin varnish.

Visitar el menú «performance/General Settings» y activar la siguientes preferencias:

Activar page cache: Si es posible, usar APC:Opcode para usar la memoria del servidor. Si no, usar disk:enhanced.

Activar minify: Yo lo dejo en auto y cache en disco. Esta opción puede causar conflictos con algunos temas, por lo que será uno de los puntos a tocar si más adelante algo se descuadra.

Database Cache: Yo lo desactivo, ya que la siguiente opción «Object Cache» guarda la misma información y puede cachear varias consultas a la base de datos en una única entrada. Al gusto. Activarlo no debería dar problemas.

Object Cache: Activado en APC:Opcode si es posible. Esto acelera mucho de por si cualquier instalación de wordpress, ya que ahorra muchísimas consultas a la base de datos.

Browser Cache Enabled: Activado. Sirve para indicarle a los clientes por cuanto tiempo deben cachear nuestra web, las imágenes, etc.. de manera que en siguientes visitas no vuelvan a pedir recursos que ya habían solicitado. Aligera mucho el servidor. NOTA: Estos valores serán usados más adelante por varnish para conocer los tiempos de cache de cada recurso.

Una vez configurado, activar la configuración y borrar las caches con el botón que nos mostrará arriba.

Si en este momento cerramos la sesión y visitamos nuestra web notaremos un importante aumento del rendimiento.

NOTA 1: Hay que cerrar la sesión, o usar otro navegador porque W3 Total Cache no se activa para los editores. Por tanto, apenas notaremos ninguna mejora.

NOTA 2: Probar que todo va bien, que no se descuadra ninguna página y que los enlaces funcionan. Algunos temas de wordpress muy avanzados (y mal programados) pueden tener problemas con la compresión de CSS y HTML.

Paso 2: Configurar W3 total Cache para usar Varnish

Volvemos a visitar la sección «Performance/general Settings» de nuestro panel de control y vamos a la sección «Reverse Proxy». Lo activamos y entramos la dirección de nuestro varnish. En mi caso, corre en el mismo servidor que apache, por tanto, será 127.0.0.1.

Lo que hemos hecho aquí es decir a wordpress como puede invalidar páginas de wordpress cuando estas hayan cambiado, es decir, a quien debe enviarle los comandos purge.

Visitar la sección «Page Cache Settings» y configurar al gusto. Por lo general, las opciones por defecto son correctas. A mi me gusta aumentar el número de páginas que deben purgarse ante un cambio y bajar los tiempos, pero depende de tu servidor y el tráfico que tengas.

Paso 3: Configurar varnish para escuchar comandos purge

Aquí entramos en materia. Suponemos que ya tenemos un varnish corriendo y bien configurado como explicamos en la entrada Instalando Varnish.

Tenemos que editar el archivo de configuración de varnish, que generalmente se encuentra es /etc/varnish/default.vlc

Si no existe el método acl_purge, debemos crear uno con esta forma:

acl purge {
«localhost»;
«127.0.0.1»;
}

Luego buscaremos la función sub_vcl_recv y añadiremos el siguiente código, lo más al principio que sea posible.

if (req.method == «PURGE») {
if (!client.ip ~ purge) {
return(synth(405,»Not allowed.»));
}
return (purge);
}

 

Con esto le estamos diciendo a varnish que escuchará peticiones purge desde estas IPs. Cualquier petición desde una IP que no esté en la lista recibirá una respuesta 405:Not allowed.

Debe ser una lista de IPs seguras, para evitar que nadie pueda lanzarnos un ataque invalidando caches.

Paso 4: Configurar varnish para cachear un wordpress

Varnish no cachea ninguna petición que incluya cookies, para evitar liarla parda con las sesiones de cada usuario. WordPress tiene una manía inmensa de generar cookies para todo. Algunas de esas cookies pueden ignorarse, otras, como las cookies de sesión no.

Debemos configurar varnish para que borre aquellas cookies que son intrascendentes.

Por otro lado, puede ocurrir que tengamos varias webs corriendo en el mismo servidor, por lo que no podemos aplicar una configuración genérica de varnish para cada web. Personalmente, tengo agrupados todos los wordpress en una sección de la configuración y los identifico a partir del dominio. De esa manera, siempre puedo crear una regla específica para cada sitio.

Paso a pegar aquí algunos trozos de mi configuración que son significativos.

En la función vcl_recv

# Configuracion generica para todos los wordpress
# Añade una entrada en etc/hosts a 127.0.0.1 para cada web. Si no, no funciona el PURGE
if (req.http.host ~ «(www.jgimenez.info|otraweb.com|foro.otraweb.com)») {
if (req.url ~ «\?(utm_(campaign|medium|source|term)|adParams|client|cx|eid|fbid|feed|ref(id|src)?|v(er|iew))=») {
set req.url = regsub(req.url, «\?.*$», «»);
}
if (req.url ~ «wp-(login|admin)» || req.url ~ «preview=true» || req.url ~ «xmlrpc.php») {
return (pass);
}
if (req.http.cookie) {
if (req.http.cookie ~ «(wordpress_|wp-settings-)») {
return(pass);
} else {
unset req.http.cookie;
}
}
}

Esto eliminará las cookies que vienen del cliente que no son necesarias para configurar la vista.

NOTA: Aquí os quisiera pedir ayuda. Esta lista de cookies cambia en función de la fuente que consultes e incluso con cada versión de wordpress. El trabajo de un sysadmin no acaba nunca. Si crees que falta o sobra algo, por favor, déjame un comentario.

Ahora haremos lo mismo, pero desde el lado de las cookies que se sirven desde el servidor web.

Buscaremos el método vcl_backend_response y añadiremos un código similar al anterior:

# Configuracion generica para todos los wordpress
if (bereq.http.host ~ «(www.jgimenez.info|otraweb.com|foro.otraweb.com)») {
#Eliminamos todas las cookies que wordpress nos intenta colar
if ( (!(bereq.url ~ «(wp-(login|admin)|login)»)) || (bereq.method == «GET») ) {
unset beresp.http.set-cookie;
#set beresp.ttl = 1h;
}
}

Aquí hemos de tener cuidado. Nos estamos cargando TODAS las cookies que wordpress nos entrega, salvo que estemos en las páginas de administración. Esto nos puede fastidiar algo, o puede romper funcionalidades extra de nuestro tema o plugins, por ejemplo, plugins de votos o contadores de visitas. Cada uno debería personalizarlo según sus necesidades borrando sólo las cookies que le interesan.

Reiniciar apache y varnish. (En realidad, apache no es necesario).

Probándolo todo

En mi caso, tuve que borrar todas las cookies antes de que funcionase. Probablemente la lista de cookies que borro es muy conservadora.

Importante recordar reiniciar varnish y probar la web sin estar logado.

Para ver que todo funciona, yo uso firebug y miro la cabecera age de la petición que entrega el código html. Si es mayor a cero, significa que la página se está cacheando.

Otra manera es consultar el log de apache y ver como a pesar de hacer peticiones, estas no llegan a apache.

Hay que estar atento al tema cookies de nuestra instalación de wordpress. Con un blog sencillo como el mio, no hay ningún problema. Con instalaciones más complicadas deberemos afinar más a la hora de filtrar cookies.

Si necesitas ayuda, o quieres comentar algo, no te cortes y deja un mensaje.