ClickHouse Database for Humans, o Alien Technologies

Alexey Lizunov, capu di u centru di cumpetenza per i canali di serviziu remoti di a Direzzione di Tecnulugia di l'Informazione di l'ICB

ClickHouse Database for Humans, o Alien Technologies

Cum'è una alternativa à a pila ELK (ElasticSearch, Logstash, Kibana), facemu ricerche nantu à l'usu di a basa di dati ClickHouse cum'è un almacenamentu di dati per i logs.

In questu articulu, vulemu parlà di a nostra sperienza cù a basa di dati ClickHouse è i risultati preliminari da l'operazione pilota. Hè da nutà subitu chì i risultati eranu impressiunanti.


ClickHouse Database for Humans, o Alien Technologies

In seguitu, descriveremu in più dettagliu cumu u nostru sistema hè cunfiguratu è di quali cumpunenti hè custituitu. Ma avà vogliu parlà un pocu di sta basa di dati in tuttu, è perchè vale a pena attente. A basa di dati ClickHouse hè una basa di dati di columnare analitica di altu rendiment da Yandex. Adupratu in i servizii Yandex, inizialmente questu hè u principale almacenamiento di dati per Yandex.Metrica. Sistema open source, gratuitu. Da u puntu di vista di u sviluppatore, aghju sempre dumandatu cumu implementanu questu, perchè ci sò dati fantastichi grandi. È l'interfaccia d'utilizatore di Metrica stessu hè assai flexible è travaglia rapidamente. Quandu avete prima familiarizatu cù sta basa di dati, avete l'impressione: "Bè, finalmente! Fattu "per u populu"! Da u prucessu di stallazione à l'inviu di e dumande ".

Sta basa di dati hà una barriera d'entrata assai bassa. Ancu un sviluppatore mediu pò installà sta basa di dati in pochi minuti è cumincià à aduprà. Tuttu travaglia bè. Ancu e persone chì sò novi in ​​Linux ponu affruntà rapidamente a stallazione è fà operazioni simplici. Se prima, à sente e parolle Big Data, Hadoop, Google BigTable, HDFS, u sviluppatore mediu hà avutu l'idea chì si parlava di qualchi terabyte, petabyte, chì certi superumani eranu implicati in l'installazione è u sviluppu di sti sistemi, allora cù u L'avventu di a basa di dati ClickHouse avemu un strumentu simplice è comprensibile cù quale pudete risolve una gamma di prublemi prima inaccessibile. Tuttu ciò chì ci vole hè una macchina abbastanza media è cinque minuti per installà. Questu hè, avemu una basa di dati cum'è, per esempiu, MySql, ma solu per almacenà miliardi di dischi! Un tipu di superarchiver cù lingua SQL. Hè cum'è e persone anu datu armi straniere.

Circa u nostru sistema di cullizzioni di log

Per cullà l'infurmazioni, i fugliali di log IIS di l'applicazioni web di formatu standard sò usati (simu ancu impegnati in l'analisi di logs di l'applicazioni, ma u nostru scopu principale in u stadiu pilotu hè di cullà i logs IIS).

Ùn pudemu micca abbandunà cumplettamente a pila ELK per diversi motivi, è cuntinuemu à aduprà i cumpunenti LogStash è Filebeat, chì anu pruvatu bè è travaglianu abbastanza affidabile è prevedibile.

U schema generale di logging hè mostratu in a figura sottu:

ClickHouse Database for Humans, o Alien Technologies

Una funzione di arregistramentu di dati in a basa di dati ClickHouse hè l'inserzione pocu frequente (una volta per seconda) di registri in grandi batch. Questu, apparentemente, hè a parte più "problematica" chì avete scontru quandu u travagliu cù a basa di dati ClickHouse per a prima volta: u schema diventa un pocu più cumplicatu.
U plugin per LogStash, chì inserisce direttamente dati in ClickHouse, hà aiutatu assai quì. Stu cumpunente hè implementatu nantu à u stessu servitore cum'è a basa di dati stessu. Dunque, in generale, ùn hè micca cunsigliatu per fà questu, ma da un puntu di vista praticu, per ùn creà servitori separati mentre hè implementatu in u stessu servitore. Ùn avemu micca osservatu fallimenti o cunflitti di risorse cù a basa di dati. Inoltre, deve esse nutatu chì u plugin hà un mecanismu di retray in casu d'errore. È in casu d'errore, u plugin scrive à u discu un batch di dati chì ùn pò micca esse inseritu (u furmatu di u schedariu hè cunvenutu: dopu à edità, pudete facilmente inserisce u batch currected usendu clickhouse-client).

Una lista cumpleta di u software utilizatu in u schema hè presentata in a tabella:

Lista di u software utilizatu

Titulu

discrizzione

Link à a distribuzione

