Base de dades ClickHouse per a humans o tecnologies alienígenes

Alexey Lizunov, cap del centre de competència per a canals de servei remot de la Direcció de Tecnologies de la Informació de l'ICB

Base de dades ClickHouse per a humans o tecnologies alienígenes

Com a alternativa a la pila ELK (ElasticSearch, Logstash, Kibana), estem realitzant investigacions sobre l'ús de la base de dades ClickHouse com a emmagatzematge de dades per als registres.

En aquest article ens agradaria parlar de la nostra experiència amb la base de dades ClickHouse i dels resultats preliminars de l'operació pilot. Val la pena assenyalar de seguida que els resultats van ser impressionants.


Base de dades ClickHouse per a humans o tecnologies alienígenes

A continuació descriurem amb més detall com està configurat el nostre sistema i de quins components consta. Però ara m'agradaria parlar una mica d'aquesta base de dades en el seu conjunt i per què val la pena parar-hi atenció. La base de dades ClickHouse és una base de dades columnar analítica d'alt rendiment de Yandex. S'utilitza als serveis Yandex, inicialment aquest és l'emmagatzematge de dades principal per a Yandex.Metrica. Sistema de codi obert, gratuït. Des del punt de vista d'un desenvolupador, sempre em vaig preguntar com ho van implementar, perquè hi ha dades fantàsticament grans. I la interfície d'usuari de Metrica és molt flexible i funciona ràpidament. Quan us familiaritzeu amb aquesta base de dades, teniu la impressió: “Bé, per fi! Fet "per al poble"! Des del procés d'instal·lació fins a l'enviament de sol·licituds."

Aquesta base de dades té una barrera d'entrada molt baixa. Fins i tot un desenvolupador mitjà pot instal·lar aquesta base de dades en pocs minuts i començar a utilitzar-la. Tot funciona sense problemes. Fins i tot les persones que són noves a Linux poden fer front ràpidament a la instal·lació i fer operacions senzilles. Si abans, en escoltar les paraules Big Data, Hadoop, Google BigTable, HDFS, el desenvolupador mitjà tenia la idea que parlaven d'uns terabytes, petabytes, que alguns superhumans estaven implicats en la configuració i desenvolupament d'aquests sistemes, llavors amb l'arribada de la base de dades ClickHouse tenim una eina senzilla i entenedora amb la qual podeu resoldre una sèrie de problemes abans inabastables. Tot el que es necessita és una màquina bastant mitjana i cinc minuts per instal·lar-se. És a dir, tenim una base de dades com, per exemple, MySql, però només per emmagatzemar milers de milions de registres! Una mena de superarxiu amb llenguatge SQL. És com si a la gent li donessin armes alienígenes.

Sobre el nostre sistema de recollida de registres

Per recopilar informació, s'utilitzen fitxers de registre d'IIS d'aplicacions web de format estàndard (actualment també ens dediquem a analitzar els registres d'aplicacions, però el nostre objectiu principal a l'etapa pilot és recollir registres d'IIS).

No hem pogut abandonar completament la pila ELK per diversos motius, i seguim utilitzant els components LogStash i Filebeat, que han demostrat ser bons i funcionen de manera bastant fiable i previsible.

L'esquema general de registre es mostra a la figura següent:

Base de dades ClickHouse per a humans o tecnologies alienígenes

