Además de PostgreSQL y MySQL, en nuestra organización utilizamos servidores de gestión de bases de datos IBM Informix. Se trata de un producto de software de gestión de bases de datos propietario, licenciado por IBM, que corre sobre sistemas Unix.

Al tratarse de software propietario, collectd (y creo que ninguna otra solución de recolección de métricas) no posee un plugin para monitorear servidores de bases de datos Informix. Por ende me dispuse a crear un script Bash que permita monitorear servidores Informix y almacene las métricas en una base de datos InfluxDB, el cual comparto en este artículo.



Según la página en Wikipedia, Informix es una familia de productos RDBMS de IBM, adquirida en 2001 a una compañía (también llamada Informix o Informix Software) cuyos orígenes se remontan a 1980. El DBMS Informix fue concebido y diseñado por Roger Sippl a finales de los años 1970. Durante parte de los años 1990 fue el segundo sistema de bases de datos más popular después de Oracle. En 2001 IBM, impulsada por una sugerencia de Wal-Mart (el mayor cliente de Informix) compró Informix. IBM tenía planes a largo plazo tanto para Informix como para DB2, compartiendo ambas bases de datos tecnología de la otra. La última versión actual de Informix es la 12.10.xC12 (liberada el 20 de julio de 2018)

Informix incluye la herramienta de monitoreo onstat, la cual permite verificar el estado del servidor en todo momento. Esta herramienta tiene una gran cantidad de opciones y provee mucha información estadística sobre el motor de bases de datos.

La idea detrás de este script es interpretar la salida del comando onstat -p (profile) y enviar los valores a una base de datos InfluxDB (utilizando la API HTTP).

Veamos cómo es la salida típica de onstat -p:

[informix@ifxdb ~]$ onstat -p

IBM Informix Dynamic Server Version 11.70.FC7GE -- On-Line -- Up 3 days 23:06:21 -- 217312 Kbytes

Profile
dskreads   pagreads   bufreads   %cached dskwrits   pagwrits   bufwrits   %cached
132546     171039     24139564   99.45   83144      233945     1230187    93.42  

isamtot    open       start      read       write      rewrite    delete     commit     rollbk
22771017   56515      374149     19350401   479845     305533     25200      19201      0

gp_read    gp_write   gp_rewrt   gp_del     gp_alloc   gp_free    gp_curs   
0          0          0          0          0          0          0         

ovlock     ovuserthread ovbuff     usercpu  syscpu   numckpts   flushes   
0          0            0          192.56   88.05    112        112       

bufwaits   lokwaits   lockreqs   deadlks    dltouts    ckpwaits   compress   seqscans  
398        4          1749780    0          0          0          79048      36490     

ixda-RA    idx-RA     da-RA      logrec-RA  RA-pgsused lchwaits  
0          10821      104358     0          99704      5659    

El objetivo es transformar los valores en esta salida a consultas InfluxQL.

Para comenzar, remover líneas en blanco y recuperar sólo las líneas a partir de "Profile":

[informix@ifxdb ~]$ onstat -p | grep -v "^$" | awk '/Profile/{y=1;next}y'
dskreads   pagreads   bufreads   %cached dskwrits   pagwrits   bufwrits   %cached
132546     171039     24139564   99.45   83144      233945     1230187    93.42  
isamtot    open       start      read       write      rewrite    delete     commit     rollbk
22771017   56515      374149     19350401   479845     305533     25200      19201      0
gp_read    gp_write   gp_rewrt   gp_del     gp_alloc   gp_free    gp_curs   
0          0          0          0          0          0          0         
ovlock     ovuserthread ovbuff     usercpu  syscpu   numckpts   flushes   
0          0            0          192.58   88.06    112        112       
bufwaits   lokwaits   lockreqs   deadlks    dltouts    ckpwaits   compress   seqscans  
398        4          1749780    0          0          0          79048      36490     
ixda-RA    idx-RA     da-RA      logrec-RA  RA-pgsused lchwaits  
0          10821      104358     0          99704      5659 

Luego eliminar los espacios en blanco extra al final de cada línea, y reemplazar el resto de los espacios en blanco por una única coma:

