pg_activity para monitorizar un Postgres dockerizado

schedule   sábado, 21 septiembre 2024

Veamos las bondades que ofrece la herramienta pg_activity, que al más puro estilo htop nos permite monitorizar nuestra base de datos PostgreSQL.

Bajo mi experiencia, la he usado tanto en entornos de producción (para ver en vivo SQLs bloqueadas, cuellos de botella, etc.), como en entornos de desarrollo (para testear procesos pesados y optimizarlos, por ejemplo). Y creo que es una herramienta que cualquier desarrollador/a debería y/o necesitaría usar a lo largo de la implementación y/o mantenimiento de una solución de software.

Dicho esto, veamos de qué va todo esto.

Tabla de contenido

¿Qué és pg_activity y para qué usarlo?

Como describen en su propio proyecto de GitHub, pg_activity es una herramienta de linea de comandos para monitorizar la actividad del servidor PostgreSQL. Supongo que más de una vez habréis usado htop para ver de una forma gráfica en vuestra terminal los procesos que se están ejecutando en vuestra máquina, y ver cuáles de ellos están consumiendo más memoria (entre otras cosas). Pues la idea de pg_activity es muy similar, muestra las queries que se estén ejecutando en ese momento sobre nuestro servidor PostgreSQL, mostrando aquéllas que hayan excedido un tiempo considerable (configurable usando el parámetro —min-duration) para así ver cuáles están llevando más tiempo, y en consecuencia, puedan están afectando al rendimiento de nuestra aplicación.

La gran mayoría de nosotros usamos ORMs (Django, SQLalchemy, Odoo, etc.) para desarrollar nuestros proyectos, con lo que no nos tenemos que preocupar (un poco sí, la verdad, pero eso ya lo hablaremos en otro momento) demasiado qué queries se ejecutan internamente cuando realizamos ciertas acciones sobre nuestra aplicación. Por ejemplo, cuando definimos los modelos y aplicamos las migraciones, internamente se ejecutan queries de tipo INSERT y/o ALTER TABLE; o cuando buscamos ciertos registros en base a un criterio, internamente se ejecutan queries de tipo SELECT; y así con el resto de acciones que se nos ocurra.

Pues bien, sabiendo que toda acción realizada con el ORM desencadena una query en el servidor PostgreSQL, podemos usar pg_activity para monitorizar el servidor PostgreSQL, y ver qué queries tardan más tiempo de lo debido. Aquí, está claro, necesitamos realizar un poco de ingeniería inversa, ya que pg_activity nos dirá la query bruta, con lo que tendremos que averiguar qué acción del ORM la está desencadenando.

Instalación de pg_activity

Si estamos usando algún sistema basado en distribuciones Debian (Debian, Ubuntu, Mint, etc.), podemos instalar pg_activity desde el propio gestor de paquetes del sistema.

sudo apt install pg-activity

Aunque yo suelo instalarlo usando el gestor de paquetes Python (pip). Incluso bajo un entorno virtual para evitar que se generen conflictos con el resto de librerías Python usadas por nuestro sistema. Para instalar la herramienta usando pip ejecutamos la siguiente orden en nuestra terminal.

pip install pg_activity[psycopg]

Además de instalar pg_activity, también se instala la dependencia psycopg, el cual es una librería que permite realizar conexiones a servidores PostgreSQL usando Python.

Podemos encontrar todas las formas de instalar pg_activity desde su propio proyecto de GitHub.

Realizar conexión a la bbdd servida sobre un contenedor Docker

Ahora que ya sabemos qué és pg_activity, y además lo tenemos instalado en nuestra máquina, vamos a conectarnos a un servidor PostgreSQL qué esté corriendo en un contenedor Docker.

Para mostrar los ejemplos voy a usar la forma más sencilla de lanzar una instancia PostgreSQL sobre Docker: creando un contenedor usando la imagen oficial. Lo más normal suele ser que tengamos un servicio de PostgreSQL que se esté usando en un proyecto, al cual se le conecte una aplicación web usando docker compose, por ejemplo. Pero para realizar la conexión será exactamente lo mismo. Únicamente hay que tener en cuenta los siguientes puntos.

