postgres_exporter e monitorando instâncias do PostgreSQL com vários bancos de dados

UPD: A nota perdeu sua relevância com o lançamento do 0.8.0. Todas as inovações podem ser encontradas no artigo: Novos recursos do postgres_exporter para monitorar o PostgreSQL


Boa tarde, leitores habr!


O Prometheus e seu ecossistema de exportadores (agentes) são uma boa ferramenta para qualquer administrador e desenvolvedor. Facilidade de entrega, configurações de simplicidade (relativas), capacidade de usar o serviço de detecção automática.
Mas não se trata tanto de Prometheus, mas de um dos agentes notáveis, o postgres_exporter. Permite coletar métricas com o PostgreSQL. Mas se tudo fosse tão simples ...


Infelizmente, a documentação do postgres_exporter é bastante ascética e afeta apenas casos gerais. Mas e se você obtiver uma instância de um cluster DBMS com vários bancos de dados e / ou desejar coletar métricas para várias instâncias do cluster de uma só vez.


Finalidade


Na verdade, sobre o objetivo do artigo ou melhor, as notas. Percebo imediatamente que aqui não descreverei os processos de montagem ou configuração do Prometheus e do postgres_exporter, sua interação. Tudo isso está descrito na documentação e em muitas outras fontes.


Gostaria de abordar alguns casos especiais de uso do postgres_exporter para resolver problemas específicos, ou seja, coletar métricas por um agente com:


  1. vários bancos de dados em uma instância;
  2. várias cópias;
  3. vários bancos de dados em diferentes instâncias.

postgres_exporter


Subjetivamente, os prós e contras.


Dos profissionais:


  1. A primeira e importante vantagem é a facilidade de entrega e configuração do agente. Agente - é um arquivo executável (opcionalmente, um arquivo yaml com um conjunto de métricas do usuário). Este é um aplicativo independente compilado para a distribuição e arquitetura necessárias e não requer a instalação de pacotes adicionais no servidor. O agente pode ser instalado no mesmo nó da instância do cluster e em um nó separado;
  2. O agente se conecta ao DBMS como um cliente sql regular. É possível conectar via inet ou através de um soquete unix;
  3. A capacidade de receber métricas por um agente, de várias instâncias de instâncias e / ou de vários bancos de dados de uma instância;
  4. As métricas são coletadas com a frequência solicitada pelo Prometheus ou outro coletor;
  5. A capacidade de receber métricas com uma simples solicitação HTTP;
  6. Recebimento automático, por um agente, de uma lista de bancos de dados em uma única instância do PostgreSQL, com a versão postgres_exporter 0.5.0+, a opção --auto-discover-database apareceu.

Dos menos:


  1. Falta de autorização;
  2. Transferência de dados somente via HTTP. Todas as métricas serão transmitidas em texto não criptografado. E isso é ruim, pois um invasor, quando interceptado, pode obter uma lista confiável de bancos de dados e funções;
  3. Não armazena em cache métricas. Assim, por exemplo, quando o agente não estiver disponível na rede, os dados do período de indisponibilidade não serão recebidos pelo Prometheus;
  4. Ao usar a opção --auto-discover-database, não é possível excluir determinados bancos de dados da lista. Isso é temporário, pois no próximo lançamento essa possibilidade já deve aparecer (opção --exclude-database).

Vários bancos de dados em uma instância


Bem, vamos à prática. Suponha que tenhamos uma instância do PostgreSQL com vários bancos de dados e precisamos organizar a coleção de métricas da instância e todos os bancos de dados.
Por que eu separei a coleção de métricas do banco de dados e a instância do cluster, tudo é muito simples, o cenário do postgres_exporter trabalhando com vários bancos de dados no mesmo cluster implica a execução do mesmo conjunto de consultas sql em bancos de dados diferentes. E, como resultado, ao tentar obter métricas a partir das visualizações pg_stat_replication, pg_stat_activity, pg_stat_statement, etc. sendo comum ao cluster, sempre obtemos, no entendimento de postgres_exporter, o mesmo conjunto de métricas que levarão a chaves e valores duplicados, o que levará a um erro.
Vamos ver como fica na prática.


Temos uma instância de teste com um conjunto de bancos de dados:


List of databases Name | Owner | Encoding | Collate | Ctype | Access privileges -----------+----------+----------+------------+------------+----------------------- dbtest1 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | dbtest2 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | dbtest3 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | postgres | postgres | UTF8 | en_US.utf8 | en_US.utf8 | 

