Baza podataka ClickHouse za ljude, ili Tehnologije vanzemaljaca

Aleksej Lizunov, voditelj odjela za kompetencije udaljenih kanala usluge u Direkciji informacijskih tehnologija MKB

Baza podataka ClickHouse za ljude, ili Tehnologije vanzemaljaca

Kao alternativu ELK стеку (ElasticSearch, Logstash, Kibana) provodimo istraživačke radove na korištenju ClickHouse DB-a kao skladišta podataka za logove.

U ovom članku bismo željeli podijeliti naše iskustvo korištenja ClickHouse DB-a i preliminarne rezultate nakon pilotne eksploatacije. Treba odmah napomenuti da su rezultati bili impresivni.


Baza podataka ClickHouse za ljude, ili Tehnologije vanzemaljaca

Dalje ćemo detaljnije opisati kako je naš sustav podešen i od kojih se komponenti sastoji. No najprije bismo voljeli malo pričati o ovoj bazi podataka u cjelini i zašto vrijedi obratiti pažnju na nju. ClickHouse DB je visoko performantna analitička kolumnarna baza podataka iz Yandexa. Koristi se u Yandexovim servisima, a izvorno je to glavno skladište podataka za Yandex.Metriku. Sustav je open-source, besplatan. Sa stanovišta programera, oduvijek me zanimalo kako su to realizirali, jer su tamo fantastički veliki podaci. A sam korisnički sučelje Metrike vrlo je fleksibilno i brzo radi. Prilikom prvog upoznavanja s ovom bazom podataka, dojam je: 'Oh, napokon! Napravljeno je 'za ljude!' Počevši od procesa instalacije pa do slanja upita.

Ova baza podataka ima vrlo nisku barijeru ulaska. Čak i programer srednje kvalifikacije može je instalirati za nekoliko minuta i početi je koristiti. Sve radi besprijekorno. Čak i ljudi koji slabo poznaju Linux mogu se brzo nositi s instalacijom i izvršavati jednostavne operacije. Ako su prije, pri riječi Big Data, Hadoop, Google BigTable, HDFS, uobičajeni programeri imali dojam da je tu riječ o terabajtima, petabajtima, i da se konfiguracijom i razvojem za te sustave bave nekakvi nadljudi, s pojavljivanjem ClickHouse DB-a dobili smo jednostavan, razumljiv alat kojim možemo rješavati do tada nedostižan krug zadataka. Dovoljna je samo jedna sasvim prosječna mašina i pet minuta za instalaciju. Tako smo dobili bazu podataka kao što je MySql, ali samo za pohranu milijardi zapisa! Neki super arhivator s SQL jezikom. Kao da su ljudima predali oružje vanzemaljaca.

O našem sustavu prikupljanja logova

Za prikupljanje informacija koriste se log datoteke IIS web aplikacija u standardnom formatu (trenutno se bavimo i parsiranjem logova aplikacija, ali je naš glavni cilj u fazi pilotne eksploatacije prikupljanje IIS logova).

Nismo mogli potpuno napustiti ELK stog iz raznih razloga i nastavljamo koristiti komponente LogStash i Filebeat, koje su se dobro pokazale i rade pouzdano i predvidivo.

Opća shema logiranja prikazana je u nastavku:

Baza podataka ClickHouse za ljude, ili Tehnologije vanzemaljaca

Karakteristika unosa podataka u ClickHouse bazu podataka je rijetka (jednom u sekundi) masovna umetanja zapisa. Očigledno, ovo je najproblematičniji dio s kojim se suočavate pri prvom radu s ClickHouse bazom podataka: shema je malo kompliciranija.
Ovdje je značajno pomogao LogStash plugin koji direktno umetne podatke u ClickHouse. Ova komponenta se postavlja na istom serveru kao i baza podataka. Generalno gledano, to se ne preporučuje, ali s praktične točke gledišta, kako ne bi stvorili dodatne servere, dok je postavljen na istom serveru. Nismo primijetili nikakve greške niti sukobe resursa s bazom podataka. Također, potrebno je napomenuti da plugin ima mehanizam ponovne prenositve u slučaju grešaka. U slučaju grešaka, plugin zapisuje na disk paket podataka koji nije uspio umetnuti (format datoteke je zgodan: nakon ispravke, lako je umetnuti ispravljeni paket pomoću clickhouse-client).

Puni popis softvera koji se koristi u shemi prikazan je u tablici:

Popis korištenog softvera

Naziv

Opis

Link na distribuciju

NGINX

Reverse-proxy za ograničavanje pristupa po portovima i organizaciju autorizacije

Trenutno se ne koristi u shemi

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

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