Una característica de l'enregistrament de dades a la base de dades ClickHouse és la inserció poc freqüent (un cop per segon) de registres en grans lots. Aquesta, aparentment, és la part més "problemàtica" que trobeu quan treballeu amb la base de dades ClickHouse per primera vegada: l'esquema es complica una mica.
El connector per a LogStash, que insereix dades directament a ClickHouse, va ajudar molt aquí. Aquest component es desplega al mateix servidor que la pròpia base de dades. Així doncs, en general, no es recomana fer-ho, sinó des d'un punt de vista pràctic, per no crear servidors separats mentre es desplega al mateix servidor. No vam observar cap error ni conflicte de recursos amb la base de dades. A més, cal tenir en compte que el connector té un mecanisme de retransmissió en cas d'error. I en cas d'error, el connector escriu al disc un lot de dades que no s'han pogut inserir (el format del fitxer és convenient: després de l'edició, podeu inserir fàcilment el lot corregit mitjançant clickhouse-client).

A la taula es presenta una llista completa del programari utilitzat en l'esquema:

Llista de programari utilitzat

Nom

Descripció

Enllaç a la distribució

NGINX

Proxy invers per restringir l'accés per port i organitzar l'autorització

Actualment no s'utilitza en l'esquema

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

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

FileBeat

Transferència de registres de fitxers.

https://www.elastic.co/downloads/beats/filebeat (distribució per a Windows 64 bits).

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

LogStash

Recollidor de troncs.

S'utilitza per recopilar registres de FileBeat, així com per recopilar registres de la cua RabbitMQ (per als servidors que es troben a la DMZ).

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

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

Logstash - sortida - clickhouse

Connector Loagstash per transferir registres a la base de dades ClickHouse per lots

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

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

/usr/share/logstash/bin/logstash-plugin instal·lar logstash-filter-prune

/usr/share/logstash/bin/logstash-plugin instal·lar logstash-filter-multiline

Feu clic a Casa

Emmagatzematge de registres 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 l'agost de 2018, les compilacions de rpm "normals" per a RHEL van aparèixer al repositori Yandex, de manera que podeu provar d'utilitzar-les. En el moment de la instal·lació estàvem utilitzant paquets compilats per Altinity.

Grafana

Visualització de registres. Configuració de taulers de control

https://grafana.com/

https://grafana.com/grafana/download

Redhat i Centos (64 bits): darrera versió

Font de dades ClickHouse per a Grafana 4.6+

Connector per a Grafana amb font de dades ClickHouse

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

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

LogStash

Registra l'encaminador de FileBeat a la cua RabbitMQ.

Nota. Malauradament, FileBeat no té sortida directament a RabbitMQ, de manera que es requereix un enllaç intermedi en forma de Logstash

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

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

ConillMQ

Cua de missatges. Aquest és un buffer d'entrades de registre a la 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

Temps d'execució Erlang (necessari per a RabbitMQ)

Temps d'execució Erlang. Necessari perquè RabbitMQ funcioni

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

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

La configuració del servidor amb la base de dades ClickHouse es presenta a la taula següent:

Nom

Valor

Nota

Configuració

Disc dur: 40 GB
RAM: 8GB
Processador: Core 2 2Ghz

Heu de parar atenció als consells per utilitzar la base de dades ClickHouse (https://clickhouse.yandex/docs/ru/operations/tips/)

Programari per a tot el sistema

Sistema operatiu: Red Hat Enterprise Linux Server (Maipo)

JRE (Java 8)

 

Com podeu veure, aquesta és una estació de treball normal.

L'estructura de la taula per emmagatzemar els registres és la següent:

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;

Utilitzem valors predeterminats per a la partició (mensual) i la granularitat de l'índex. Tots els camps corresponen pràcticament a les entrades de registre d'IIS per registrar les sol·licituds http. Per separat, observem que hi ha camps separats per emmagatzemar etiquetes utm (s'analitzen en l'etapa d'inserció a la taula des del camp de la cadena de consulta).

A més, s'han afegit diversos camps del sistema a la taula per emmagatzemar informació sobre sistemes, components i servidors. Per obtenir una descripció d'aquests camps, consulteu la taula següent. En una taula emmagatzemem els registres de diversos sistemes.

Nom

Descripció

Exemple

fld_app_name

Nom de l'aplicació/sistema
Valors vàlids:

  • lloc1.domini.com Lloc extern 1
  • lloc2.domini.com Lloc extern 2
  • lloc intern1.domini.local Lloc intern 1

lloc1.domini.com

fld_app_module

Mòdul del sistema
Valors vàlids:

  • web - Lloc web
  • svc — Servei web del lloc web
  • intgr — Servei d'integració web
  • bo — Administrador (BackOffice)

web

fld_nom_website

Nom del lloc a IIS

Es poden desplegar diversos sistemes en un servidor, o fins i tot diverses instàncies d'un mòdul del sistema

web-principal

fld_server_name

Nom del servidor

web1.domini.com

fld_log_file_name

Ruta al fitxer de registre al servidor

Des de:inetpublogsLogFiles
W3SVC1u_ex190711.log

Això us permet crear gràfics de manera eficient a Grafana. Per exemple, visualitzeu les sol·licituds des de la part frontal d'un sistema específic. Això és similar al comptador del lloc a Yandex.Metrica.

Aquí teniu algunes estadístiques sobre l'ús de la base de dades durant dos mesos.

Nombre de registres per sistema i component

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.)

Volum de dades del disc

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.

Relació de compressió de dades de columna

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.

Descripció dels components utilitzats

FileBeat. Transferència de registres de fitxers

Aquest component supervisa els canvis als fitxers de registre del disc i passa la informació a LogStash. Instal·lat a tots els servidors on s'escriuen fitxers de registre (normalment IIS). Funciona en mode de cua (és a dir, només transfereix registres afegits al fitxer). Però podeu configurar-lo per separat per transferir fitxers sencers. Això és convenient quan necessiteu descarregar dades dels mesos anteriors. Només cal posar el fitxer de registre en una carpeta i el llegirà sencer.

Quan el servei s'atura, les dades es deixen de transferir a l'emmagatzematge.

Un exemple de configuració és el següent:

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. Col·lector de registres

Aquest component està dissenyat per rebre registres de registre de FileBeat (o mitjançant una cua RabbitMQ), analitzar-los i inserir-los per lots a la base de dades ClickHouse.

Per inserir-lo a ClickHouse, utilitzeu el connector Logstash-output-clickhouse. El connector Logstash té un mecanisme per recuperar les sol·licituds, però durant un tancament regular, és millor aturar el servei en si. Quan s'atura, els missatges s'acumularan a la cua RabbitMQ, de manera que si l'aturada és durant molt de temps, és millor aturar Filebeats als servidors. En un esquema on RabbitMQ no s'utilitza (a la xarxa local Filebeat envia directament els registres a Logstash), Filebeats funcionen bastant acceptable i segur, de manera que per a ells la indisponibilitat de la sortida no té conseqüències.

Un exemple de configuració és el següent:

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"
        }
    }
 
}

