ClickHouse Database for Humans ou Alien Technologies

Aleksey Lizunov, xefe do Centro de Competencia para Canles de Servizo Remoto da Dirección de Tecnoloxías da Información da MKB

ClickHouse Database for Humans ou Alien Technologies

Como alternativa á pila ELK (ElasticSearch, Logstash, Kibana), estamos investigando sobre o uso da base de datos ClickHouse como almacén de datos para rexistros.

Neste artigo, gustaríanos falar da nosa experiencia no uso da base de datos ClickHouse e dos resultados preliminares da operación piloto. Hai que ter en conta de inmediato que os resultados foron impresionantes.


ClickHouse Database for Humans ou Alien Technologies

A continuación, describiremos con máis detalle como está configurado o noso sistema e de que compoñentes consta. Pero agora gustaríame falar un pouco sobre esta base de datos no seu conxunto e por que paga a pena prestarlle atención. A base de datos ClickHouse é unha base de datos columnar analítica de alto rendemento de Yandex. Utilízase nos servizos de Yandex, inicialmente é o principal almacenamento de datos para Yandex.Metrica. Sistema de código aberto, gratuíto. Desde o punto de vista dun programador, sempre me preguntei como o implementaron, porque hai datos fantásticos. E a propia interface de usuario de Metrica é moi flexible e rápida. Ao primeiro coñecemento desta base de datos, a impresión é: “¡Ben, por fin! Feito para o pobo! Comezando desde o proceso de instalación e rematando co envío de solicitudes.

Esta base de datos ten un limiar de entrada moi baixo. Incluso un programador con habilidades medias pode instalar esta base de datos en poucos minutos e comezar a usala. Todo funciona con claridade. Incluso as persoas que son novas en Linux poden xestionar rapidamente a instalación e facer as operacións máis sinxelas. Se antes, coas palabras Big Data, Hadoop, Google BigTable, HDFS, un desenvolvedor común tiña ideas de que se trataba duns terabytes, petabytes, que algúns superhumanos se dedicaban á configuración e ao desenvolvemento destes sistemas, entón coa chegada do ClickHouse base de datos, temos unha ferramenta sinxela e comprensible coa que podes resolver un abano de tarefas antes inalcanzables. Só leva unha máquina bastante media e cinco minutos para instalar. É dicir, temos unha base de datos como, por exemplo, MySql, pero só para almacenar miles de millóns de rexistros. Un certo super-arquivador coa linguaxe SQL. É como se lle entregaran á xente as armas de alieníxenas.

Sobre o noso sistema de rexistro

Para recoller información, utilízanse ficheiros de rexistro de IIS de aplicacións web de formato estándar (actualmente tamén estamos analizando rexistros de aplicacións, pero o obxectivo principal na fase piloto é recoller rexistros de IIS).

Por varias razóns, non puidemos abandonar completamente a pila ELK e seguimos usando os compoñentes LogStash e Filebeat, que demostraron ser ben e funcionan de forma bastante fiable e previsible.

O esquema xeral de rexistro móstrase na seguinte figura:

ClickHouse Database for Humans ou Alien Technologies

Unha característica de escribir datos na base de datos ClickHouse é a inserción infrecuente (unha vez por segundo) de rexistros en grandes lotes. Esta, ao parecer, é a parte máis "problemática" que atopas cando experimentas por primeira vez a traballar coa base de datos ClickHouse: o esquema faise un pouco máis complicado.
O complemento para LogStash, que insire directamente datos en ClickHouse, axudou moito aquí. Este compoñente está implantado no mesmo servidor que a propia base de datos. Polo que, en xeral, non se recomenda facelo, pero si desde un punto de vista práctico, para non producir servidores separados mentres estea despregado no mesmo servidor. Non observamos fallos nin conflitos de recursos coa base de datos. Ademais, hai que ter en conta que o complemento ten un mecanismo de reintento en caso de erros. E en caso de erros, o complemento escribe no disco un lote de datos que non se puideron inserir (o formato de ficheiro é conveniente: despois da edición, pode inserir facilmente o lote corrixido usando clickhouse-client).

Na táboa preséntase unha lista completa do software utilizado no esquema:

Lista de software utilizado

nome

Descrición

Ligazón de distribución

Nginx

Proxy inverso para restrinxir o acceso por portos e organizar a autorización

Actualmente non se utiliza no esquema

https://nginx.org/ru/download.html

https://nginx.org/download/nginx-1.16.0.tar.gz

FileBeat

Transferencia de rexistros de ficheiros.

https://www.elastic.co/downloads/beats/filebeat (kit de distribución para Windows 64 bits).

https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-7.3.0-windows-x86_64.zip

logstash

Recolector de rexistros.

Utilízase para recoller rexistros de FileBeat, así como para recoller rexistros da cola RabbitMQ (para servidores que están na DMZ).

https://www.elastic.co/products/logstash