NGINX

Reverse-proxy per limità l'accessu da u portu è l'autorizazione d'urganizazione

Attualmente micca usatu in u schema

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

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

FileBeat

Trasferimentu di file logs.

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

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

LogStash

Collettore di log.

Adupratu per cullà logs da FileBeat, è ancu per cullà logs da a fila RabbitMQ (per i servitori chì si trovanu in a DMZ.)

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

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

Logstash-output-clickhouse

Loagstash plugin per trasferisce logs à a basa di dati 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

CliccaCasa

Log storage 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 partesi da Aostu 2018, e custruzzioni di rpm "normali" per RHEL apparsu in u repository Yandex, cusì pudete pruvà à aduprà. À u mumentu di a stallazione, avemu usatu pacchetti compilati da Altinity.

Grafana

Visualizazione di logs. Configurazione di dashboards

https://grafana.com/

https://grafana.com/grafana/download

Redhat & Centos (64 Bit) - l'ultima versione

Fonte di dati ClickHouse per Grafana 4.6+

Plugin per Grafana cù fonte di dati ClickHouse

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

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

LogStash

Log router da FileBeat à RabbitMQ queue.

Nota. Sfortunatamente, FileBeat ùn hà micca output direttamente à RabbitMQ, cusì hè necessariu un ligame intermediu in forma di Logstash.

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

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

Rabbit MQ

Coda di messagi. Questu hè un buffer di entrate di log in a 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 (Nessariu per RabbitMQ)

Erlang runtime. Hè necessariu per RabbitMQ per travaglià

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

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

A cunfigurazione di u servitore cù a basa di dati ClickHouse hè presentata in a tabella seguente:

Titulu

valore

Vita

Cunfigurazione

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