Iniciamos o postgres_exporter, com a opção --auto-discover-database (se o nome do banco de dados não estiver especificado na cadeia de conexão, a conexão será feita no banco de dados com o nome de usuário):


 $ DATA_SOURCE_NAME="postgresql://postgres@127.0.0.1:5432/?sslmode=disable" ./postgres_exporter --auto-discover-databases --log.format=logger:stdout 

  • DATA_SOURCE_NAME - variável de ambiente contendo parâmetros para conectar-se a uma instância do PostgreSQL

Na saída do agente, observamos uma imagem idílica, ela é lançada e foi capaz de conectar-se a todos os bancos de dados no cluster (embora não escreva em quais bancos de dados, mas espero que isso seja corrigido):


 INFO[0000] Established new database connection to "127.0.0.1:5432". source="postgres_exporter.go:788" INFO[0000] Established new database connection to "127.0.0.1:5432". source="postgres_exporter.go:788" INFO[0000] Semantic Version Changed on "127.0.0.1:5432": 0.0.0 -> 11.5.0 source="postgres_exporter.go:1251" INFO[0000] Semantic Version Changed on "127.0.0.1:5432": 0.0.0 -> 11.5.0 source="postgres_exporter.go:1251" INFO[0000] Established new database connection to "127.0.0.1:5432". source="postgres_exporter.go:788" INFO[0000] Semantic Version Changed on "127.0.0.1:5432": 0.0.0 -> 11.5.0 source="postgres_exporter.go:1251" INFO[0000] Established new database connection to "127.0.0.1:5432". source="postgres_exporter.go:788" INFO[0000] Semantic Version Changed on "127.0.0.1:5432": 0.0.0 -> 11.5.0 source="postgres_exporter.go:1251" INFO[0000] Established new database connection to "127.0.0.1:5432". source="postgres_exporter.go:788" INFO[0000] Semantic Version Changed on "127.0.0.1:5432": 0.0.0 -> 11.5.0 source="postgres_exporter.go:1251" INFO[0000] Starting Server: :9187 source="postgres_exporter.go:1490" 

Eu acho que um leitor atento perceberá que existem quatro bases no cluster (postgres, dbtest1, dbtest2 e dbtest3, template0 e template1 são ignorados) e há cinco conexões. No nosso caso, o postgres_exporter cria duas conexões com o banco de dados do postgres. E com esse recurso, você precisa ter muito cuidado. Porque Vamos descobrir um pouco mais sobre isso.


Bem, vamos continuar e tentar obter as métricas:


 $ curl http://localhost:9178/metrics 

Como resultado, na saída, recebemos avisos sobre duplicatas "foram coletados antes com o mesmo nome e valores de rótulo" (mas no log postgres_exporter, não veremos avisos):


 ... * collected metric pg_stat_activity_max_tx_duration label:<name:"datname" value:"dbtest1" > label:<name:"server" value:"127.0.0.1:5432" > label:<name:"state" value:"fastpath function call" > gauge:<value:0 > was collected before with the same name and label values * collected metric pg_stat_bgwriter_checkpoints_timed label:<name:"server" value:"127.0.0.1:5432" > counter:<value:1 > was collected before with the same name and label values ... 

A única maneira de se livrar dos erros é desativar a coleção de métricas por padrão. Há duas maneiras de fazer isso: primeiro defina as variáveis ​​de ambiente PG_EXPORTER_DISABLE_DEFAULT_METRICS e PG_EXPORTER_DISABLE_SETTINGS_METRICS para true ou use as opções --disable-default-Metrics e --disable-settings-metrics


Reinicie o postgres_exporter com opções adicionais:


 $ DATA_SOURCE_NAME="postgresql://postgres@127.0.0.1:5432/?sslmode=disable" ./postgres_exporter --auto-discover-databases --log.format=logger:stdout --disable-default-metrics --disable-settings-metrics 

Tentando obter as métricas:


 $ curl http://localhost:9178/metrics 