FileBeat

Prijenos datoteka s logovima.

https://www.elastic.co/downloads/beats/filebeat (distribucija za Windows 64bit).

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

LogStash

Sakupljač logova.

Koristi se za prikupljanje logova od FileBeat-a, kao i za prikupljanje logova iz RabbitMQ reda (za servere koji se nalaze u DMZ-u).

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

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

Logstash-output-clickhouse

Logstash plugin za prijenos logova u ClickHouse bazu podataka u paketima

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

Skladište logova 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

Napomena. Od kolovoza 2018. u Yandex repozitoriju pojavile su se "normalne" rpm build verzije za RHEL, pa ih možete probati koristiti. U vrijeme instalacije koristili smo pakete koje je izradio Altinity.

Grafana

Vizualizacija logova. Postavljanje dashboarda

https://grafana.com/

https://grafana.com/grafana/download

Redhat & Centos (64 Bit) – posljednja verzija

ClickHouse izvor podataka za Grafanu 4.6+

Plugin za Grafanu s izvorom podataka ClickHouse

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

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

LogStash

Router logova od FileBeata u RedQueue RabbitMQ.

Napomena. Nažalost, FileBeat nema direktni izlaz u RabbitMQ, stoga je potrebno posredničko rješenje u obliku Logstasha.

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

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

RabbitMQ

Red poruka. Ovo je međuspremnik zapisa logova u 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 (neophodan za RabbitMQ).

Okruženje za izvršavanje Erlang. Potrebno za rad RabbitMQ.

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

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

Konfiguracija poslužitelja s ClickHouse bazom podataka predstavljena je u sljedećoj tabeli:

Naziv

Vrijednost

Napomena

Konfiguracija

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

Važno je obratiti pažnju na savjete za korištenje ClickHouse baze podataka (https://clickhouse.yandex/docs/ru/operations/tips/)

Opći softver sustava.

OS: Red Hat Enterprise Linux Server (Maipo).

JRE (Java 8).

 

Kao što se može vidjeti, ovo je obična radna stanica.

Struktura tabele za pohranu logova izgleda ovako:

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;

Koristimo zadane vrijednosti za particioniranje (po mjesecima) i granularity indeksa. Sva polja praktički odgovaraju zapisima loga IIS za evidentiranje http zahtjeva. Dodatno napominjemo, posebna polja za pohranu utm oznaka (one se parsiraju u trenutku umetanja u tabelu iz polja upita).

Također su u tabelu dodana neka sistemska polja za pohranu informacija o sistemima, komponentama, poslužiteljima. Opis tih polja može se vidjeti u tabeli ispod. U jednoj tabeli pohranjujemo logove za nekoliko sistema.

Naziv

Opis

Primjer

fld_app_name

Naziv aplikacije/sistema.
Dozvoljene vrijednosti:

  • site1.domain.com Vanjski sajt 1.
  • site2.domain.com Vanjski sajt 2.
  • internal-site1.domain.local Unutrašnji sajt 1.

site1.domain.com

fld_app_module

Modul sistema.
Dozvoljene vrijednosti:

  • web — Veb-sajt.
  • svc — Veb-servis sajt.
  • intgr — Veb-servis integracije.
  • bo — Administrativna platforma (BackOffice).

web

fld_website_name

Naziv sajta u IIS.

Na jednom poslužitelju može biti raspoređeno nekoliko sistema, ili čak nekoliko instanci jednog modula sistema.

web-main

fld_server_name

Ime poslužitelja

web1.domain.com

fld_log_file_name

Putanja do datoteke loga na poslužitelju.

C:inetpublogsLogFiles
W3SVC1u_ex190711.log

To omogućuje učinkovito izradu grafikona u Grafani. Na primjer, pregled zahtjeva s frontenda određene sustave. To je slično mjeraču posjeta u Yandex.Metrica.

Evo neke statistike o korištenju baze podataka tijekom dva mjeseca.

Broj zapisa prema sustavima i njihovim komponentama

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.hr  │ web            │     131441 │
│ site2.domain.hr  │ web            │    1751081 │
│ site3.domain.hr  │ web            │  106887543 │
│ site3.domain.hr  │ svc            │   44908603 │
│ site3.domain.hr  │ intgr          │    9813911 │
│ site4.domain.hr  │ web            │     772095 │
│ site5.domain.hr  │ web            │   17037221 │
│ site5.domain.hr  │ intgr          │     838559 │
│ site5.domain.hr  │ bo             │       7404 │
│ site6.domain.hr  │ web            │     595877 │
│ site7.domain.hr  │ 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.)

Volumen podataka na disku

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.

