Databáze ClickHouse pro lidi nebo mimozemské technologie

Aleksey Lizunov, vedoucí kompetenčního centra pro kanály vzdálené služby Ředitelství informačních technologií MKB

Databáze ClickHouse pro lidi nebo mimozemské technologie

Jako alternativu k ELK stacku (ElasticSearch, Logstash, Kibana) provádíme výzkum využití databáze ClickHouse jako úložiště dat pro protokoly.

V tomto článku bychom rádi hovořili o našich zkušenostech s používáním databáze ClickHouse a o předběžných výsledcích pilotního provozu. Je třeba hned poznamenat, že výsledky byly působivé.


Databáze ClickHouse pro lidi nebo mimozemské technologie

Dále si podrobněji popíšeme, jak je náš systém nakonfigurován a z jakých komponent se skládá. Nyní bych ale rád pohovořil trochu o této databázi jako celku a proč stojí za to jí věnovat pozornost. Databáze ClickHouse je vysoce výkonná analytická sloupcová databáze od společnosti Yandex. Používá se ve službách Yandex, zpočátku je to hlavní úložiště dat pro Yandex.Metrica. Open-source systém, zdarma. Z pohledu vývojáře mě vždy zajímalo, jak to implementovali, protože jsou tam fantasticky velká data. A samotné uživatelské rozhraní Metricy je velmi flexibilní a rychlé. Při prvním seznámení s touto databází je dojem: „No konečně! Vyrobeno pro lidi! Počínaje procesem instalace a konče odesláním požadavků.

Tato databáze má velmi nízký vstupní práh. Tuto databázi zvládne nainstalovat i průměrně zdatný vývojář během pár minut a začít ji používat. Vše funguje přehledně. Dokonce i lidé, kteří jsou v Linuxu noví, zvládnou instalaci rychle a provedou ty nejjednodušší operace. Pokud dříve, se slovy Big Data, Hadoop, Google BigTable, HDFS, měl obyčejný vývojář představy, že jde o nějaké terabajty, petabajty, že se na nastavení a vývoji těchto systémů podílejí nějací nadlidé, pak s příchodem ClickHouse databáze, dostali jsme jednoduchý, srozumitelný nástroj, se kterým můžete řešit dříve nedosažitelné spektrum úkolů. Instalace trvá pouze jeden poměrně průměrný stroj a pět minut. To znamená, že jsme získali takovou databázi, jako je například MySql, ale pouze pro ukládání miliard záznamů! Jistý super-archivátor s jazykem SQL. Je to, jako by lidem byly předány zbraně mimozemšťanů.

O našem logovacím systému

Ke sběru informací se používají soubory protokolu IIS webových aplikací standardního formátu (v současné době také zpracováváme protokoly aplikací, ale hlavním cílem v pilotní fázi je shromažďovat protokoly IIS).

Z různých důvodů jsme nemohli úplně opustit ELK stack a nadále používáme komponenty LogStash a Filebeat, které se osvědčily a fungují celkem spolehlivě a předvídatelně.

Obecné schéma protokolování je znázorněno na obrázku níže:

Databáze ClickHouse pro lidi nebo mimozemské technologie

Funkce zápisu dat do databáze ClickHouse je zřídka (jednou za sekundu) vkládání záznamů ve velkých dávkách. Toto je zjevně nejproblematičtější část, se kterou se setkáte, když poprvé zažijete práci s databází ClickHouse: schéma se trochu zkomplikuje.
Zde hodně pomohl plugin pro LogStash, který přímo vkládá data do ClickHouse. Tato komponenta je nasazena na stejném serveru jako samotná databáze. Obecně řečeno, nedoporučuje se to dělat, ale z praktického hlediska, aby se nevyráběly samostatné servery, když je nasazen na stejném serveru. Nezaznamenali jsme žádné selhání nebo konflikty zdrojů s databází. Kromě toho je třeba poznamenat, že plugin má mechanismus opakování v případě chyb. A v případě chyb plugin zapíše na disk dávku dat, která se nepodařilo vložit (formát souboru je pohodlný: po úpravě můžete snadno vložit opravenou dávku pomocí clickhouse-client).

Kompletní seznam softwaru použitého ve schématu je uveden v tabulce:

Seznam použitého softwaru

Jméno

popis

Distribuční odkaz

Nginx

Reverzní proxy pro omezení přístupu podle portů a organizaci autorizace

