BD ClickHouse per le persone, o Tecnologie spaziali

Aleksey Lizunov, responsabile del centro di competenza per i canali di servizio a distanza della direzione delle tecnologie informative di MKB

BD ClickHouse per le persone, o Tecnologie spaziali

In alternativa al stack ELK (ElasticSearch, Logstash, Kibana), stiamo conducenti studi sull'uso del database ClickHouse come archivio dati per i log.

In questo articolo desideriamo condividere la nostra esperienza con il database ClickHouse e i risultati preliminari emersi dalla fase pilota. È importante sottolineare fin da subito che i risultati sono stati impressionanti.


BD ClickHouse per le persone, o Tecnologie spaziali

Di seguito descriveremo in dettaglio come è configurato il nostro sistema e quali componenti lo compongono. Ma ora vorremmo parlare un po' di questo database in generale e del motivo per cui merita attenzione. Il database ClickHouse è un sistema di gestione dei database colonnare ad alte prestazioni sviluppato da Yandex. Viene utilizzato nei servizi di Yandex ed è originariamente il principale repository di dati per Yandex.Metrica. È un sistema open-source e gratuito. Da sviluppatore, sono sempre stato curioso di capire come sia stato realizzato, considerando i volumi di dati enormi. Anche l'interfaccia utente di Metrica è molto flessibile e reattiva. Alla prima conoscenza con questo database, l'impressione è stata: "Finalmente! È stato fatto 'per le persone'! Dalla procedura di installazione all'invio delle query."

Questo DB ha una soglia di ingresso molto bassa. Anche un sviluppatore con un livello medio di competenze può installare questo DB e iniziare a utilizzarlo in pochi minuti. Tutto funziona in modo fluido. Anche le persone che non hanno familiarità con Linux possono gestire rapidamente l'installazione e effettuare operazioni semplici. In passato, quando si sentiva parlare di Big Data, Hadoop, Google BigTable, HDFS, un normale sviluppatore aveva l'impressione che si trattasse di terabyte o petabyte, e che le configurazioni e lo sviluppo per questi sistemi fossero compito di superuomini. Con l'arrivo del DB ClickHouse, abbiamo a disposizione uno strumento semplice e comprensibile, con cui è possibile affrontare compiti che prima parevano impossibili. Basta una macchina di livello medio e cinque minuti per installarlo. Abbiamo dunque un DB come MySQL, ma progettato per memorizzare miliardi di record! Una sorta di superarchiviatore con linguaggio SQL. È come se agli esseri umani fosse stato dato un'arma aliena.

Informazioni sul nostro sistema di raccolta log