https://artifacts.elastic.co/downloads/logstash/logstash-7.0.1.rpm

Logstash-output-clickhouse

Complemento Loagstash para transferir rexistros á base de datos ClickHouse por lotes

https://github.com/mikechris/logstash-output-clickhouse

/usr/share/logstash/bin/logstash-plugin instalar logstash-output-clickhouse

/usr/share/logstash/bin/logstash-plugin instalar logstash-filter-prune

/usr/share/logstash/bin/logstash-plugin instalar logstash-filter-multiline

clickhouse

Almacenamento de rexistros https://clickhouse.yandex/docs/ru/

https://packagecloud.io/Altinity/clickhouse/packages/el/7/clickhouse-server-19.5.3.8-1.el7.x86_64.rpm

https://packagecloud.io/Altinity/clickhouse/packages/el/7/clickhouse-client-19.5.3.8-1.el7.x86_64.rpm

Nota. A partir de agosto de 2018, as compilacións de rpm "normais" para RHEL apareceron no repositorio de Yandex, polo que podes tentar usalas. No momento da instalación, estabamos a usar paquetes construídos por Altinity.

grafana

Visualización de rexistro. Configurar paneis de mando

https://grafana.com/

https://grafana.com/grafana/download

Redhat & Centos (64 Bit) - última versión

Fonte de datos ClickHouse para Grafana 4.6+

Complemento para Grafana coa fonte de datos ClickHouse

https://grafana.com/plugins/vertamedia-clickhouse-datasource

https://grafana.com/api/plugins/vertamedia-clickhouse-datasource/versions/1.8.1/download

logstash

Rexistra o enrutador de FileBeat á cola RabbitMQ.

Nota. Desafortunadamente, FileBeat non ten saída directamente a RabbitMQ, polo que é necesaria unha ligazón intermedia en forma de Logstash

https://www.elastic.co/products/logstash

https://artifacts.elastic.co/downloads/logstash/logstash-7.0.1.rpm

CoelloMQ

fila de mensaxes. Este é o búfer de rexistro na DMZ

https://www.rabbitmq.com/download.html

https://github.com/rabbitmq/rabbitmq-server/releases/download/v3.7.14/rabbitmq-server-3.7.14-1.el7.noarch.rpm

Tempo de execución de Erlang (necesario para RabbitMQ)

Tempo de execución Erlang. Necesario para que RabbitMQ funcione

http://www.erlang.org/download.html

https://www.rabbitmq.com/install-rpm.html#install-erlang http://www.erlang.org/downloads/21.3

A configuración do servidor coa base de datos ClickHouse preséntase na seguinte táboa:

nome

Valor

Nota

Configuración

Disco duro: 40 GB
RAM: 8GB
Procesador: Core 2 2Ghz