Stupanj kompresije podataka u stupcima

ODABERI
    naziv,
    formatReadableSize(data_uncompressed_bytes) AS nekomprimirano,
    formatReadableSize(data_compressed_bytes) AS komprimirano,
    data_uncompressed_bytes / data_compressed_bytes AS omjer_kompresije
IZ sustav.kolonice
GDJE tablica = 'log_web'
 
┌─naziv───────────────────┬─nekomprimirano─┬─komprimirano─┬─────omjer_kompresije─┐
│ logdatum               │ 401.53 MiB   │ 1.80 MiB   │ 223.16665968777315 │
│ logvrijeme             │ 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 │
│ metoda                 │ 201.53 MiB   │ 43.64 MiB  │  4.617721053304486 │
│ uriStablo              │ 5.13 GiB     │ 832.51 MiB │  6.311522291936919 │
│ uriUpit               │ 2.58 GiB     │ 501.06 MiB │  5.269731450124478 │
│ port                   │ 803.06 MiB   │ 3.98 MiB   │ 201.91673864241824 │
│ korisničkoIme          │ 318.08 MiB   │ 26.93 MiB  │ 11.812513794583598 │
│ klijentIP              │ 2.35 GiB     │ 82.59 MiB  │ 29.132328640073343 │
│ klijentPraviIP         │ 2.49 GiB     │ 465.05 MiB │  5.478382297052563 │
│ korisničkiAgent        │ 18.34 GiB    │ 764.08 MiB │  24.57905114484208 │
│ referer                │ 14.71 GiB    │ 1.37 GiB   │ 10.736792723669906 │
│ odgovor                │ 803.06 MiB   │ 83.81 MiB  │  9.582334090987247 │
│ pododgovor             │ 399.87 MiB   │ 1.83 MiB   │  218.4831068635027 │
│ win32odgovor          │ 407.86 MiB   │ 7.41 MiB   │ 55.050315514606815 │
│ vrijemeOduzeto         │ 1.57 GiB     │ 402.06 MiB │ 3.9947395692010637 │
│ uriUpit__utm_medium    │ 208.17 MiB   │ 12.29 MiB  │ 16.936148912472955 │
│ uriUpit__utm_source    │ 215.18 MiB   │ 13.00 MiB  │ 16.548367623199912 │
│ uriUpit__utm_campaign  │ 381.46 MiB   │ 37.94 MiB  │ 10.055156353418509 │
│ uriUpit__utm_term      │ 231.82 MiB   │ 10.78 MiB  │ 21.502540454070672 │
│ uriUpit__utm_content   │ 441.34 MiB   │ 87.60 MiB  │  5.038260760449327 │
│ uriUpit__yclid         │ 216.88 MiB   │ 16.58 MiB  │  13.07721335008116 │
│ uriUpit__regija        │ 204.35 MiB   │ 9.49 MiB   │  21.52661903446796 │
└────────────────────────┴──────────────┴────────────┴────────────────────┘
 
28 redaka u skupu. Prošlo: 0.005 sekundi.

Opis korištenih komponenti

FileBeat. Prijenos datoteka s logovima

Ova komponenta prati promjene u log datotekama na disku i prenosi informacije u LogStash. Instalira se na svim serverima gdje se pišu log datoteke (obično IIS). Radi u režimu tail (tj. prenosi samo dodane zapise u datoteci). No, može se posebno postaviti i za prijenos cijelih datoteka. To je zgodno kada je potrebno učitati podatke za prethodne mjesece. Jednostavno stavite datoteku s logovima u mapu i ona će je sama potpuno pročitati.

Kada se usluga zaustavi, podaci prestaju dalje da se šalju u skladište.

Primer konfiguracije izgleda ovako:

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

LogStash. Skupljač logova

Ova komponenta je namenjena za prikupljanje zapisa logova od FileBeat-a (ili putem reda RabbitMQ), parsiranje i umetanje u serijama u Bazu podataka ClickHouse.

Za umetanje u ClickHouse koristi se dodatak Logstash-output-clickhouse. Dodatak Logstash ima mehanizam za ponavljanje zahteva, ali pri normalnom zaustavljanju, bolje je ipak da se zaustavi sama usluga. Kada se zaustavi, poruke će se gomilati u redu RabbitMQ, stoga ako je zaustavljanje na duži vremenski period, bolje je zaustaviti Filebeat-e na serverima. U šemi gde se ne koristi RabbitMQ (u lokalnoj mreži Filebeat direktno šalje logove u Logstash), Filebeat-i rade sasvim prihvatljivo i sigurno, stoga za njih nedostupnost output-a prolazi bez posledica.