[informix@ifxdb ~]$ onstat -p | grep -v "^$" | awk '/Profile/{y=1;next}y' | sed 's/[[:space:]]*$//' | sed 's/ \{1,\}/,/g'
dskreads,pagreads,bufreads,%cached,dskwrits,pagwrits,bufwrits,%cached
132546,171039,24139564,99.45,83144,233945,1230187,93.42
isamtot,open,start,read,write,rewrite,delete,commit,rollbk
22771017,56515,374149,19350401,479845,305533,25200,19201,0
gp_read,gp_write,gp_rewrt,gp_del,gp_alloc,gp_free,gp_curs
0,0,0,0,0,0,0
ovlock,ovuserthread,ovbuff,usercpu,syscpu,numckpts,flushes
0,0,0,192.60,88.07,112,112
bufwaits,lokwaits,lockreqs,deadlks,dltouts,ckpwaits,compress,seqscans
398,4,1749780,0,0,0,79048,36490
ixda-RA,idx-RA,da-RA,logrec-RA,RA-pgsused,lchwaits
0,10821,104358,0,99704,5659

Finalmente es necesario utilizar un par de bucles para agrupar cada clave con su correspondiente valor. En cada iteración del bucle exterior, recuperar dos líneas de la salida anterior. Cada línea se convierte a un arreglo (separado por comas). Luego se concatena cada clave (ítem del primer arreglo) con su correspondiente valor (ítem del arreglo 2).

El resultado es el siguiente:

[informix@ifxdb ~]$ while read -r L1 && read -r L2; do
>   IFS=',' read -r -a A1 <<< "$L1"
>   IFS=',' read -r -a A2 <<< "$L2"
> 
>   for (( I=0; I<${#A1[@]}; I++ ));
>   do
>     echo "informix_value,host=ifxdb,type=profile,type_instance=${A1[I]} value=${A2[I]}"
>   done
> 
> done <<< "$ONSTAT_PROFILE"
informix_value,host=ifxdb,type=profile,type_instance=dskreads value=132546
informix_value,host=ifxdb,type=profile,type_instance=pagreads value=171039
informix_value,host=ifxdb,type=profile,type_instance=bufreads value=24139604
informix_value,host=ifxdb,type=profile,type_instance=%cached value=99.45
informix_value,host=ifxdb,type=profile,type_instance=dskwrits value=83144
informix_value,host=ifxdb,type=profile,type_instance=pagwrits value=233945
informix_value,host=ifxdb,type=profile,type_instance=bufwrits value=1230187
informix_value,host=ifxdb,type=profile,type_instance=%cached value=93.42
informix_value,host=ifxdb,type=profile,type_instance=isamtot value=22771038
informix_value,host=ifxdb,type=profile,type_instance=open value=56515
informix_value,host=ifxdb,type=profile,type_instance=start value=374150
informix_value,host=ifxdb,type=profile,type_instance=read value=19350418
informix_value,host=ifxdb,type=profile,type_instance=write value=479845
informix_value,host=ifxdb,type=profile,type_instance=rewrite value=305533
informix_value,host=ifxdb,type=profile,type_instance=delete value=25200
informix_value,host=ifxdb,type=profile,type_instance=commit value=19201
informix_value,host=ifxdb,type=profile,type_instance=rollbk value=0
informix_value,host=ifxdb,type=profile,type_instance=gp_read value=0
informix_value,host=ifxdb,type=profile,type_instance=gp_write value=0
informix_value,host=ifxdb,type=profile,type_instance=gp_rewrt value=0
informix_value,host=ifxdb,type=profile,type_instance=gp_del value=0
informix_value,host=ifxdb,type=profile,type_instance=gp_alloc value=0
informix_value,host=ifxdb,type=profile,type_instance=gp_free value=0
informix_value,host=ifxdb,type=profile,type_instance=gp_curs value=0
informix_value,host=ifxdb,type=profile,type_instance=ovlock value=0
informix_value,host=ifxdb,type=profile,type_instance=ovuserthread value=0
informix_value,host=ifxdb,type=profile,type_instance=ovbuff value=0
informix_value,host=ifxdb,type=profile,type_instance=usercpu value=192.66
informix_value,host=ifxdb,type=profile,type_instance=syscpu value=88.11
informix_value,host=ifxdb,type=profile,type_instance=numckpts value=112
informix_value,host=ifxdb,type=profile,type_instance=flushes value=112
informix_value,host=ifxdb,type=profile,type_instance=bufwaits value=398
informix_value,host=ifxdb,type=profile,type_instance=lokwaits value=4
informix_value,host=ifxdb,type=profile,type_instance=lockreqs value=1749780
informix_value,host=ifxdb,type=profile,type_instance=deadlks value=0
informix_value,host=ifxdb,type=profile,type_instance=dltouts value=0
informix_value,host=ifxdb,type=profile,type_instance=ckpwaits value=0
informix_value,host=ifxdb,type=profile,type_instance=compress value=79048
informix_value,host=ifxdb,type=profile,type_instance=seqscans value=36491
informix_value,host=ifxdb,type=profile,type_instance=ixda-RA value=0
informix_value,host=ifxdb,type=profile,type_instance=idx-RA value=10821
informix_value,host=ifxdb,type=profile,type_instance=da-RA value=104358
informix_value,host=ifxdb,type=profile,type_instance=logrec-RA value=0
informix_value,host=ifxdb,type=profile,type_instance=RA-pgsused value=99704
informix_value,host=ifxdb,type=profile,type_instance=lchwaits value=5659

Perfecto, en este punto se ha logrado convertir la salida de onstat -p en un batch de consultas InfluxQL. El nombre de métrica elegido es "informix_value" (en concordancia con los nombres de métrica utilizados por collectd). Cada valor se relaciona a su clave a través del tag "type_instance".

Finalmente resta insertar este batch de métricas en la base de datos InfluxDB utilizando la API HTTP. Las consultas se envían a través del método HTTP POST a la siguiente URL: http://192.168.140.65:8086/write?db=collectd.

El script resultante es el siguiente:

#!/bin/bash

INFLUXDB_USER="informix"
INFLUXDB_PASS="1234"
INFLUXDB_URL="http://192.168.140.65:8086/write?db=collectd"

HOST=$(hostname)
MEASUREMENT="informix_value"
TAG="$MEASUREMENT,host=$HOST,type=profile"

ONSTAT_PROFILE=$(onstat -p | grep -v "^$" | awk '/Profile/{y=1;next}y' | sed 's/[[:space:]]*$//' | sed 's/ \{1,\}/,/g')

while read -r L1 && read -r L2; do
  IFS=',' read -r -a A1 <<< "$L1"
  IFS=',' read -r -a A2 <<< "$L2"

  for (( I=0; I<${#A1[@]}; I++ ));
  do
    echo "$TAG,type_instance=${A1[I]} value=${A2[I]}"
  done

done <<< "$ONSTAT_PROFILE" | curl -u $INFLUXDB_USER:$INFLUXDB_PASS -i -XPOST "$INFLUXDB_URL" --data-binary @- >/dev/null 2>&1 || exit 1

Configurar adecuadamente las variables INFLUXDB_USER, INFLUXDB_PASS, INFLUXDB_URL, HOST y MEASUREMENT. Luego guardar el script en una ubicación conveniente (/usr/local/bin/).

Dejo este script en mi cuenta de GitHub: linuxitux / scripts / misc / informix-profile-influxdb.bash.

Finalmente es necesario ejecutar periódicamente este script utilizando un cronjob:

[informix@ifxdb ~]$ crontab -e

Por ejemplo, para ejecutar una vez por minuto:

# Monitoreo con InfluxDB+Grafana
* * * * * /usr/local/bin/informix-profile-influxdb.bash

Habilitar la API HTTP en InfluxDB

A fin de poder escribir estos datos en la base InfluxDB, es necesario que la API HTTP esté habilitada.

En el servidor donde se ha instalado InfluxDB, permitir el acceso remoto a la API HTTP editando el archivo de configuración:

# nano /etc/influxdb/influxdb.conf

Por defecto sólo se permite el acceso desde localhost:

[http]
  enabled = true
  bind-address = "127.0.0.1:8086"

Es posible asignar una IP en la red local, o permitir que escuche en todas las interfaces configuradas ingresando 0.0.0.0:

[http]
  enabled = true
  bind-address = "0.0.0.0:8086"

En este caso se recomienda luego filtrar el acceso mediante un firewall.

Reiniciar InfluxDB:

# service influxdb restart

A continuación, y si se ha habilitado el uso de autenticación (cosa altamente recomendable), es necesario crear un usuario con privilegios de escritura en la base de datos destino ("collectd", en este caso).

Iniciar el cliente influx y conectarse al motor con privilegios de administración:

# influx -username admin -password ''
password: 
Visit https://enterprise.influxdata.com to register for updates, InfluxDB server management, and monitoring.
Connected to http://localhost:8086 version 1.0.2
InfluxDB shell version: 1.0.2
>

Crear el usuario (según la configuración en el script) y otorgarle permisos de escritura sobre la base de datos destino:

> create user informix with password '1234'
> grant all on "collectd" to "informix"
> quit

Si todo es correcto, será posible comenzar a visualizar las métricas de Informix recolectadas por el script.

Tener en cuenta que la mayoría de las métricas son contadores, con lo cual resulta útil convertirlas a deltas aplicando la transformación derivada a fin de lograr una gráfica conveniente en Grafana:

La página Web Oninit: Onstat Reference - onstat -p Profile statistics provee una descripción detallada de cada uno de los valores en las diferentes salidas del comando onstat, lo cual permite identificar fácilmente qué valores resulta útil monitorear.

Referencias


Tal vez pueda interesarte


Compartí este artículo