Per raccogliere informazioni vengono utilizzati i file di log IIS delle applicazioni web in formato standard (attualmente ci stiamo occupando anche dell'analisi dei log delle applicazioni, ma il nostro obiettivo principale in questa fase pilota è la raccolta dei log IIS).

Non siamo riusciti a rinunciare completamente allo stack ELK per vari motivi, e continuiamo a utilizzare componenti come LogStash e Filebeat, che si sono dimostrati efficienti e funzionano in modo affidabile e prevedibile.

Lo schema generale di logging è mostrato nell'immagine qui sotto:

BD ClickHouse per le persone, o Tecnologie spaziali

Una peculiarità della registrazione dei dati nel database ClickHouse è l'inserimento poco frequente (una volta al secondo) di registrazioni in grandi batch. Questo, a quanto sembra, è il punto più «problematico» che si incontra nell'esperienza iniziale con ClickHouse: lo schema diventa leggermente più complesso.
Qui il plugin per LogStash ha dato un grande aiuto, inserendo direttamente i dati in ClickHouse. Questo componente è distribuito sullo stesso server della stessa BD. In generale non è consigliato farlo, ma da un punto di vista pratico, per non creare server aggiuntivi, mentre è distribuito sullo stesso server. Non abbiamo riscontrato né malfunzionamenti né conflitti di risorse con la BD. Inoltre, va notato che il plugin ha un meccanismo di retry in caso di errori. In caso di errore, il plugin scrive su disco un batch di dati che non è riuscito a inserire (il formato del file è conveniente: dopo una modifica, è facile reinserire il batch corretto usando clickhouse-client).

L'elenco completo del software utilizzato nello schema è riportato in tabella:

Elenco del software utilizzato

Nome

Descrizione

Link al pacchetto

NGINX

Reverse-proxy per limitare l'accesso per porte e organizzare l'autenticazione

Attualmente non utilizzato nello schema

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

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

FileBeat

Trasmissione dei log di file.

https://www.elastic.co/downloads/beats/filebeat (pacchetto per Windows 64bit).

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

LogStash

Raccoglitore di log.

Utilizzato per raccogliere log da FileBeat, così come per raccogliere log dalla coda RabbitMQ (per i server che si trovano nella DMZ).

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

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

Logstash-output-clickhouse

Plugin Loagstash per inviare i log nel database ClickHouse in batch

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

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

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

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

ClickHouse

Archivio log 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 partire da agosto 2018, nel repository Yandex sono apparse le "normali" build rpm per RHEL, quindi è possibile provare a utilizzarle. Al momento dell'installazione, abbiamo utilizzato i pacchetti compilati da Altinity.

Grafana

Visualizzazione dei log. Configurazione dei dashboard

https://grafana.com/

https://grafana.com/grafana/download

Redhat & Centos (64 Bit) – ultima versione

Datasource ClickHouse per Grafana 4.6+

Plugin per Grafana con datasource ClickHouse

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

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

LogStash

Router di log da FileBeat a RabbitMQ.

Nota. Sfortunatamente, FileBeat non ha un output diretto in RabbitMQ, quindi è necessario un elemento intermedio sotto forma di Logstash

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

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

RabbitMQ

Coda di messaggi. Questo è un buffer delle registrazioni log nella 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

Erlang Runtime (Necessario per RabbitMQ)

Ambiente di esecuzione Erlang. Richiesto per il funzionamento di RabbitMQ

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

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

La configurazione del server con il database ClickHouse è presentata nella seguente tabella:

Nome

Significato

Nota

Configurazione

HDD: 40GB
RAM: 8GB
Processore: Core 2 2Ghz

È necessario prestare attenzione ai consigli per l'uso del database ClickHouse (https://clickhouse.yandex/docs/ru/operations/tips/)

Software di sistema generale

SO: Red Hat Enterprise Linux Server (Maipo)

JRE (Java 8)

 

Come si può notare, si tratta di una normale workstation.

La struttura della tabella per la memorizzazione dei log appare nel seguente modo:

log_web.sql

CREA TABELLA log_web (
  logdate Data,
  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()
PARTIZIONA PER toYYYYMM(logdate)
ORDINA PER (fld_app_name, fld_app_module, logdatetime)
IMPOSTAZIONI index_granularity = 8192;

Utilizziamo valori predefiniti per la partizione (mensile) e la granularità dell'indice. Tutti i campi corrispondono praticamente alle registrazioni del log IIS per la registrazione delle richieste http. Si noti separatamente che ci sono campi specifici per memorizzare i tag utm (vengono analizzati durante l'inserimento nella tabella dal campo della stringa di query).

Inoltre, nella tabella sono stati aggiunti alcuni campi di sistema per memorizzare informazioni su sistemi, componenti e server. La descrizione di questi campi è riportata di seguito nella tabella. In una sola tabella memorizziamo i log di più sistemi.

Nome

Descrizione

Esempio

fld_app_name

Nome dell'applicazione/sistema
Valori ammessi:

  • site1.domain.com Sito esterno 1
  • site2.domain.com Sito esterno 2
  • internal-site1.domain.local Sito interno 1

site1.domain.com

fld_app_module

Modulo di sistema
Valori ammessi:

  • web — Sito web
  • svc — Servizio web del sito
  • intgr — Servizio web di integrazione
  • bo — Admin (BackOffice)

web

fld_website_name

Nome del sito in IIS

Su un server possono essere distribuiti più sistemi, o anche più istanze dello stesso modulo di sistema

web-main

fld_server_name

Nome del server

web1.domain.com

fld_log_file_name

Percorso del file di log sul server

C:inetpublogsLogFiles
W3SVC1u_ex190711.log

Questo consente di costruire grafici in modo efficace in Grafana. Ad esempio, visualizzare le richieste provenienti dal front-end di un sistema specifico. È simile a un contatore di sito in Yandex.Metrica.

Ecco alcune statistiche sull'uso del DB negli ultimi due mesi.

Numero di registrazioni suddivise per sistemi e i loro componenti

SELEZIONA
    fld_app_name,
    fld_app_module,
    conteggio(fld_app_name) AS rows_count
DA log_web
RAGGRUPPA PER
    fld_app_name,
    fld_app_module
    CON TOTALE
ORDINA PER
    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 │
└──────────────────┴────────────────┴────────────┘
 
Totali:
┌─fld_app_name─┬─fld_app_module─┬─rows_count─┐
│              │                │  210522593 │
└──────────────┴────────────────┴────────────┘
 
11 righe nel set. Tempo trascorso: 4,874 sec. Elaborati 210,52 milioni di righe, 421,67 MB (43,19 milioni di righe/s, 86,51 MB/s).

Spazio occupato su disco

SELEZIONARE
    formatReadableSize(sum(data_uncompressed_bytes)) AS non_compressi,
    formatReadableSize(sum(data_compressed_bytes)) AS compressi,
    sum(rows) AS righe_totali
DA system.parts
DOVE table = 'log_web'
 
┌─non_compressi─┬─compressi─┬─righe_totali─┐
│ 54.50 GiB    │ 4.86 GiB   │  211427094 │
└──────────────┴────────────┴────────────┘
 
1 righe nel set. Tempo trascorso: 0.035 sec.

Grado di compressione dei dati nelle colonne

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 righe nel set. Tempo trascorso: 0.005 sec.

Descrizione dei componenti utilizzati

FileBeat. Trasferimento dei log dei file

Questo componente monitora le modifiche ai file di log sul disco e invia le informazioni a LogStash. Viene installato su tutti i server dove vengono scritti i file di log (generalmente IIS). Funziona in modalità tail (cioè, invia solo le nuove voci nel file). Tuttavia, è possibile configurarlo separatamente per inviare l'intero file. Questo è utile quando è necessario caricare i dati dei mesi precedenti. Basta posizionare il file di log nella cartella e lo leggerà interamente.

Quando il servizio è fermo, i dati smettono di essere trasmessi al repository.

Un esempio di configurazione appare come segue:

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.it"
    fld_app_name: "site1.domain.it"
    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.it"
    fld_app_name: "site2.domain.it"
    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.it.cer"
  ssl.key: "C:/filebeat/certs/site1.domain.it.key"
 
#================================ Processors =====================================
 
processors:
  - add_host_metadata: ~
  - add_cloud_metadata: ~

LogStash. Raccolta log

Questo componente è progettato per ricevere le registrazioni di log da FileBeat (via RabbitMQ), eseguire il parsing e inserire i dati in batch nel database ClickHouse.

Per l'inserimento in ClickHouse si utilizza il plugin Logstash-output-clickhouse. Il plugin Logstash ha un meccanismo di retry delle richieste, ma durante l'arresto del servizio, è meglio fermare il servizio stesso. Durante l'arresto, i messaggi si accumuleranno nella coda RabbitMQ, quindi se l'arresto dura a lungo, è meglio fermare i Filebeat sui server. Nello schema in cui non si utilizza RabbitMQ (nella rete locale, Filebeat invia direttamente i log a Logstash), i Filebeat funzionano in modo molto accettabile e sicuro, quindi la loro indisponibilità non ha conseguenze.

Un esempio di configurazione appare come segue:

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. Repository di log

I log di tutti i sistemi vengono salvati in un'unica tabella (vedi all'inizio dell'articolo). Questa è destinata a memorizzare informazioni sulle richieste: tutti i parametri sono simili per diversi formati, ad esempio i log IIS, i log Apache e Nginx. Per i log delle applicazioni, in cui vengono registrati, ad esempio, errori, messaggi informativi e avvisi, sarà prevista una tabella separata con la struttura corrispondente (attualmente in fase di progettazione).

Quando si progetta la tabella, è molto importante determinare la chiave primaria (sulla quale verranno ordinati i dati durante la memorizzazione). Questo influisce sul grado di compressione dei dati e sulla velocità delle query. Nel nostro esempio, la chiave è
ORDER BY (fld_app_name, fld_app_module, logdatetime)
Cioè, in base al nome del sistema, al nome del componente del sistema e alla data dell'evento. Inizialmente, la data dell'evento era al primo posto. Dopo averla spostata all'ultimo posto, le richieste hanno iniziato a funzionare circa il doppio più velocemente. Cambiare la chiave primaria richiederà la ricreazione della tabella e il ricaricamento dei dati affinché ClickHouse riordini i dati su disco. Questa è un'operazione pesante, quindi è consigliabile pianificare con largo anticipo quali elementi debbano far parte della chiave di ordinamento.

È inoltre importante notare che nelle ultime versioni è stato introdotto il tipo di dato LowCardinality. Utilizzando questo tipo, si riduce notevolmente la dimensione dei dati compressi per quei campi con bassa cardinalità (pochi valori).

Attualmente è in uso la versione 19.6 e prevediamo di provare ad aggiornare alla versione più recente. In queste versioni sono state introdotte funzionalità fantastiche come Adaptive Granularity, Skipping indices e il codec DoubleDelta, ad esempio.

Per impostazione predefinita, durante l'installazione il livello di registrazione è impostato su trace. I log vengono sottoposti a rotazione e archiviazione, ma possono espandersi fino a un gigabyte. Se non necessario, si può impostare il livello di warning, riducendo notevolmente la dimensione del log. La configurazione del logging è definita nel file config.xml:


warning

Alcuni comandi utili

Poiché i pacchetti di installazione originali sono compilati per Debian, per altre versioni di Linux è necessario utilizzare i pacchetti forniti da Altinity.

Qui puoi trovare le istruzioni con i link al loro repository: https://www.altinity.com/blog/2017/12/18/logstash-with-clickhouse
sudo yum search clickhouse-server
sudo yum install clickhouse-server.noarch

1. verifica dello stato
sudo systemctl status clickhouse-server

2. arresto del server
sudo systemctl stop clickhouse-server

3. avvio del server
sudo systemctl start clickhouse-server

Avvio per eseguire query in modalità multilinea (comandi eseguibili dopo il segno ";")
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

Il plugin ClickHouse per Logstash in caso di errore in una riga salva l'intero batch nel file /tmp/log_web_failed.json
Puoi correggere manualmente questo file e provare a caricarlo manualmente nel DB:
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

uscita dalla riga di comando
quit;
## Configurazione TLS
https://www.altinity.com/blog/2019/3/5/clickhouse-networking-part-2

openssl s_client -connect log.domain.com:9440 < /dev/null

LogStash. Router di log da FileBeat a RabbitMQ

Questo componente è utilizzato per instradare i log provenienti da FileBeat nella coda RabbitMQ. Qui ci sono due punti importanti:

  1. Sfortunatamente, FileBeat non ha un plugin di output per scrivere direttamente in RabbitMQ. E da quanto sembra dalle segnalazioni su GitHub, questa funzionalità non è prevista. Esiste un plugin per Kafka, ma per motivi specifici non possiamo utilizzarlo.
  2. Ci sono requisiti per la raccolta dei log nella DMZ. In base a questi requisiti, i log devono prima essere messi in coda e poi LogStash legge esternamente le registrazioni dalla coda.

Pertanto, proprio per i server situati nella DMZ è necessario utilizzare uno schema leggermente più complesso. Un esempio di configurazione è il seguente:

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

RabbitMQ. Coda di messaggi

Questo componente è utilizzato per il buffering dei registri di log nella DMZ. La registrazione avviene attraverso la combinazione Filebeat → LogStash. La lettura è effettuata dall'esterno della DMZ tramite LogStash. Con l'uso di RabbitMQ, vengono elaborati circa 4.000 messaggi al secondo.

Il routing dei messaggi è configurato in base al nome del sistema, cioè sulle informazioni di configurazione di FileBeat. Tutti i messaggi vengono indirizzati a un'unica coda. Se per qualche motivo il servizio delle code viene interrotto, ciò non comporterà la perdita di messaggi: i FileBeat riceveranno errori di connessione e interromperanno temporaneamente l'invio. LogStash, che legge dalla coda, riceverà anche errori di rete e attenderà il ripristino della connessione. Pertanto, i dati smetteranno di essere scritti nel database.

Le seguenti istruzioni vengono utilizzate per creare e configurare le code:

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

Grafana. Dashboard

Questo componente viene utilizzato per visualizzare i dati di monitoraggio. È necessario installare il plugin ClickHouse datasource per Grafana 4.6+. Abbiamo dovuto modificarlo un po' per migliorare l'efficienza del trattamento dei filtri SQL nel dashboard.

Ad esempio, utilizziamo variabili e, se non sono impostate nel campo filtro, vorremmo che non generasse condizioni in WHERE del tipo (uriStem = » AND uriStem != »). In tal caso, ClickHouse leggerà la colonna uriStem. In generale, abbiamo provato diverse opzioni e alla fine abbiamo modificato il plugin (macro $valueIfEmpty), in modo che in caso di valore vuoto restituisse 1, senza menzionare la colonna stessa.

E ora possiamo usare la seguente query per il grafico

$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')

che si traduce in questo SQL (nota che i campi vuoti uriStem si sono trasformati semplicemente in 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

Conclusione

L'emergere del database ClickHouse rappresenta un evento significativo nel mercato. Era difficile immaginare che, completamente gratuitamente, avessimo in un istante a disposizione uno strumento potente e pratico per lavorare con big data. Certamente, con l'aumentare delle esigenze (ad esempio, sharding e replica su più server), la configurazione diventerà più complessa. Ma, dalle prime impressioni, lavorare con questo database è molto piacevole. Si nota chiaramente che il prodotto è stato creato "per le persone".

Rispetto a ElasticSearch, i costi di archiviazione e trattamento dei log, secondo stime preliminari, si riducono da cinque a dieci volte. In altre parole, se per l'attuale volume dei dati fosse stato necessario configurare un cluster di più macchine, con ClickHouse ci basta una sola macchina poco potente. Certo, anche in ElasticSearch esistono meccanismi di compressione dei dati su disco e altre funzionalità che consentono di ridurre significativamente il consumo delle risorse, ma rispetto a ClickHouse ciò richiederebbe costi maggiori.

Senza ottimizzazioni speciali da parte nostra, con le impostazioni predefinite, il caricamento dei dati e le query dal database funzionano con un'incredibile velocità. Attualmente abbiamo pochi dati (circa 200 milioni di record), ma il server è debole. Questo strumento possiamo utilizzarlo in futuro anche per altri scopi non legati alla conservazione dei log. Ad esempio, per analisi end-to-end, nella sicurezza e nell'apprendimento automatico.

Alla fine parliamo un po' dei pro e dei contro.

Svantaggi

  1. Caricamento di record in grandi pacchetti. Da un lato, è una funzionalità, ma comunque è necessario utilizzare componenti aggiuntivi per il buffering dei record. Questo compito non è sempre semplice, ma è comunque risolvibile. E ci piacerebbe semplificare lo schema.
  2. Alcune funzionalità esotiche o nuove caratteristiche spesso si rompono nelle nuove versioni. Questo provoca preoccupazioni e riduce la voglia di aggiornarsi. Ad esempio, il motore delle tabelle Kafka è una caratteristica molto utile che permette di leggere direttamente gli eventi da Kafka, senza dover implementare i consumer. Ma, viste le numerose segnalazioni su GitHub, al momento stiamo attenti a utilizzare questo motore in produzione. Tuttavia, se non si effettuano cambiamenti drastici e si utilizza la funzionalità principale, funziona stabilmente.

Pro

  1. Non rallenta.
  2. Basso ingresso.
  3. Open-source.
  4. Gratuita.
  5. Buona scalabilità (sharding/replikazione "out of the box")
  6. È nel registro del software russo raccomandato dal Ministero delle Comunicazioni.
  7. Disponibilità di supporto ufficiale da parte di Yandex.

Fonte: habr.com

Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server 🔥 Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server | ProHoster