pipelines.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. Emmagatzematge de registres

Els registres de tots els sistemes es guarden en una taula (vegeu al principi de l'article). Està dissenyat per emmagatzemar informació sobre sol·licituds: tots els paràmetres són similars per a diferents formats, per exemple, registres d'IIS, registres d'apache i nginx. Per als registres d'aplicacions en què, per exemple, es registren errors, missatges d'informació i avisos, es proporcionarà una taula separada amb l'estructura adequada (actualment en fase de disseny).

Quan es dissenya una taula, és molt important decidir la clau primària (per la qual s'ordenaran les dades durant l'emmagatzematge). D'això depèn el grau de compressió de dades i la velocitat de consulta. En el nostre exemple, la clau és
ORDER BY (nom_aplicació_fld, mòdul_aplicació_fld, datahora)
És a dir, pel nom del sistema, el nom del component del sistema i la data de l'esdeveniment. Inicialment, la data de l'esdeveniment va ser primer. Després de traslladar-lo a l'últim lloc, les consultes van començar a funcionar aproximadament el doble de ràpid. Per canviar la clau primària caldrà tornar a crear la taula i tornar a carregar les dades perquè ClickHouse torni a ordenar les dades al disc. Aquesta és una operació difícil, per la qual cosa s'aconsella pensar detingudament per endavant què s'ha d'incloure a la clau d'ordenació.

També cal tenir en compte que el tipus de dades LowCardinality va aparèixer en versions relativament recents. Quan s'utilitza, la mida de les dades comprimides es redueix dràsticament per als camps que tenen poca cardinalitat (poques opcions).

Actualment estem utilitzant la versió 19.6 i tenim previst intentar actualitzar-la a la darrera versió. Tenen funcions tan meravelloses com la granularitat adaptativa, els índexs de salt i el còdec DoubleDelta, per exemple.

Per defecte, durant la instal·lació, el nivell de registre de configuració s'estableix com a traça. Els registres es giren i s'arxiven, però al mateix temps s'expandeixen fins a un gigabyte. Si no cal, podeu configurar el nivell d'avís i la mida del registre disminuirà bruscament. La configuració de registre s'especifica al fitxer config.xml:

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

Algunes ordres útils

Поскольку оригинальные пакеты установки собираются по 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. Registra l'encaminador de FileBeat a la cua RabbitMQ

Aquest component s'utilitza per encaminar els registres procedents de FileBeat a la cua RabbitMQ. Aquí hi ha dos punts:

  1. Malauradament, FileBeat no té un connector de sortida per escriure directament a RabbitMQ. I aquesta funcionalitat, a jutjar per la publicació del seu github, no està prevista per a la implementació. Hi ha un connector per a Kafka, però per certs motius no el podem utilitzar nosaltres mateixos.
  2. Hi ha requisits per recopilar registres a la DMZ. En funció d'ells, primer s'han de posar en cua els registres i després LogStash llegeix els registres de la cua externament.

Per tant, específicament per al cas dels servidors situats en una DMZ, cal utilitzar un esquema tan lleugerament complicat. Un exemple de configuració és el següent:

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
    }
}

ConillMQ. Cua de missatges