E assim, tudo correu conforme o planejado, mas não há uma única métrica associada ao PostgreSQL na saída:


 # HELP go_gc_duration_seconds A summary of the GC invocation durations. # TYPE go_gc_duration_seconds summary go_gc_duration_seconds{quantile="0"} 0 go_gc_duration_seconds{quantile="0.25"} 0 go_gc_duration_seconds{quantile="0.5"} 0 go_gc_duration_seconds{quantile="0.75"} 0 go_gc_duration_seconds{quantile="1"} 0 go_gc_duration_seconds_sum 0 go_gc_duration_seconds_count 0 ... # HELP process_virtual_memory_bytes Virtual memory size in bytes. # TYPE process_virtual_memory_bytes gauge process_virtual_memory_bytes 1.3832192e+07 

Além disso, para obter a carga útil, precisamos criar um arquivo que descreva quais métricas queremos receber (não se esqueça, só podemos coletar métricas específicas do banco de dados).


Para o teste, coletaremos métricas da relação pg_statio_user_tables. Para fazer isso, crie um arquivo queries.yaml com o seguinte conteúdo:


 pg_statio_user_tables: query: "SELECT current_database() as datname, schemaname, relname, heap_blks_read, heap_blks_hit FROM pg_statio_user_tables" metrics: - datname: usage: "LABEL" description: "Name of database" - schemaname: usage: "LABEL" description: "Name of the schema that this table is in" - relname: usage: "LABEL" description: "Name of this table" - heap_blks_read: usage: "COUNTER" description: "Number of disk blocks read from this table" - heap_blks_hit: usage: "COUNTER" description: "Number of buffer hits in this table" 

Eu acho que aqui é necessário esclarecer um ponto, a saber, adicionar o nome do banco de dados no qual a consulta é executada. Este é um requisito obrigatório e há pelo menos dois motivos para isso:


  1. Os bancos de dados podem ter tabelas com o mesmo nome, o que levará a um erro devido à duplicação de métricas;
  2. Sem isso, não é possível identificar a qual banco de dados a métrica se refere, que transformará os dados coletados em lixo.

Então, lançamos nosso agente com a opção --extend.query-path (aqui é indicado o caminho para o arquivo yaml com a descrição das métricas):


 DATA_SOURCE_NAME="postgresql://postgres@127.0.0.1:5432?sslmode=disable" ./postgres_exporter --log.format=logger:stdout --auto-discover-databases --disable-default-metrics --disable-settings-metrics --extend.query-path=./queries.yaml 

Estamos tentando obter as métricas (para maior clareza, usamos apenas pg_statio_user_tables_heap_blks_hit):


 curl -s http://localhost:9187/metrics | grep pg_statio_user_tables_heap_blks_hit 

Como resultado, obtemos um conjunto de métricas interpretado exclusivamente:


 # HELP pg_statio_user_tables_heap_blks_hit Number of buffer hits in this table # TYPE pg_statio_user_tables_heap_blks_hit counter pg_statio_user_tables_heap_blks_hit{datname="dbtest1",relname="t1",schemaname="public",server="127.0.0.1:5432"} 0 pg_statio_user_tables_heap_blks_hit{datname="dbtest1",relname="t2",schemaname="public",server="127.0.0.1:5432"} 0 pg_statio_user_tables_heap_blks_hit{datname="dbtest2",relname="t1",schemaname="public",server="127.0.0.1:5432"} 0 pg_statio_user_tables_heap_blks_hit{datname="dbtest2",relname="t2",schemaname="public",server="127.0.0.1:5432"} 0 pg_statio_user_tables_heap_blks_hit{datname="dbtest3",relname="t1",schemaname="public",server="127.0.0.1:5432"} 0 pg_statio_user_tables_heap_blks_hit{datname="dbtest3",relname="t2",schemaname="public",server="127.0.0.1:5432"} 0 

Como resultado, tivemos a oportunidade, usando a opção --auto-discover-database, de coletar métricas de todos os bancos de dados de uma instância do cluster. Um bom bônus é que, quando você adiciona um novo banco de dados, não precisa reiniciar o agente.
Mas com tudo isso, ficamos sem métricas de instância. A solução, no momento, é apenas uma - usar diferentes agentes para coletar métricas de banco de dados e instância.
É claro que não parece muito bom, mas é possível nivelar esse incômodo ao agrupar agentes para coletar métricas de várias instâncias. Vamos considerar esta, outra oportunidade bastante interessante abaixo.


A resposta para o enigma da conexão 'extra'