Avete da esse attentu à i cunsiglii per utilizà a basa di dati ClickHouse (https://clickhouse.yandex/docs/ru/operations/tips/)

U software in tuttu u sistema

OS: Red Hat Enterprise Linux Server (Maipo)

JRE (Java 8)

 

Comu pudete vede, questu hè una stazione di travagliu regulare.

A struttura di a tavula per almacenà i logs hè a siguenti:

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;

Utilizemu valori predeterminati per a partizione (mensile) è a granularità di l'indici. Tutti i campi praticamente currispondenu à e voci di log IIS per a registrazione di e richieste http. Separatamente, avemu nutatu chì ci sò campi separati per almacenà tag utm (sò analizati in a tappa di inserisce in a tavula da u campu di stringa di query).

Inoltre, parechji campi di u sistema sò stati aghjuntu à a tavula per almacenà infurmazione nantu à i sistemi, cumpunenti è servitori. Per una descrizzione di sti campi, vede a tabella sottu. In una tavula guardemu logs per parechji sistemi.

Titulu

discrizzione

Esempiu:

fld_app_name

Nome di l'applicazione / sistema
Valori validi:

  • site1.domain.com Situ esternu 1
  • site2.domain.com Situ esternu 2
  • internal-site1.domain.local Situ internu 1

site1.domain.com

fld_app_module

Modulu di sistema
Valori validi:

  • web - situ web
  • svc - serviziu web di u situ web
  • intgr - serviziu di integrazione Web
  • bo - Amministratore (BackOffice)

Web

fld_website_name

Nome di u situ in IIS

Diversi sistemi ponu esse implementati in un servitore, o ancu parechji casi di un modulu di sistema

web-main

fld_server_name

Nome di u servitore

web1.domain.com

fld_log_file_name

Path à u schedariu di log in u servitore

Da:inetpublogsLogFiles
W3SVC1u_ex190711.log

Questu permette di custruisce in modu efficiente grafici in Grafana. Per esempiu, vede e dumande da u front end di un sistema specificu. Questu hè simile à u cuntatore di u situ in Yandex.Metrica.

Eccu alcune statistiche nantu à l'usu di basa di dati per dui mesi.

Numero di registri per sistema è cumpunenti

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

Volumi di dati di discu

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.

Rapportu di cumpressione di dati di colonna

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.

Descrizzione di cumpunenti utilizati

FileBeat. Trasferimentu di logs di schedari

Stu cumpunente monitoreghja i cambiamenti à i schedarii di log in u discu è passa l'infurmazioni à LogStash. Installatu nantu à tutti i servitori induve i schedarii di log sò scritti (di solitu IIS). Funziona in modu di coda (vale à dì, trasferisce solu i registri aghjuntu à u schedariu). Ma pudete cunfigurà separatamente per trasferisce i schedari sanu. Questu hè convenientu quandu avete bisognu di scaricà dati per i mesi precedenti. Basta à mette u schedariu di log in un cartulare è vi leghje in tuttu.

Quandu u serviziu si ferma, i dati ùn sò più trasferiti à u almacenamiento.

Un esempiu di cunfigurazione hè cusì:

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

Stu cumpunente hè pensatu per riceve i registri di log da FileBeat (o attraversu una fila RabbitMQ), analizà è inserisci in batch in a basa di dati ClickHouse.

Per inserisce in ClickHouse, utilizate u plugin Logstash-output-clickhouse. U plugin Logstash hà un mecanismu per rinvià e dumande, ma durante un arrestu regulare, hè megliu piantà u serviziu stessu. Quandu si ferma, i missaghji s'acumuleranu in a fila di RabbitMQ, perchè se u stop hè per un bellu pezzu, allora hè megliu piantà Filebeats in i servitori. In un schema induve RabbitMQ ùn hè micca utilizatu (nantu à a reta locale Filebeat manda direttamente logs à Logstash), Filebeats funziona abbastanza accettabile è sicuru, cusì per elli l'indisponibilità di a pruduzzioni ùn hà micca cunsequenze.

Un esempiu di cunfigurazione hè cusì:

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"

Clicca House. Log storage

I logs per tutti i sistemi sò salvati in una tavola (vede à u principiu di l'articulu). Hè pensatu per almacenà infurmazioni nantu à e dumande: tutti i paràmetri sò simili per diversi formati, per esempiu logs IIS, logs apache è nginx. Per i logs di l'applicazioni in quale, per esempiu, l'errore, i missaghji d'informazioni, l'avvertimenti sò registrati, una tavola separata serà furnita cù a struttura adatta (attualmente in u stadiu di cuncepimentu).

Quandu u disignu di una tavula, hè assai impurtante di decide nantu à a chjave primaria (da quale i dati seranu ordinati durante u almacenamiento). U gradu di cumpressione di dati è a velocità di dumanda dipendenu da questu. In u nostru esempiu, a chjave hè
ORDER BY (fld_app_name, fld_app_module, logdatetime)
Questu hè, da u nome di u sistema, u nome di u cumpunente di u sistema è a data di l'avvenimentu. In principiu, a data di l'avvenimentu hè stata prima. Dopu avè spustatu à l'ultimu locu, e dumande cuminciaru à travaglià circa duie volte più veloce. U cambiamentu di a chjave primaria hà bisognu di ricreà a tavula è di re-uploading the data in modu chì ClickHouse hà da ri-sortà i dati nantu à u discu. Questa hè una operazione difficiuli, per quessa, hè cunsigliu di pensà cun cura in anticipu nantu à ciò chì deve esse inclusu in a chjave di sorte.

Hè ancu esse nutatu chì u tipu di dati LowCardinality apparsu in versioni relativamente recenti. Quandu l'utilizanu, a dimensione di dati cumpressi hè ridutta drasticamente per quelli campi chì anu una cardinalità bassa (pochi opzioni).

Attualmente usemu a versione 19.6 è pensamu di pruvà à aghjurnà à l'ultima versione. Hanu caratteristiche maravigliose cum'è Adaptive Granularity, Skipping indexes è u codec DoubleDelta, per esempiu.

Per automaticamente, durante a stallazione, u livellu di logging di cunfigurazione hè stabilitu per traccia. I logs sò rotati è archiviati, ma à u stessu tempu si allarganu finu à un gigabyte. Se ùn ci hè micca bisognu, pudete stabilisce u nivellu à l'avvisu, allora a dimensione di u logu diminuirà drasticamente. I paràmetri di logging sò specificati in u schedariu config.xml:

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

Certi cumandamenti utili

Поскольку оригинальные пакеты установки собираются по 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. Log router da FileBeat à RabbitMQ queue

Stu cumpunente hè utilizatu per indirizzà i logs chì venenu da FileBeat à a fila RabbitMQ. Ci sò dui punti quì:

  1. Sfortunatamente, FileBeat ùn hà micca un plugin di output per scrive direttamente à RabbitMQ. E tali funziunalità, à ghjudicà da u postu nantu à u so github, ùn hè micca pianificatu per l'implementazione. Ci hè un plugin per Kafka, ma per certi mutivi ùn pudemu micca aduprà noi stessi.
  2. Ci sò esigenze per a cullizzioni di logs in a DMZ. Basatu nantu à elli, i logs devenu esse prima in fila è dopu LogStash leghje i registri da a fila esternamente.

Per quessa, specificamente per u casu di servitori situati in una DMZ, hè necessariu di utilizà un tali schema pocu complicatu. Un esempiu di cunfigurazione hè cusì:

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 missaghji

Stu cumpunente hè utilizatu per buffer l'entrate di log in a DMZ. A registrazione hè fatta attraversu u ligame Filebeat → LogStash. A lettura hè fatta da fora di a DMZ via LogStash. Quandu operanu attraversu RabbitMQ, circa 4 mila missaghji per seconda sò trattati.

U routing di u messagiu hè cunfiguratu da u nome di u sistema, vale à dì, basatu nantu à e dati di cunfigurazione FileBeat. Tutti i missaghji vanu in una fila. Se per una certa ragione u serviziu di fila hè firmatu, questu ùn hà micca purtatu à a perdita di missaghju: FileBeats riceverà errori di cunnessione è cesserà temporaneamente di mandà. È LogStash, chì leghje da a fila, riceverà ancu errori di rete è aspittà chì a cunnessione sia restaurata. In questu casu, sicuru, i dati ùn saranu più scritti in a basa di dati.

I seguenti struzzioni sò usati per creà è cunfigurà file:

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

Stu cumpunente hè utilizatu per visualizà i dati di surviglianza. In questu casu, avete bisognu di stallà a fonte di dati ClickHouse per u plugin Grafana 4.6+. Avemu avutu à aghjustà un pocu per migliurà l'efficienza di processà i filtri SQL in u dashboard.

Per esempiu, avemu usatu variàbbili, è s'ellu ùn sò micca specificatu in u campu di filtru, allora vulemu chì ùn generà micca una cundizione in WHERE di a forma ( uriStem = "AND uriStem ! = "). In questu casu, ClickHouse leghje a colonna uriStem. Allora, avemu pruvatu diverse opzioni è infine riparatu u plugin (a macro $valueIfEmpty) per rinvià 1 in casu di un valore viotu, senza mintuvà a colonna stessu.

È avà pudete aduprà sta dumanda per u graficu

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

chì hè cunvertitu in SQL cusì (nota chì i campi uriStem vacanti sò cunvertiti in solu 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

cunchiusioni

L'apparizione di a basa di dati ClickHouse hè diventata un avvenimentu di riferimentu in u mercatu. Era difficiuli d'imagine chì in un istante, cumplettamente gratuitu, eramu armati cù un strumentu putente è praticu per travaglià cù big data. Di sicuru, cum'è i bisogni aumentanu (per esempiu, sharding è replicazione à parechji servitori), u schema diventerà più cumplessu. Ma sicondu i primi impressioni, travaglià cù sta basa di dati hè assai piacevule. Hè chjaru chì u pruduttu hè fattu "per e persone".

Paragunatu à ElasticSearch, u costu di almacenà è di trasfurmazioni di logs, secondu l'estimi preliminari, hè ridutta da cinque à deci volte. In altri palori, se per u voluminu attuale di dati avemu bisognu di stallà un cluster di parechje macchine, allora quandu usendu ClickHouse avemu bisognu solu una macchina di bassa putenza. Iè, sicuru, ElasticSearch hà ancu meccanismi di cumpressione di dati nantu à u discu è altre funziunalità chì ponu riduce significativamente u cunsumu di risorse, ma paragunatu à ClickHouse questu richiederà più costi.

Senza alcuna ottimisazione speciale da a nostra parte, cù paràmetri predeterminati, caricate dati è ricuperazione di dati da a basa di dati travaglia à una velocità incredibile. Ùn avemu micca assai dati ancu (circa 200 million records), ma u servitore stessu hè debule. Puderemu aduprà sta strumentu in u futuru per altri scopi chì ùn sò micca ligati à l'almacenamiento di logs. Per esempiu, per l'analitiche end-to-end, in u campu di sicurità, machine learning.

À a fine, un pocu nantu à i pro è i contra.

Минусы

  1. Caricà i dischi in grandi lotti. Da una banda, questa hè una funzione, ma avete sempre aduprà cumpunenti supplementari per buffer records. Stu compitu ùn hè micca sempre simplice, ma sempre risolvibile. E vogliu simplificà u schema.
  2. Alcune funzionalità esotiche o funzioni novi si rompenu spessu in e versioni novi. Questu suscita preoccupazioni, riducendu u desideriu di aghjurnà à una nova versione. Per esempiu, u mutore di table Kafka hè una funzione assai utile chì vi permette di leghje direttamente l'avvenimenti da Kafka, senza implementà i cunsumatori. Ma à ghjudicà da u numeru di Issues nantu à Github, simu sempre attenti à aduprà stu mutore in a produzzione. Tuttavia, s'ellu ùn fate micca muvimenti bruschi à u latu è utilizate a funziunalità di basa, allora u travagliu stabile.

Плюсы

  1. Ùn rallenta.
  2. Soglia di entrata bassa.
  3. fonte aperta.
  4. Gratuitu.
  5. Scalable (sharding / replicazione fora di a scatula)
  6. Inclusu in u registru di u software russu cunsigliatu da u Ministeru di a Comunicazione.
  7. Disponibilità di supportu ufficiale da Yandex.

Source: www.habr.com

Add a comment