Aquest component s'utilitza per guardar les entrades de registre a la DMZ. La gravació es fa mitjançant l'enllaç Filebeat → LogStash. La lectura es fa des de fora de la DMZ mitjançant LogStash. Quan es treballa a través de RabbitMQ, es processen uns 4 mil missatges per segon.

L'encaminament dels missatges es configura pel nom del sistema, és a dir, en funció de les dades de configuració de FileBeat. Tots els missatges van a una cua. Si per algun motiu el servei de cua s'atura, això no comportarà la pèrdua de missatges: FileBeats rebrà errors de connexió i deixarà d'enviar-se temporalment. I LogStash, que llegeix des de la cua, també rebrà errors de xarxa i esperarà que es restableixi la connexió. En aquest cas, per descomptat, les dades ja no s'escriuran a la base de dades.

Les instruccions següents s'utilitzen per crear i configurar cues:

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. Taulers de control

Aquest component s'utilitza per visualitzar les dades de seguiment. En aquest cas, heu d'instal·lar la font de dades ClickHouse per al connector Grafana 4.6+. Hem hagut de modificar-lo una mica per millorar l'eficiència del processament dels filtres SQL al tauler.

Per exemple, utilitzem variables, i si no s'especifiquen al camp de filtre, voldríem que no generi cap condició en el ON del formulari ( uriStem = "AND uriStem != "). En aquest cas, ClickHouse llegirà la columna uriStem. Així doncs, vam provar diferents opcions i finalment vam arreglar el connector (la macro $valueIfEmpty) perquè retornés 1 en cas d'un valor buit, sense esmentar la pròpia columna.

I ara podeu utilitzar aquesta consulta per al gràfic

$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 es converteix a SQL així (tingueu en compte que els camps uriStem buits es converteixen només en 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ó

L'aparició de la base de dades ClickHouse s'ha convertit en un esdeveniment referent al mercat. Era difícil imaginar que en un instant, de forma totalment gratuïta, estiguéssim armats amb una eina potent i pràctica per treballar amb big data. Per descomptat, a mesura que augmenten les necessitats (per exemple, fragmentació i rèplica a diversos servidors), l'esquema es farà més complex. Però segons les primeres impressions, treballar amb aquesta base de dades és molt agradable. És evident que el producte està fet “per a la gent”.

En comparació amb ElasticSearch, el cost d'emmagatzemar i processar els registres, segons estimacions preliminars, es redueix de cinc a deu vegades. En altres paraules, si per al volum actual de dades hauríem de configurar un clúster de diverses màquines, quan utilitzem ClickHouse només necessitem una màquina de baix consum. Sí, per descomptat, ElasticSearch també té mecanismes de compressió de dades al disc i altres característiques que poden reduir significativament el consum de recursos, però en comparació amb ClickHouse això requerirà costos més grans.

Sense cap optimització especial per part nostra, amb la configuració predeterminada, la càrrega de dades i la recuperació de la base de dades funciona a una velocitat increïble. Encara no tenim moltes dades (uns 200 milions de registres), però el servidor en si és feble. Podem utilitzar aquesta eina en el futur per a altres finalitats no relacionades amb l'emmagatzematge de registres. Per exemple, per a l'anàlisi d'extrem a extrem, en l'àmbit de la seguretat, l'aprenentatge automàtic.

Al final, una mica sobre els pros i els contres.

Contres

  1. Càrrega de registres en lots grans. D'una banda, aquesta és una característica, però encara heu d'utilitzar components addicionals per guardar els registres. Aquesta tasca no sempre és senzilla, però encara es pot resoldre. I m'agradaria simplificar l'esquema.
  2. Algunes funcionalitats exòtiques o noves característiques solen trencar-se en les noves versions. Això genera preocupacions, reduint el desig d'actualitzar a una versió nova. Per exemple, el motor de taula de Kafka és una característica molt útil que us permet llegir directament els esdeveniments de Kafka, sense implementar els consumidors. Però a jutjar pel nombre de problemes a Github, encara estem desconfiats d'utilitzar aquest motor en producció. Tanmateix, si no feu moviments bruscos cap al costat i utilitzeu la funcionalitat bàsica, funciona de manera estable.

Pros

  1. No s'alenteix.
  2. Llindar d'entrada baix.
  3. Codi obert.
  4. Gratuït.
  5. Escalable (fragmentació/replicació immediata)
  6. Inclòs al registre de programari rus recomanat pel Ministeri de Comunicacions.
  7. Disponibilitat de suport oficial de Yandex.

Font: www.habr.com

Afegeix comentari