V současné době se ve schématu nepoužívá

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

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

FileBeat

Přenos protokolů souborů.

https://www.elastic.co/downloads/beats/filebeat (distribuční sada pro Windows 64bit).

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

logstash

Sběratel kulatiny.

Používá se ke shromažďování protokolů z FileBeat a také ke shromažďování protokolů z fronty RabbitMQ (pro servery, které jsou v DMZ.)

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

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

Logstash-output-clickhouse

Zásuvný modul Loagstash pro přenos logů do databáze ClickHouse v dávkách

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

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

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

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

clickhouse

Ukládání protokolů 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

Poznámka. Od srpna 2018 se v úložišti Yandex objevily „normální“ sestavení otáček za minutu pro RHEL, takže je můžete zkusit použít. V době instalace jsme používali balíčky vytvořené Altinity.

grafana

Vizualizace logu. Nastavení řídicích panelů

https://grafana.com/

https://grafana.com/grafana/download

Redhat & Centos (64 Bit) - nejnovější verze

Zdroj dat ClickHouse pro Grafana 4.6+

Plugin pro Grafana se zdrojem dat ClickHouse

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

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

logstash

Log router z FileBeat do RabbitMQ fronty.

Poznámka. FileBeat bohužel nemá výstup přímo do RabbitMQ, takže je vyžadován mezilehlý odkaz ve formě Logstash

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

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

RabbitMQ

fronta zpráv. Toto je vyrovnávací paměť protokolu v 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 (vyžadováno pro RabbitMQ)

Runtime Erlang. Vyžadováno pro fungování RabbitMQ

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

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

Konfigurace serveru s databází ClickHouse je uvedena v následující tabulce:

Jméno

Hodnota

Poznámka

Konfigurace

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