Primer konfiguracije izgleda ovako:

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. Skladište logova

Logovi svih sustava pohranjuju se u jednu tablicu (vidi na početku članka). Ona je namijenjena za pohranu informacija o zahtjevima: svi parametri su slični za različite formate, poput IIS logova, apache i nginx logova. Za logove aplikacija, u kojima se bilježe, na primjer, greške, informativne poruke, upozorenja, bit će predviđena zasebna tablica s odgovarajućom strukturom (trenutno u fazi projektiranja).

Prilikom projektiranja tablice vrlo je važno odrediti primarni ključ (prema kojem će se podaci sortirati prilikom pohrane). Od toga ovisi stupanj kompresije podataka i brzina upita. U našem primjeru ključ je
ORDER BY (fld_app_name, fld_app_module, logdatetime)
Dakle, prema nazivu sustava, nazivu komponente sustava i datumu događaja. Izvorno je datum događaja bio na prvom mjestu. Nakon premještanja na posljednje mjesto, upiti su postali brži otprilike dvostruko. Promjena primarnog ključa zahtijeva ponovnu izradu tablice i ponovnu uplatu podataka, kako bi ClickHouse ponovo sortirao podatke na disku. To je teška operacija, stoga je poželjno unaprijed dobro razmisliti što bi trebalo uključiti u ključ sortiranja.

Također je potrebno napomenuti da je u posljednjim verzijama uveden tip podataka LowCardinality. Njegovom upotrebom naglo se smanjuje veličina komprimiranih podataka za ona polja koja imaju nisku kardinalnost (malo varijacija).

Trenutno se koristi verzija 19.6, a planiramo pokušati nadograditi verziju na najnoviju. U njima su uvedene sjajne značajke poput Adaptive Granularity, Skipping indices i kodiranja DoubleDelta, na primjer.

Po defaultu, prilikom instalacije u konfiguraciji postavljen je nivo logiranja trace. Logovi se rotiraju i arhiviraju, ali se pritom proširuju do jednog gigabajta. Ako nije potrebna, može se postaviti nivo warning, tada se veličina loga naglo smanjuje. Postavke logiranja definiraju se u datoteci config.xml:

<!-- Mogući nivoi: https://github.com/pocoproject/poco/blob/develop/Foundation/include/Poco/Logger.h#L105 -->
<level>warning</level>

Neke korisne komande

Budući da se izvorni instalacijski paketi sastavljaju prema Debianu, za druge verzije Linuxa potrebno je koristiti pakete koje je sastavila tvrtka Altinity.

U ovom linku nalaze se upute s poveznicama na njihovu pohranu: https://www.altinity.com/blog/2017/12/18/logstash-with-clickhouse
sudo yum search clickhouse-server
sudo yum install clickhouse-server.noarch

1. provjera statusa
sudo systemctl status clickhouse-server

2. zaustavljanje poslužitelja
sudo systemctl stop clickhouse-server

3. pokretanje poslužitelja
sudo systemctl start clickhouse-server

Pokretanje za izvršenje upita u višelinijskom načinu (izvršavanje nakon znaka ";")
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

ClickHouse plugin za Logstash u slučaju greške u jednom redu čuva cijelu seriju u datoteku /tmp/log_web_failed.json
Možete ručno ispraviti tu datoteku i pokušati je umetnuti u Bazu podataka ručno:
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

izlaz iz naredbenog retka
quit;
## Postavke TLS
https://www.altinity.com/blog/2019/3/5/clickhouse-networking-part-2

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

LogStash. Usmjerivač logova od FileBeata do queue RabbitMQ

Ova komponenta se koristi za usmjeravanje logova primljenih od FileBeata do queue RabbitMQ. Ovdje su dva aspekta:

  1. Nažalost, FileBeat nema output plugin za izravno zapisivanje u RabbitMQ. Takva funkcionalnost, sudeći po problemu na njihovom GitHubu, ne planira se implementirati. Postoji plugin za Kafka, ali iz određenih razloga je ne možemo koristiti kod nas.
  2. Postoje zahtjevi za sakupljanje logova u DMZ. Prema njima, logovi prvo moraju biti smješteni u queue, a zatim LogStash izvana čita iz queuea zapise.

Stoga, upravo za slučaj kada su poslužitelji smješteni u DMZ, moramo koristiti malo složeniju shemu. Primjer konfiguracije izgleda ovako:

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. Red queue

Ovaj komponent se koristi za bufferiranje log zapisnika u DMZ-u. Zapis se vrši preko veze Filebeat → LogStash. Čitanje se odvija izvan DMZ-a putem LogStasha. U radu preko RabbitMQ obrađuje se oko 4 tisuće poruka u sekundi.