Lembre-se, no início, chamamos a atenção para a conexão "extra", portanto, este é um recurso do postgres_exporter com a opção --auto-discover-database.
Mas por que isso pode causar muitos problemas? De fato, tudo é simples e já descrito acima, ou seja, o problema é que o postgres_exporter coletará métricas do banco de dados do postgres duas vezes e começará a duplicar métricas. No nosso caso, apenas a aparência da opção --exclude-database pode ajudar (portanto, estamos ansiosos pelo próximo lançamento).
E sim, se você tiver tabelas de usuários no banco de dados postgres, o exemplo acima não funcionará.


Várias instâncias


Bem, siga em frente. Nós descobrimos como obter métricas de vários bancos de dados, agora consideraremos a opção de como monitorar várias instâncias com um agente. É muito simples, para isso basta listá-los na variável de ambiente DATA_SOURCE_NAME separada por vírgula:


 $ DATA_SOURCE_NAME="postgresql://postgres@127.0.0.1:5432/postgres?sslmode=disable,postgresql://postgres@127.0.0.1:5434/postgres?sslmode=disable" ./postgres_exporter --log.format=logger:stdout 

Aqui nos conectamos a duas instâncias de cluster diferentes executando, no nosso caso, no nó local. Aqui está o que parece nos logs:


 INFO[0000] Established new database connection to "127.0.0.1:5432". source="postgres_exporter.go:788" INFO[0000] Semantic Version Changed on "127.0.0.1:5432": 0.0.0 -> 11.5.0 source="postgres_exporter.go:1251" INFO[0000] Established new database connection to "127.0.0.1:5434". source="postgres_exporter.go:788" INFO[0000] Semantic Version Changed on "127.0.0.1:5434": 0.0.0 -> 11.5.0 source="postgres_exporter.go:1251" INFO[0000] Starting Server: :9187 source="postgres_exporter.go:1490" 

Em seguida, tentamos obter as métricas (para maior clareza, nos restringimos à métrica pg_stat_database_blk_read_time):


 curl -s http://localhost:9187/metrics | grep pg_stat_database_blk_read_time 

Como resultado, de um agente, obtemos métricas para as duas instâncias:


 # HELP pg_stat_database_blk_read_time Time spent reading data file blocks by backends in this database, in milliseconds # TYPE pg_stat_database_blk_read_time counter pg_stat_database_blk_read_time{datid="1",datname="template1",server="127.0.0.1:5432"} 0 pg_stat_database_blk_read_time{datid="1",datname="template1",server="127.0.0.1:5434"} 0 pg_stat_database_blk_read_time{datid="13116",datname="template0",server="127.0.0.1:5432"} 0 pg_stat_database_blk_read_time{datid="13116",datname="template0",server="127.0.0.1:5434"} 0 pg_stat_database_blk_read_time{datid="13117",datname="postgres",server="127.0.0.1:5432"} 0 pg_stat_database_blk_read_time{datid="13117",datname="postgres",server="127.0.0.1:5434"} 0 pg_stat_database_blk_read_time{datid="16384",datname="dbtest1",server="127.0.0.1:5432"} 0 pg_stat_database_blk_read_time{datid="16385",datname="dbtest2",server="127.0.0.1:5432"} 0 pg_stat_database_blk_read_time{datid="16386",datname="dbtest3",server="127.0.0.1:5432"} 0 

Nesse caso, tudo era um pouco mais simples do que no caso de vários bancos de dados em uma instância. Ao mesmo tempo, ainda temos a oportunidade de receber métricas globais de todas as instâncias.


Sumário


E assim, o terceiro caso indicado para fins é uma combinação dos dois descritos acima, portanto não vejo razão para trazê-lo.


Como resultado, o que temos na linha de fundo, postgres_exporter, na minha opinião, é uma ferramenta de administrador bastante interessante e promissora para monitorar instâncias do cluster PostgreSQL e os bancos de dados implantados neles. Mas devido à sua idade, não é sem falhas que podem ser entendidas e perdoadas.


Fontes


  • Prometheus [ 1 ] é um aplicativo de código aberto usado para monitorar e alertar eventos. Ele grava métricas em tempo real em um banco de dados de séries temporais criado usando o modelo de solicitação HTTP, com consultas flexíveis e alertas em tempo real.
  • O postgres_exporter é um exportador de métricas do PostgreSQL para o Prometheus.

Versão, no momento da redação, v 0.5.1. Versões suportadas do PostgreSQL 9.4+ (restrição da versão 9.1+ mencionada no código fonte).

Source: https://habr.com/ru/post/pt468573/


All Articles