Je třeba věnovat pozornost tipům pro obsluhu databáze ClickHouse (https://clickhouse.yandex/docs/ru/operations/tips/)

Obecný systémový software

OS: Red Hat Enterprise Linux Server (Maipo)

JRE (Java 8)

 

Jak vidíte, jedná se o obyčejnou pracovní stanici.

Struktura tabulky pro ukládání protokolů je následující:

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;

Používáme výchozí rozdělení (podle měsíce) a granularitu indexu. Všechna pole prakticky odpovídají položkám protokolu IIS pro protokolování požadavků http. Samostatně si všimneme, že existují samostatná pole pro ukládání utm-tagů (jsou analyzovány ve fázi vkládání do tabulky z pole řetězce dotazu).

Do tabulky bylo také přidáno několik systémových polí pro ukládání informací o systémech, komponentách, serverech. Popis těchto polí naleznete v tabulce níže. V jedné tabulce ukládáme protokoly pro více systémů.

Jméno

popis

příklad

fld_app_name

Název aplikace/systému
Platné hodnoty:

  • site1.domain.com Externí web 1
  • site2.domain.com Externí web 2
  • internal-site1.domain.local Interní web 1

site1.domena.com

fld_app_module

Systémový modul
Platné hodnoty:

  • web - Web
  • svc – služba webových stránek
  • intgr - Integrační webová služba
  • bo - správce (BackOffice)

web

fld_website_name

Název webu ve službě IIS

Na jednom serveru může být nasazeno několik systémů nebo dokonce několik instancí jednoho systémového modulu

hlavní web

název_fld_serveru

Název serveru

web1.domena.com

fld_log_file_name

Cesta k souboru protokolu na serveru

C:inetpublogsLogFiles
W3SVC1u_ex190711.log

To vám umožní efektivně vytvářet grafy v Grafaně. Například zobrazit požadavky z frontendu konkrétního systému. Je to podobné jako počítadlo stránek v Yandex.Metrica.

Zde je několik statistik o používání databáze za dva měsíce.

Počet záznamů v členění podle systémů a jejich součástí

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

Množství dat 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.

Stupeň komprese dat ve sloupcích

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.

Popis použitých komponentů

FileBeat. Přenos protokolů souborů

Tato součást sleduje změny v souborech protokolu na disku a předává informace do LogStash. Instalováno na všech serverech, kde se zapisují soubory protokolu (obvykle IIS). Pracuje v režimu tail (tj. přenáší pouze přidané záznamy do souboru). Ale samostatně jej lze nakonfigurovat pro přenos celých souborů. To je užitečné, když potřebujete stáhnout data z předchozích měsíců. Stačí vložit soubor protokolu do složky a přečte jej celý.

Když je služba zastavena, data se již nepřenášejí dále do úložiště.

Příklad konfigurace vypadá takto:

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. Sběratel logů

Tato komponenta je navržena tak, aby přijímala položky protokolu z FileBeat (nebo prostřednictvím fronty RabbitMQ), analyzovala a vkládala dávky do databáze ClickHouse.

Pro vložení do ClickHouse se používá plugin Logstash-output-clickhouse. Plugin Logstash má mechanismus opakování požadavku, ale při pravidelném vypínání je lepší zastavit samotnou službu. Po zastavení se budou zprávy hromadit ve frontě RabbitMQ, takže pokud je zastavení na dlouhou dobu, je lepší zastavit Filebeats na serverech. Ve schématu, kde se nepoužívá RabbitMQ (v lokální síti Filebeat posílá logy přímo do Logstashe), Filebeats fungují celkem přijatelně a bezpečně, takže pro ně nedostupnost výstupu prochází bez následků.

Příklad konfigurace vypadá takto:

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

potrubí.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. Ukládání protokolů

Logy pro všechny systémy jsou uloženy v jedné tabulce (viz na začátku článku). Je určen k ukládání informací o požadavcích: všechny parametry jsou podobné pro různé formáty, jako jsou protokoly IIS, protokoly Apache a nginx. Pro aplikační logy, do kterých se zaznamenávají např. chyby, informační zprávy, varování, bude k dispozici samostatná tabulka s příslušnou strukturou (aktuálně ve fázi návrhu).

Při návrhu tabulky je velmi důležité rozhodnout se pro primární klíč (podle kterého se budou data při ukládání třídit). Na tom závisí stupeň komprese dat a rychlost dotazu. V našem příkladu je klíč
ORDER BY (fld_app_name, fld_app_module, logdatetime)
Tedy podle názvu systému, názvu systémové komponenty a data události. Zpočátku bylo na prvním místě datum akce. Po přesunutí na poslední místo začaly dotazy fungovat zhruba dvakrát rychleji. Změna primárního klíče bude vyžadovat opětovné vytvoření tabulky a opětovné načtení dat, aby ClickHouse znovu seřadil data na disku. Jedná se o náročnou operaci, takže je dobré hodně přemýšlet o tom, co by mělo obsahovat klíč řazení.

Je třeba také poznamenat, že datový typ LowCardinality se objevil v relativně nedávných verzích. Při jeho použití se velikost komprimovaných dat drasticky zmenší u těch polí, která mají nízkou mohutnost (málo možností).

Momentálně se používá verze 19.6 a plánujeme zkusit aktualizaci na nejnovější verzi. Mají tak skvělé funkce, jako je například adaptivní granularita, indexy přeskakování a kodek DoubleDelta.

Ve výchozím nastavení je během instalace úroveň protokolování nastavena na trasování. Logy se otáčejí a archivují, ale zároveň se roztahují až na gigabajt. Pokud to není potřeba, můžete nastavit úroveň varování, pak se velikost protokolu drasticky sníží. Nastavení protokolování se nastavuje v souboru config.xml:

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

Některé užitečné příkazy

Поскольку оригинальные пакеты установки собираются по 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 z FileBeat do RabbitMQ fronty

Tato komponenta se používá ke směrování protokolů přicházejících z FileBeat do fronty RabbitMQ. Jsou zde dva body:

  1. FileBeat bohužel nemá výstupní plugin pro zápis přímo do RabbitMQ. A taková funkčnost, soudě podle problému na jejich githubu, není plánována k implementaci. Pro Kafku existuje plugin, ale z nějakého důvodu jej nemůžeme používat doma.
  2. Na sběr logů v DMZ jsou kladeny požadavky. Na jejich základě musí být logy nejprve přidány do fronty a poté LogStash čte záznamy z fronty zvenčí.

Proto je pro případ, kdy jsou servery umístěny v DMZ, použít takové trochu komplikované schéma. Příklad konfigurace vypadá takto:

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. fronta zpráv

Tato komponenta se používá k ukládání záznamů protokolu v DMZ. Nahrávání se provádí pomocí sady Filebeat → LogStash. Čtení se provádí zvenčí DMZ přes LogStash. Při provozu přes RabboitMQ se zpracovává asi 4 tisíce zpráv za sekundu.

Směrování zpráv je konfigurováno podle názvu systému, tj. na základě konfiguračních dat FileBeat. Všechny zprávy jdou do jedné fronty. Pokud je z nějakého důvodu služba řazení do fronty zastavena, nepovede to ke ztrátě zpráv: FileBeats obdrží chyby připojení a dočasně pozastaví odesílání. A LogStash, který čte z fronty, také obdrží chyby sítě a počká na obnovení připojení. V tomto případě se data samozřejmě již nebudou zapisovat do databáze.

K vytvoření a konfiguraci front se používají následující pokyny:

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. Řídicí panely

Tato komponenta se používá k vizualizaci monitorovacích dat. V tomto případě musíte nainstalovat zdroj dat ClickHouse pro plugin Grafana 4.6+. Museli jsme to trochu upravit, abychom zlepšili efektivitu zpracování SQL filtrů na dashboardu.

Například používáme proměnné, a pokud nejsou nastaveny v poli filtru, pak bychom chtěli, aby negenerovalo podmínku v WHERE formuláře ( uriStem = » AND uriStem != » ). V tomto případě bude ClickHouse číst sloupec uriStem. Obecně jsme zkoušeli různé možnosti a nakonec jsme plugin (makro $valueIfEmpty) opravili tak, aby v případě prázdné hodnoty vrátil 1, aniž bychom zmínili samotný sloupec.

A nyní můžete tento dotaz použít pro graf

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

což se překládá do tohoto SQL (všimněte si, že prázdná pole uriStem byla převedena pouze na 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

Závěr

Vzhled databáze ClickHouse se stal mezníkem na trhu. Bylo těžké si představit, že zcela zdarma jsme byli během okamžiku vyzbrojeni výkonným a praktickým nástrojem pro práci s velkými daty. Samozřejmě, s rostoucími potřebami (například sdílení a replikace na více serverů) bude schéma složitější. Na první dojmy je ale práce s touto databází velmi příjemná. Je vidět, že produkt je dělaný „pro lidi“.

Ve srovnání s ElasticSearch se odhaduje, že náklady na ukládání a zpracování protokolů se sníží pětkrát až desetkrát. Jinými slovy, pokud bychom pro aktuální objem dat museli nastavit cluster více strojů, tak nám při použití ClickHouse stačí jeden nízkopříkonový stroj. Ano, samozřejmě, ElasticSearch má také mechanismy pro kompresi dat na disku a další funkce, které mohou výrazně snížit spotřebu zdrojů, ale ve srovnání s ClickHouse to bude dražší.

Bez jakýchkoliv speciálních optimalizací z naší strany, ve výchozím nastavení funguje načítání dat a výběr z databáze úžasnou rychlostí. Zatím nemáme moc dat (asi 200 milionů záznamů), ale samotný server je slabý. Tento nástroj můžeme v budoucnu použít pro jiné účely, které nesouvisejí s ukládáním protokolů. Například pro end-to-end analytiku v oblasti bezpečnosti, strojového učení.

Na závěr něco málo o pro a proti.

Zápory

  1. Načítání záznamů ve velkých dávkách. Na jednu stranu je to funkce, ale stále musíte používat další komponenty pro ukládání záznamů do vyrovnávací paměti. Tento úkol není vždy snadný, ale přesto řešitelný. A rád bych schéma zjednodušil.
  2. Některé exotické funkce nebo nové funkce často v nových verzích přestanou fungovat. To vyvolává obavy a snižuje potřebu upgradovat na novou verzi. Například tabulkový engine Kafka je velmi užitečná funkce, která vám umožňuje přímo číst události z Kafky, bez implementace spotřebitelů. Ale soudě podle počtu Issues na githubu jsme stále opatrní, abychom tento engine nepoužili ve výrobě. Pokud však neděláte náhlá gesta do strany a používáte hlavní funkcionalitu, pak funguje stabilně.

Pros

  1. Nezpomaluje.
  2. Nízký vstupní práh.
  3. open source.
  4. Je to zdarma.
  5. Dobře se škáluje (sharding/replikace po vybalení)
  6. Zahrnuto v registru ruského softwaru doporučeného ministerstvem komunikací.
  7. Přítomnost oficiální podpory od společnosti Yandex.

Zdroj: www.habr.com

Přidat komentář