É necesario prestar atención aos consellos para operar a base de datos ClickHouse (https://clickhouse.yandex/docs/ru/operations/tips/)

Software xeral do sistema

OS: Red Hat Enterprise Linux Server (Maipo)

JRE (Java 8)

 

Como podes ver, esta é unha estación de traballo común.

A estrutura da táboa para almacenar rexistros é a seguinte:

log_web.sql

CREATE TABLE log_web (
  logdate Date,
  logdatetime DateTime CODEC(Delta, LZ4HC),
   
  fld_log_file_name LowCardinality( String ),
  fld_server_name LowCardinality( String ),
  fld_app_name LowCardinality( String ),
  fld_app_module LowCardinality( String ),
  fld_website_name LowCardinality( String ),
 
  serverIP LowCardinality( String ),
  method LowCardinality( String ),
  uriStem String,
  uriQuery String,
  port UInt32,
  username LowCardinality( String ),
  clientIP String,
  clientRealIP String,
  userAgent String,
  referer String,
  response String,
  subresponse String,
  win32response String,
  timetaken UInt64
   
  , uriQuery__utm_medium String
  , uriQuery__utm_source String
  , uriQuery__utm_campaign String
  , uriQuery__utm_term String
  , uriQuery__utm_content String
  , uriQuery__yclid String
  , uriQuery__region String
 
) Engine = MergeTree()
PARTITION BY toYYYYMM(logdate)
ORDER BY (fld_app_name, fld_app_module, logdatetime)
SETTINGS index_granularity = 8192;

Usamos a partición predeterminada (por mes) e a granularidade do índice. Todos os campos corresponden practicamente a entradas de rexistro de IIS para rexistrar solicitudes http. Separadamente, observamos que hai campos separados para almacenar etiquetas utm (son analizadas na fase de inserción na táboa desde o campo da cadea de consulta).

Ademais, engadíronse varios campos do sistema á táboa para almacenar información sobre sistemas, compoñentes e servidores. Consulte a táboa seguinte para ver unha descrición destes campos. Nunha táboa, almacenamos rexistros de varios sistemas.

nome

Descrición

Exemplo

fld_app_name

Nome da aplicación/sistema
Valores válidos:

  • site1.domain.com Sitio externo 1
  • site2.domain.com Sitio externo 2
  • internal-site1.domain.local Sitio interno 1

sitio1.dominio.com

fld_app_module

Módulo do sistema
Valores válidos:

  • web - Sitio web
  • svc - Servizo de sitio web
  • intgr - Servizo web de integración
  • bo - Administrador (BackOffice)

tea

fld_website_name

Nome do sitio en IIS

Pódense implementar varios sistemas nun servidor ou incluso varias instancias dun módulo do sistema

web principal

fld_server_name

Nome do servidor

web1.dominio.com

fld_log_file_name

Ruta ao ficheiro de rexistro no servidor

C:inetpublogsLogFiles
W3SVC1u_ex190711.log

Isto permítelle construír gráficos de forma eficiente en Grafana. Por exemplo, ver solicitudes desde a interface dun sistema en particular. Isto é semellante ao contador do sitio en Yandex.Metrica.

Aquí tes algunhas estatísticas sobre o uso da base de datos durante dous meses.

Número de rexistros desagregados por sistemas e os seus compoñentes

SELECT
    fld_app_name,
    fld_app_module,
    count(fld_app_name) AS rows_count
FROM log_web
GROUP BY
    fld_app_name,
    fld_app_module
    WITH TOTALS
ORDER BY
    fld_app_name ASC,
    rows_count DESC
 
┌─fld_app_name─────┬─fld_app_module─┬─rows_count─┐
│ site1.domain.ru  │ web            │     131441 │
│ site2.domain.ru  │ web            │    1751081 │
│ site3.domain.ru  │ web            │  106887543 │
│ site3.domain.ru  │ svc            │   44908603 │
│ site3.domain.ru  │ intgr          │    9813911 │
│ site4.domain.ru  │ web            │     772095 │
│ site5.domain.ru  │ web            │   17037221 │
│ site5.domain.ru  │ intgr          │     838559 │
│ site5.domain.ru  │ bo             │       7404 │
│ site6.domain.ru  │ web            │     595877 │
│ site7.domain.ru  │ web            │   27778858 │
└──────────────────┴────────────────┴────────────┘
 
Totals:
┌─fld_app_name─┬─fld_app_module─┬─rows_count─┐
│              │                │  210522593 │
└──────────────┴────────────────┴────────────┘
 
11 rows in set. Elapsed: 4.874 sec. Processed 210.52 million rows, 421.67 MB (43.19 million rows/s., 86.51 MB/s.)

A cantidade de datos no disco

SELECT
    formatReadableSize(sum(data_uncompressed_bytes)) AS uncompressed,
    formatReadableSize(sum(data_compressed_bytes)) AS compressed,
    sum(rows) AS total_rows
FROM system.parts
WHERE table = 'log_web'
 
┌─uncompressed─┬─compressed─┬─total_rows─┐
│ 54.50 GiB    │ 4.86 GiB   │  211427094 │
└──────────────┴────────────┴────────────┘
 
1 rows in set. Elapsed: 0.035 sec.

Grao de compresión de datos en columnas

SELECT
    name,
    formatReadableSize(data_uncompressed_bytes) AS uncompressed,
    formatReadableSize(data_compressed_bytes) AS compressed,
    data_uncompressed_bytes / data_compressed_bytes AS compress_ratio
FROM system.columns
WHERE table = 'log_web'
 
┌─name───────────────────┬─uncompressed─┬─compressed─┬─────compress_ratio─┐
│ logdate                │ 401.53 MiB   │ 1.80 MiB   │ 223.16665968777315 │
│ logdatetime            │ 803.06 MiB   │ 35.91 MiB  │ 22.363966401202305 │
│ fld_log_file_name      │ 220.66 MiB   │ 2.60 MiB   │  84.99905736932571 │
│ fld_server_name        │ 201.54 MiB   │ 50.63 MiB  │  3.980924816977078 │
│ fld_app_name           │ 201.17 MiB   │ 969.17 KiB │ 212.55518183686877 │
│ fld_app_module         │ 201.17 MiB   │ 968.60 KiB │ 212.67805817411906 │
│ fld_website_name       │ 201.54 MiB   │ 1.24 MiB   │  162.7204926761546 │
│ serverIP               │ 201.54 MiB   │ 50.25 MiB  │  4.010824061219731 │
│ method                 │ 201.53 MiB   │ 43.64 MiB  │  4.617721053304486 │
│ uriStem                │ 5.13 GiB     │ 832.51 MiB │  6.311522291936919 │
│ uriQuery               │ 2.58 GiB     │ 501.06 MiB │  5.269731450124478 │
│ port                   │ 803.06 MiB   │ 3.98 MiB   │ 201.91673864241824 │
│ username               │ 318.08 MiB   │ 26.93 MiB  │ 11.812513794583598 │
│ clientIP               │ 2.35 GiB     │ 82.59 MiB  │ 29.132328640073343 │
│ clientRealIP           │ 2.49 GiB     │ 465.05 MiB │  5.478382297052563 │
│ userAgent              │ 18.34 GiB    │ 764.08 MiB │  24.57905114484208 │
│ referer                │ 14.71 GiB    │ 1.37 GiB   │ 10.736792723669906 │
│ response               │ 803.06 MiB   │ 83.81 MiB  │  9.582334090987247 │
│ subresponse            │ 399.87 MiB   │ 1.83 MiB   │  218.4831068635027 │
│ win32response          │ 407.86 MiB   │ 7.41 MiB   │ 55.050315514606815 │
│ timetaken              │ 1.57 GiB     │ 402.06 MiB │ 3.9947395692010637 │
│ uriQuery__utm_medium   │ 208.17 MiB   │ 12.29 MiB  │ 16.936148912472955 │
│ uriQuery__utm_source   │ 215.18 MiB   │ 13.00 MiB  │ 16.548367623199912 │
│ uriQuery__utm_campaign │ 381.46 MiB   │ 37.94 MiB  │ 10.055156353418509 │
│ uriQuery__utm_term     │ 231.82 MiB   │ 10.78 MiB  │ 21.502540454070672 │
│ uriQuery__utm_content  │ 441.34 MiB   │ 87.60 MiB  │  5.038260760449327 │
│ uriQuery__yclid        │ 216.88 MiB   │ 16.58 MiB  │  13.07721335008116 │
│ uriQuery__region       │ 204.35 MiB   │ 9.49 MiB   │  21.52661903446796 │
└────────────────────────┴──────────────┴────────────┴────────────────────┘
 
28 rows in set. Elapsed: 0.005 sec.

Descrición dos compoñentes empregados

FileBeat. Transferencia de rexistros de ficheiros

Este compoñente rastrexa os cambios nos ficheiros de rexistro no disco e pasa a información a LogStash. Instalado en todos os servidores onde se escriben ficheiros de rexistro (normalmente IIS). Funciona en modo cola (é dicir, transfire só os rexistros engadidos ao ficheiro). Pero por separado pódese configurar para transferir ficheiros enteiros. Isto é útil cando necesitas descargar datos de meses anteriores. Só tes que poñer o ficheiro de rexistro nun cartafol e lerao na súa totalidade.

Cando se detén o servizo, os datos xa non se transfiren ao almacenamento.

Un exemplo de configuración é así:

filebeat.yml

filebeat.inputs:
- type: log
  enabled: true
  paths:
    - C:/inetpub/logs/LogFiles/W3SVC1/*.log
  exclude_files: ['.gz$','.zip$']
  tail_files: true
  ignore_older: 24h
  fields:
    fld_server_name: "site1.domain.ru"
    fld_app_name: "site1.domain.ru"
    fld_app_module: "web"
    fld_website_name: "web-main"
 
- type: log
  enabled: true
  paths:
    - C:/inetpub/logs/LogFiles/__Import/access_log-*
  exclude_files: ['.gz$','.zip$']
  tail_files: false
  fields:
    fld_server_name: "site2.domain.ru"
    fld_app_name: "site2.domain.ru"
    fld_app_module: "web"
    fld_website_name: "web-main"
    fld_logformat: "logformat__apache"
 
 
filebeat.config.modules:
  path: ${path.config}/modules.d/*.yml
  reload.enabled: false
  reload.period: 2s
 
output.logstash:
  hosts: ["log.domain.com:5044"]
 
  ssl.enabled: true
  ssl.certificate_authorities: ["C:/filebeat/certs/ca.pem", "C:/filebeat/certs/ca-issuing.pem"]
  ssl.certificate: "C:/filebeat/certs/site1.domain.ru.cer"
  ssl.key: "C:/filebeat/certs/site1.domain.ru.key"
 
#================================ Processors =====================================
 
processors:
  - add_host_metadata: ~
  - add_cloud_metadata: ~

logstash. Recolector de rexistros

Este compoñente está deseñado para recibir entradas de rexistro de FileBeat (ou a través da cola RabbitMQ), analizando e inserindo lotes na base de datos ClickHouse.

Para a inserción en ClickHouse, úsase o complemento Logstash-output-clickhouse. O complemento Logstash ten un mecanismo de reintento de solicitude, pero cun apagado regular, é mellor deter o servizo en si. Cando se deteña, as mensaxes acumularanse na cola de RabbitMQ, polo que se a parada é durante moito tempo, é mellor deter Filebeats nos servidores. Nun esquema onde RabbitMQ non se usa (na rede local, Filebeat envía directamente rexistros a Logstash), Filebeats funciona de forma bastante aceptable e segura, polo que para eles a indisponibilidade da saída pasa sen consecuencias.

Un exemplo de configuración é así:

log_web__filebeat_clickhouse.conf

input {
 
    beats {
        port => 5044
        type => 'iis'
        ssl => true
        ssl_certificate_authorities => ["/etc/logstash/certs/ca.cer", "/etc/logstash/certs/ca-issuing.cer"]
        ssl_certificate => "/etc/logstash/certs/server.cer"
        ssl_key => "/etc/logstash/certs/server-pkcs8.key"
        ssl_verify_mode => "peer"
 
            add_field => {
                "fld_server_name" => "%{[fields][fld_server_name]}"
                "fld_app_name" => "%{[fields][fld_app_name]}"
                "fld_app_module" => "%{[fields][fld_app_module]}"
                "fld_website_name" => "%{[fields][fld_website_name]}"
                "fld_log_file_name" => "%{source}"
                "fld_logformat" => "%{[fields][fld_logformat]}"
            }
    }
 
    rabbitmq {
        host => "queue.domain.com"
        port => 5671
        user => "q-reader"
        password => "password"
        queue => "web_log"
        heartbeat => 30
        durable => true
        ssl => true
        #ssl_certificate_path => "/etc/logstash/certs/server.p12"
        #ssl_certificate_password => "password"
 
        add_field => {
            "fld_server_name" => "%{[fields][fld_server_name]}"
            "fld_app_name" => "%{[fields][fld_app_name]}"
            "fld_app_module" => "%{[fields][fld_app_module]}"
            "fld_website_name" => "%{[fields][fld_website_name]}"
            "fld_log_file_name" => "%{source}"
            "fld_logformat" => "%{[fields][fld_logformat]}"
        }
    }
 
}
 
filter { 
 
      if [message] =~ "^#" {
        drop {}
      }
 
      if [fld_logformat] == "logformat__iis_with_xrealip" {
     
          grok {
            match => ["message", "%{TIMESTAMP_ISO8601:log_timestamp} %{IP:serverIP} %{WORD:method} %{NOTSPACE:uriStem} %{NOTSPACE:uriQuery} %{NUMBER:port} %{NOTSPACE:username} %{IPORHOST:clientIP} %{NOTSPACE:userAgent} %{NOTSPACE:referer} %{NUMBER:response} %{NUMBER:subresponse} %{NUMBER:win32response} %{NUMBER:timetaken} %{NOTSPACE:xrealIP} %{NOTSPACE:xforwarderfor}"]
          }
      } else {
   
          grok {
             match => ["message", "%{TIMESTAMP_ISO8601:log_timestamp} %{IP:serverIP} %{WORD:method} %{NOTSPACE:uriStem} %{NOTSPACE:uriQuery} %{NUMBER:port} %{NOTSPACE:username} %{IPORHOST:clientIP} %{NOTSPACE:userAgent} %{NOTSPACE:referer} %{NUMBER:response} %{NUMBER:subresponse} %{NUMBER:win32response} %{NUMBER:timetaken}"]
          }
 
      }
 
      date {
        match => [ "log_timestamp", "YYYY-MM-dd HH:mm:ss" ]
          timezone => "Etc/UTC"
        remove_field => [ "log_timestamp", "@timestamp" ]
        target => [ "log_timestamp2" ]
      }
 
        ruby {
            code => "tstamp = event.get('log_timestamp2').to_i
                        event.set('logdatetime', Time.at(tstamp).strftime('%Y-%m-%d %H:%M:%S'))
                        event.set('logdate', Time.at(tstamp).strftime('%Y-%m-%d'))"
        }
 
      if [bytesSent] {
        ruby {
          code => "event['kilobytesSent'] = event['bytesSent'].to_i / 1024.0"
        }
      }
 
 
      if [bytesReceived] {
        ruby {
          code => "event['kilobytesReceived'] = event['bytesReceived'].to_i / 1024.0"
        }
      }
 
   
        ruby {
            code => "event.set('clientRealIP', event.get('clientIP'))"
        }
        if [xrealIP] {
            ruby {
                code => "event.set('clientRealIP', event.get('xrealIP'))"
            }
        }
        if [xforwarderfor] {
            ruby {
                code => "event.set('clientRealIP', event.get('xforwarderfor'))"
            }
        }
 
      mutate {
        convert => ["bytesSent", "integer"]
        convert => ["bytesReceived", "integer"]
        convert => ["timetaken", "integer"] 
        convert => ["port", "integer"]
 
        add_field => {
            "clientHostname" => "%{clientIP}"
        }
      }
 
        useragent {
            source=> "useragent"
            prefix=> "browser"
        }
 
        kv {
            source => "uriQuery"
            prefix => "uriQuery__"
            allow_duplicate_values => false
            field_split => "&"
            include_keys => [ "utm_medium", "utm_source", "utm_campaign", "utm_term", "utm_content", "yclid", "region" ]
        }
 
        mutate {
            join => { "uriQuery__utm_source" => "," }
            join => { "uriQuery__utm_medium" => "," }
            join => { "uriQuery__utm_campaign" => "," }
            join => { "uriQuery__utm_term" => "," }
            join => { "uriQuery__utm_content" => "," }
            join => { "uriQuery__yclid" => "," }
            join => { "uriQuery__region" => "," }
        }
 
}
 
output { 
  #stdout {codec => rubydebug}
    clickhouse {
      headers => ["Authorization", "Basic abcdsfks..."]
      http_hosts => ["http://127.0.0.1:8123"]
      save_dir => "/etc/logstash/tmp"
      table => "log_web"
      request_tolerance => 1
      flush_size => 10000
      idle_flush_time => 1
        mutations => {
            "fld_log_file_name" => "fld_log_file_name"
            "fld_server_name" => "fld_server_name"
            "fld_app_name" => "fld_app_name"
            "fld_app_module" => "fld_app_module"
            "fld_website_name" => "fld_website_name"
 
            "logdatetime" => "logdatetime"
            "logdate" => "logdate"
            "serverIP" => "serverIP"
            "method" => "method"
            "uriStem" => "uriStem"
            "uriQuery" => "uriQuery"
            "port" => "port"
            "username" => "username"
            "clientIP" => "clientIP"
            "clientRealIP" => "clientRealIP"
            "userAgent" => "userAgent"
            "referer" => "referer"
            "response" => "response"
            "subresponse" => "subresponse"
            "win32response" => "win32response"
            "timetaken" => "timetaken"
             
            "uriQuery__utm_medium" => "uriQuery__utm_medium"
            "uriQuery__utm_source" => "uriQuery__utm_source"
            "uriQuery__utm_campaign" => "uriQuery__utm_campaign"
            "uriQuery__utm_term" => "uriQuery__utm_term"
            "uriQuery__utm_content" => "uriQuery__utm_content"
            "uriQuery__yclid" => "uriQuery__yclid"
            "uriQuery__region" => "uriQuery__region"
        }
    }
 
}

canalizacións.yml

# This file is where you define your pipelines. You can define multiple.
# For more information on multiple pipelines, see the documentation:
#   https://www.elastic.co/guide/en/logstash/current/multiple-pipelines.html
 
- pipeline.id: log_web__filebeat_clickhouse
  path.config: "/etc/logstash/log_web__filebeat_clickhouse.conf"

clickhouse. Almacenamento de rexistros

Os rexistros de todos os sistemas gárdanse nunha soa táboa (ver ao comezo do artigo). Preténdese almacenar información sobre solicitudes: todos os parámetros son similares para diferentes formatos, como rexistros de IIS, rexistros de apache e nginx. Para os rexistros de aplicacións, nos que, por exemplo, se rexistran erros, mensaxes de información, avisos, proporcionarase unha táboa separada coa estrutura adecuada (actualmente na fase de deseño).

Ao deseñar unha táboa, é moi importante decidir a clave principal (pola cal se ordenarán os datos durante o almacenamento). Disto dependen o grao de compresión dos datos e a velocidade de consulta. No noso exemplo, a clave é
ORDE POR (fld_app_name, fld_app_module, logdatetime)
É dicir, polo nome do sistema, o nome do compoñente do sistema e a data do evento. Inicialmente, a data do evento foi a primeira. Despois de movelo ao último lugar, as consultas comezaron a funcionar aproximadamente o dobre de rápido. Cambiar a chave primaria requirirá recrear a táboa e volver cargar os datos para que ClickHouse reordena os datos no disco. Esta é unha operación pesada, polo que é unha boa idea pensar moito no que se debe incluír na clave de clasificación.

Tamén hai que ter en conta que o tipo de datos LowCardinality apareceu relativamente nas versións recentes. Ao usalo, o tamaño dos datos comprimidos redúcese drasticamente para aqueles campos que teñen baixa cardinalidade (poucas opcións).

A versión 19.6 está en uso e pensamos tentar actualizar á última versión. Teñen características tan marabillosas como Adaptive Granularity, Skipping indexes e o codec DoubleDelta, por exemplo.

Por defecto, durante a instalación, o nivel de rexistro está configurado para rastrexar. Os rexistros rótanse e arquivan, pero ao mesmo tempo se expanden ata un gigabyte. Se non hai necesidade, pode establecer o nivel de aviso, entón o tamaño do rexistro redúcese drasticamente. A configuración de rexistro está definida no ficheiro config.xml:

<!-- Possible levels: https://github.com/pocoproject/poco/blob/develop/Foundation/include/Poco/Logger. h#L105 -->
<level>warning</level>

Algúns comandos útiles

Поскольку оригинальные пакеты установки собираются по Debian, то для других версий Linux необходимо использовать пакеты собранные компанией Altinity.
 
Вот по этой ссылке есть инструкции с ссылками на их репозиторий: https://www.altinity.com/blog/2017/12/18/logstash-with-clickhouse
sudo yum search clickhouse-server
sudo yum install clickhouse-server.noarch
  
1. проверка статуса
sudo systemctl status clickhouse-server
 
2. остановка сервера
sudo systemctl stop clickhouse-server
 
3. запуск сервера
sudo systemctl start clickhouse-server
 
Запуск для выполнения запросов в многострочном режиме (выполнение после знака ";")
clickhouse-client --multiline
clickhouse-client --multiline --host 127.0.0.1 --password pa55w0rd
clickhouse-client --multiline --host 127.0.0.1 --port 9440 --secure --user default --password pa55w0rd
 
Плагин кликлауза для логстеш в случае ошибки в одной строке сохраняет всю пачку в файл /tmp/log_web_failed.json
Можно вручную исправить этот файл и попробовать залить его в БД вручную:
clickhouse-client --host 127.0.0.1 --password password --query="INSERT INTO log_web FORMAT JSONEachRow" < /tmp/log_web_failed__fixed.json
 
sudo mv /etc/logstash/tmp/log_web_failed.json /etc/logstash/tmp/log_web_failed__fixed.json
sudo chown user_dev /etc/logstash/tmp/log_web_failed__fixed.json
sudo clickhouse-client --host 127.0.0.1 --password password --query="INSERT INTO log_web FORMAT JSONEachRow" < /etc/logstash/tmp/log_web_failed__fixed.json
sudo mv /etc/logstash/tmp/log_web_failed__fixed.json /etc/logstash/tmp/log_web_failed__fixed_.json
 
выход из командной строки
quit;
## Настройка TLS
https://www.altinity.com/blog/2019/3/5/clickhouse-networking-part-2
 
openssl s_client -connect log.domain.com:9440 < /dev/null

logstash. Rexistra o enrutador de FileBeat á cola RabbitMQ

Este compoñente úsase para enrutar os rexistros procedentes de FileBeat á cola RabbitMQ. Aquí hai dous puntos:

  1. Desafortunadamente, FileBeat non ten un complemento de saída para escribir directamente en RabbitMQ. E tal funcionalidade, a xulgar polo problema no seu github, non está prevista para a súa implementación. Hai un complemento para Kafka, pero por algún motivo non podemos usalo na casa.
  2. Hai requisitos para recoller rexistros na DMZ. En función deles, primeiro deben engadirse os rexistros á cola e logo LogStash le as entradas da cola desde fóra.

Polo tanto, é para o caso en que os servidores están situados na DMZ que hai que usar un esquema tan complicado. Un exemplo de configuración é así:

iis_w3c_logs__filebeat_rabbitmq.conf

input {
 
    beats {
        port => 5044
        type => 'iis'
        ssl => true
        ssl_certificate_authorities => ["/etc/pki/tls/certs/app/ca.pem", "/etc/pki/tls/certs/app/ca-issuing.pem"]
        ssl_certificate => "/etc/pki/tls/certs/app/queue.domain.com.cer"
        ssl_key => "/etc/pki/tls/certs/app/queue.domain.com-pkcs8.key"
        ssl_verify_mode => "peer"
    }
 
}
 
output { 
  #stdout {codec => rubydebug}
 
    rabbitmq {
        host => "127.0.0.1"
        port => 5672
        exchange => "monitor.direct"
        exchange_type => "direct"
        key => "%{[fields][fld_app_name]}"
        user => "q-writer"
        password => "password"
        ssl => false
    }
}

CoelloMQ. fila de mensaxes

Este compoñente úsase para almacenar entradas de rexistro na DMZ. A gravación realízase a través de Filebeat → LogStash. A lectura realízase desde fóra da DMZ a través de LogStash. Cando se opera a través de RabboitMQ, procesan unhas 4 mil mensaxes por segundo.

O enrutamento de mensaxes está configurado polo nome do sistema, é dicir, en función dos datos de configuración de FileBeat. Todas as mensaxes van a unha cola. Se por algún motivo se detén o servizo de cola, isto non provocará a perda de mensaxes: FileBeats recibirá erros de conexión e suspenderá temporalmente o envío. E LogStash que le da cola tamén recibirá erros de rede e agardará a que se restaure a conexión. Neste caso, os datos, por suposto, xa non se escribirán na base de datos.

Para crear e configurar filas úsanse as seguintes instrucións:

sudo /usr/local/bin/rabbitmqadmin/rabbitmqadmin declare exchange --vhost=/ name=monitor.direct type=direct sudo /usr/local/bin/rabbitmqadmin/rabbitmqadmin declare queue --vhost=/ name=web_log durable=true
sudo /usr/local/bin/rabbitmqadmin/rabbitmqadmin --vhost="/" declare binding source="monitor.direct" destination_type="queue" destination="web_log" routing_key="site1.domain.ru"
sudo /usr/local/bin/rabbitmqadmin/rabbitmqadmin --vhost="/" declare binding source="monitor.direct" destination_type="queue" destination="web_log" routing_key="site2.domain.ru"

Grafana. Paneis de mando

Este compoñente úsase para visualizar os datos de seguimento. Neste caso, cómpre instalar a fonte de datos ClickHouse para o complemento Grafana 4.6+. Tivemos que axustalo un pouco para mellorar a eficiencia do procesamento de filtros SQL no panel.

Por exemplo, usamos variables e, se non están definidas no campo de filtro, gustaríanos que non xerase unha condición no WHERE do formulario ( uriStem = » AND uriStem != » ). Neste caso, ClickHouse lerá a columna uriStem. En xeral, probamos diferentes opcións e finalmente corriximos o complemento (a macro $valueIfEmpty) para que no caso dun valor baleiro devolva 1, sen mencionar a propia columna.

E agora podes usar esta consulta para o gráfico

$columns(response, count(*) c) from $table where $adhoc
and $valueIfEmpty($fld_app_name, 1, fld_app_name = '$fld_app_name')
and $valueIfEmpty($fld_app_module, 1, fld_app_module = '$fld_app_module') and $valueIfEmpty($fld_server_name, 1, fld_server_name = '$fld_server_name') and $valueIfEmpty($uriStem, 1, uriStem like '%$uriStem%')
and $valueIfEmpty($clientRealIP, 1, clientRealIP = '$clientRealIP')

que se traduce a este SQL (teña en conta que os campos uriStem baleiros convertéronse en só 1)

SELECT
t,
groupArray((response, c)) AS groupArr
FROM (
SELECT
(intDiv(toUInt32(logdatetime), 60) * 60) * 1000 AS t, response,
count(*) AS c FROM default.log_web
WHERE (logdate >= toDate(1565061982)) AND (logdatetime >= toDateTime(1565061982)) AND 1 AND (fld_app_name = 'site1.domain.ru') AND (fld_app_module = 'web') AND 1 AND 1 AND 1
GROUP BY
t, response
ORDER BY
t ASC,
response ASC
)
GROUP BY t ORDER BY t ASC

Conclusión

A aparición da base de datos ClickHouse converteuse nun evento histórico no mercado. Era difícil imaxinar que, de forma totalmente gratuíta, nun instante nos armamos cunha ferramenta poderosa e práctica para traballar con big data. Por suposto, co aumento das necesidades (por exemplo, fragmentación e replicación en varios servidores), o esquema farase máis complicado. Pero nas primeiras impresións, traballar con esta base de datos é moi agradable. Pódese ver que o produto está feito "para as persoas".

En comparación con ElasticSearch, estímase que o custo de almacenamento e procesamento dos rexistros se reduce de cinco a dez veces. Noutras palabras, se para a cantidade actual de datos teriamos que configurar un clúster de varias máquinas, cando se usa ClickHouse, unha máquina de baixo consumo é suficiente para nós. Si, por suposto, ElasticSearch tamén ten mecanismos de compresión de datos no disco e outras funcións que poden reducir significativamente o consumo de recursos, pero en comparación con ClickHouse, isto será máis caro.

Sen optimizacións especiais da nosa parte, na configuración predeterminada, a carga de datos e a selección da base de datos funciona a unha velocidade sorprendente. Aínda non temos moitos datos (uns 200 millóns de rexistros), pero o servidor en si é débil. Poderemos utilizar esta ferramenta no futuro para outros fins non relacionados co almacenamento de rexistros. Por exemplo, para a análise de extremo a extremo, no ámbito da seguridade, a aprendizaxe automática.

Ao final, un pouco sobre os pros e contras.

Contra

  1. Cargando rexistros en grandes lotes. Por unha banda, esta é unha característica, pero aínda tes que usar compoñentes adicionais para almacenar rexistros no búfer. Esta tarefa non sempre é fácil, pero aínda así é resolubel. E gustaríame simplificar o esquema.
  2. Algunhas funcións exóticas ou novas funcións adoitan romperse nas novas versións. Isto causa preocupación, reducindo o desexo de actualizar a unha nova versión. Por exemplo, o motor de táboas de Kafka é unha característica moi útil que che permite ler directamente eventos de Kafka, sen implementar consumidores. Pero a xulgar polo número de problemas no github, aínda temos coidado de non usar este motor na produción. Non obstante, se non fai xestos bruscos cara ao lado e usa a función principal, entón funcionará de forma estable.

Pros

  1. Non ralentiza.
  2. Limiar de entrada baixo.
  3. Código aberto.
  4. Libre.
  5. Escala ben (fragmento/replicación fóra da caixa)
  6. Incluído no rexistro de software ruso recomendado polo Ministerio de Comunicacións.
  7. A presenza de apoio oficial de Yandex.

Fonte: www.habr.com

Engadir un comentario