Teniendo claros los datos necesarios para realizar la conexión, voy a crear un contenedor con una base de datos de prueba para mostrar los ejemplos.

docker run \
    --name test_postgres_server \
    -p "5432:5432" \
    -e POSTGRES_PASSWORD=pythoninspanish \
    -d \
    postgres:16-alpine

Veamos a continuación qué desencadena exactamente el comando recién ejecutado (como hemos comentado antes, podéis usar una instancia de PosgreSQL ya existen para realizar la conexión con pg_activity, con lo que os podéis saltar esta parte):

Por defecto, al usar la imagen Docker oficial de PostgreSQL, tanto el usuario postgres como la base de datos postgres son creadas al ejecutarse implícitamente el script initdb en el entrypoint.

Ahora que ya tenemos la instancia levantada (ya sea la del ejemplo, o cualquier otra que tengáis), tan solo nos quedaría ejecutar la herramienta pg_activity para conectarnos a nuestra base de datos y comenzar a monitorizarla.

pg_activity -h localhost -p 5432 -U postgres -d postgres

Vamos a ver qué estamos haciendo exactamente:

Si la comunicación entre nuestra máquina y la instancia de PostgreSQL es correcta, se nos solicitará la contraseña (más adelante veremos la forma de que no nos solicite siempre la contraseña) del usuario de PostgreSQL que estamos usando para realizar la conexión, “postgres” en este ejemplo. Os aparecerá algo como lo siguiente.

pg_activity-request-password.png

Metemos la contraseña correspondiente, y se nos abrirá la herramienta pg_activity.

pg_activity-first-screen.png

Ya estaremos conectados a nuestra base de datos para monitorizarla. En la parte superior se nos indica varias cosas; la versión de PosgreSQL que usa nuestra instancia; el nombre de la máquina donde está siendo ejecutada; el usuario, puerto y base de datos que hemos usado para realizar la conexión (postgres@localhost:5432/postgres); incluso el tiempo que lleva la instancia levantada (34 minutos en mi ejemplo).

Para salir de pg_activity bastaría simplemente con pulsar q en nuestro teclado.

Crear fichero .pgpass para agilizar la conexión a la bbdd

Para evitar tener que indicar siempre la contraseña de nuestro usuario PostgreSQL podemos crear en nuestro home el fichero .pgpass. Se trata de un fichero de texto plano, en el cual se pueden definir diferentes credenciales para distintas instancias de PostgreSQL. El formato que espera es el siguiente.

hostname:port:database:username:password

No tiene ningún misterio, y además como hemos comentado hace un momento, se pueden añadir diferentes líneas con conexiones a base de datos diferentes, o incluso otras instancias.

Como anotación, sería importante establecer ciertos permisos al fichero para asegurarnos que nadie pueda acceder a él (salvo nuestro usuario). Vamos a crear el fichero con los datos de conexión del ejemplo anterior para que quede claro.

Primero creamos el fichero en nuestro home.

touch ~/.pgpass

Añadimos los datos de conexión.

 echo "localhost:5432:postgres:postgres:pythoninspanish" >> ~/.pgpass

Establecemos los permisos para que únicamente nuestro usuario pueda leer y escribir sobre el fichero.

chmod 600 ~/.pgpass

Y vualá, ya lo tendríamos. La próxima vez que ejecutemos el pg_activity sobre la instancia indicada no nos solicitará la contraseña.

Conclusión

Hemos visto qué es pg_activity y para qué sirve, y además hemos visto un ejemplo práctico de como monitorizar una base de datos dockerizada y la forma de evitar que siempre nos solicite la contraseña.

Ahora únicamente quedaría monitorizar la base de datos con las distintas opciones que ofrece pg_activity, pero no las hablaremos aquí porque se aleja de la finalidad de esta publicación. De todas formas, en la misma documentación del proyecto indican los distintos parámetros a usar y el cómo interactuar con la terminal una vez comenzamos la monitorización.


Espero os haya gustado la publicación, y que cómo yo, uséis pg_activity para detectar posibles cuellos de botella ocasionados por un mal planteamiento o uso del ORM que estemos realizando en nuestra aplicación. Hasta la próxima, ¡pythonistas! 🐍❤️

Ir al inicio