Ruting poruka podešen je prema nazivu sustava, tj. na osnovi podataka iz konfiguracije FileBeat. Sve poruke idu u jedan red. Ako iz nekog razloga usluga redova bude zaustavljena, to neće dovesti do gubitka poruka: FileBeat će primati greške u vezi i privremeno obustaviti slanje. A LogStash, koji čita iz reda, također će primati mrežne greške i čekati da se veza obnovi. Podaci se u tom slučaju, naravno, prestaju zapisivati u bazu podataka.

Sljedeće upute se koriste za izradu i postavljanje redova:

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

Ovaj komponent se koristi za vizualizaciju podataka monitoringa. U tu svrhu potrebno je instalirati plug-in ClickHouse datasource for Grafana 4.6+. Morali smo ga malo prilagoditi kako bismo poboljšali učinkovitost obrade SQL filtriranjem na dashboardu.

Na primjer, koristimo varijable, a ako nisu postavljene u polju filtra, voljeli bismo da ne generira uvjet u WHERE-u koji izgleda kao ( uriStem = » AND uriStem != » ). U tom slučaju, ClickHouse će čitati kolonu uriStem. Uglavnom, isprobali smo različite opcije i na kraju prilagodili plug-in (makros $valueIfEmpty), tako da u slučaju prazne vrijednosti vraća 1, bez pominjanja same kolone.

I sada možemo koristiti ovakav upit za grafikon

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

koji se pretvara u takav SQL (primijetite da su prazna polja uriStem pretvorena samo u 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

Zaključak

Pojava ClickHouse baze podataka bila je značajan događaj na tržištu. Teško je bilo zamisliti da ćemo potpuno besplatno u jednom trenutku nabaviti moćan i praktičan alat za rad s velikim podacima. Naravno, s povećanjem potreba (na primjer, shardiranje i replikacija na nekoliko servera) shema će postati složenija. No, prema prvim utiscima, rad s ovom bazom podataka vrlo je ugodan. Vidljivo je da je proizvod napravljen "za ljude".

U usporedbi s ElasticSearch-om, troškovi pohrane i obrade logova, prema preliminarnim procjenama, smanjuju se od pet do deset puta. Drugim riječima, ako bismo za trenutni obujam podataka morali postaviti klaster od nekoliko strojeva, uz upotrebu ClickHouse-a nam potrebna samo jedna slaba mašina. Da, naravno, u ElasticSearch-u također postoje mehanizmi za kompresiju podataka na disku i druge značajke koje omogućuju značajno smanjenje potrošnje resursa, ali u usporedbi s ClickHouse-om to bi zahtijevalo veće troškove.

Bez ikakvih posebnih optimizacija s naše strane, s zadanim postavkama, učitavanje podataka i upiti iz baze podataka rade nevjerojatnom brzinom. Podataka trenutno imamo malo (oko 200 milijuna zapisa), ali server je slab. Ovaj alat možemo u budućnosti koristiti i za druge svrhe, koje nemaju veze s pohranom logova. Na primjer, za cjelovitu analitiku, u području sigurnosti, strojnom učenju.

Na kraju malo o minusima i plusima.

Nedostaci

  1. Učitavanje zapisa u velikim paketima. S jedne strane, to je značajka, ali svejedno je potrebno koristiti dodatne komponente za međuspremanje zapisa. Ova zadaća nije uvijek jednostavna, ali je ipak rješiva. I volio bih pojednostaviti shemu.
  2. Neki egzotični funkcionalnosti ili nove značajke često se u novim verzijama pokvare. To izaziva zabrinutost, smanjujući želju za nadogradnjom na novu verziju. Na primjer, Kafka tablični motor – vrlo korisna značajka koja omogućava izravno čitanje događaja iz Kafke, bez implementacije potrošača. No, sudeći po broju problema na GitHubu, zasad se klonimo korištenja tog motora u produkciji. Ipak, ako ne radimo nagle pomake i koristimo osnovnu funkcionalnost, radi stabilno.

Prednosti

  1. Ne usporava.
  2. Nizak prag ulaska.
  3. Open-source.
  4. Besplatno.
  5. Dobro se skalira (shardiranje/replikacija "iz kutije")
  6. Uvršteno u registar ruskog softvera preporučenog od strane Ministra za komunikacije.
  7. Postojanje službene podrške od Yandexa.

Izvor: habr.com

Kupite pouzdan hosting za web stranice s DDoS zaštitom, VPS VDS servere 🔥 Kupite pouzdan hosting za web stranice s DDoS zaštitom, VPS VDS servere | ProHoster