„ClickHouse Database for Humans“ arba „Alien Technologies“.

Aleksejus Lizunovas, MKB Informacinių technologijų direkcijos Nuotolinių paslaugų kanalų kompetencijos centro vadovas

„ClickHouse Database for Humans“ arba „Alien Technologies“.

Kaip alternatyvą ELK kaminui (ElasticSearch, Logstash, Kibana), atliekame ClickHouse duomenų bazės, kaip žurnalų duomenų saugyklos, naudojimą.

Šiame straipsnyje norėtume pakalbėti apie mūsų patirtį naudojantis ClickHouse duomenų baze ir preliminarius bandomosios operacijos rezultatus. Iš karto reikia pažymėti, kad rezultatai buvo įspūdingi.


„ClickHouse Database for Humans“ arba „Alien Technologies“.

Toliau išsamiau apibūdinsime, kaip mūsų sistema sukonfigūruota ir iš kokių komponentų ji susideda. Bet dabar norėčiau šiek tiek pakalbėti apie šią duomenų bazę kaip visumą ir kodėl verta į ją atkreipti dėmesį. „ClickHouse“ duomenų bazė yra didelio našumo analitinė stulpelių duomenų bazė iš „Yandex“. Jis naudojamas „Yandex“ paslaugose, iš pradžių tai yra pagrindinė „Yandex.Metrica“ duomenų saugykla. Atvirojo kodo sistema, nemokama. Žvelgiant iš kūrėjo pusės, man visada buvo įdomu, kaip jie tai įgyvendino, nes yra fantastiškai didelių duomenų. O pati Metrica vartotojo sąsaja yra labai lanksti ir greita. Pirmą kartą susipažinus su šia duomenų baze, susidaro įspūdis: „Na, pagaliau! Sukurta žmonėms! Pradedant nuo diegimo proceso ir baigiant užklausų siuntimu.

Ši duomenų bazė turi labai žemą įėjimo slenkstį. Net ir vidutinės kvalifikacijos kūrėjas gali per kelias minutes įdiegti šią duomenų bazę ir pradėti ja naudotis. Viskas veikia aiškiai. Netgi žmonės, kurie dar nesinaudojo Linux, gali greitai atlikti diegimą ir atlikti paprasčiausias operacijas. Jei anksčiau, naudojant žodžius „Big Data“, „Hadoop“, „Google BigTable“, HDFS, paprastas kūrėjas turėjo minčių, kad kalbama apie keletą terabaitų, petabaitų, kad kai kurie antžmogiai užsiima šių sistemų nustatymais ir kūrimu, tai atsiradus „ClickHouse“ duomenų bazę, gavome paprastą, suprantamą įrankį, su kuriuo galite išspręsti anksčiau nepasiekiamą užduočių spektrą. Įdiegti užtrunka tik vieną gana vidutinį įrenginį ir penkias minutes. Tai yra, mes turime tokią duomenų bazę kaip, pavyzdžiui, MySql, bet tik milijardams įrašų saugojimui! Tam tikras super archyvatorius su SQL kalba. Lyg žmonėms būtų įteikti ateivių ginklai.

Apie mūsų registravimo sistemą

Informacijai rinkti naudojami standartinio formato žiniatinklio programų IIS žurnalų failai (šiuo metu taip pat analizuojame programų žurnalus, tačiau pagrindinis tikslas bandomajame etape yra rinkti IIS žurnalus).

Dėl įvairių priežasčių negalėjome visiškai atsisakyti ELK stacko ir toliau naudojame LogStash ir Filebeat komponentus, kurie pasiteisino ir veikia gana patikimai ir nuspėjamai.

Bendra registravimo schema parodyta paveikslėlyje žemiau:

„ClickHouse Database for Humans“ arba „Alien Technologies“.

Duomenų rašymo į ClickHouse duomenų bazę ypatybė yra nedažnas (kartą per sekundę) įrašų įterpimas didelėmis partijomis. Tai, matyt, yra „problemiškiausia“ dalis, su kuria susiduriate pirmą kartą dirbant su ClickHouse duomenų baze: schema tampa šiek tiek sudėtingesnė.
Čia labai padėjo LogStash įskiepis, kuris tiesiogiai įterpia duomenis į ClickHouse. Šis komponentas yra įdiegtas tame pačiame serveryje kaip ir pati duomenų bazė. Taigi, paprastai kalbant, tai daryti nerekomenduojama, o praktiniu požiūriu, kad nebūtų gaminami atskiri serveriai, kol jis yra dislokuotas tame pačiame serveryje. Nepastebėjome jokių gedimų ar išteklių konfliktų su duomenų baze. Be to, reikia pažymėti, kad įskiepis turi pakartotinio bandymo mechanizmą klaidų atveju. O esant klaidoms, įskiepis įrašo į diską duomenų, kurių nepavyko įterpti, paketą (failo formatas patogus: po redagavimo galite lengvai įterpti pataisytą paketą naudodami clickhouse-client).

Visas schemoje naudojamos programinės įrangos sąrašas pateiktas lentelėje:

Naudotos programinės įrangos sąrašas

Pavadinimas

aprašymas

Platinimo nuoroda

nginx

Atvirkštinis tarpinis serveris, skirtas apriboti prieigą prie prievadų ir organizuoti autorizavimą

Šiuo metu schemoje nenaudojamas

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

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

FileBeat

Failų žurnalų perkėlimas.

https://www.elastic.co/downloads/beats/filebeat (platinimo rinkinys, skirtas „Windows 64bit“).

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

logstash

Rąstų surinkėjas.

Naudojamas žurnalams iš FileBeat, taip pat žurnalams iš RabbitMQ eilės (serveriams, kurie yra DMZ) rinkti.

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

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

Logstash-output-clickhouse

Loagstash įskiepis, skirtas žurnalų siuntimui į ClickHouse duomenų bazę partijomis

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

/usr/share/logstash/bin/logstash-plugin įdiegti logstash-output-clickhouse

/usr/share/logstash/bin/logstash-plugin įdiegti logstash-filter-prune

/usr/share/logstash/bin/logstash-plugin įdiegti logstash-filter-multiline

„ClickHouse“

Rąstų saugykla 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

Pastaba. Nuo 2018 m. rugpjūčio mėn. „Yandex“ saugykloje pasirodė „įprasti“ RHEL rpm versijos, todėl galite pabandyti jas naudoti. Diegimo metu naudojome „Altinity“ sukurtus paketus.

grafana

Žurnalo vizualizacija. Prietaisų skydelių nustatymas

https://grafana.com/

https://grafana.com/grafana/download

Redhat & Centos (64 bitų) – naujausia versija

„ClickHouse“ duomenų šaltinis, skirtas „Grafana 4.6+“.

„Grafana“ papildinys su „ClickHouse“ duomenų šaltiniu

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

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

logstash

Užregistruokite maršrutizatorių iš „FileBeat“ į „RabbitMQ“ eilę.

Pastaba. Deja, FileBeat neturi išvesties tiesiai į RabbitMQ, todėl reikalinga tarpinė nuoroda Logstash forma

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

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

TriušisMQ

pranešimų eilė. Tai yra žurnalo buferis 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“ (būtina „RabbitMQ“)

Erlang vykdymo laikas. Būtina, kad RabbitMQ veiktų

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

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

Serverio konfigūracija su ClickHouse duomenų baze pateikta šioje lentelėje:

Pavadinimas

Vertė

Atkreipti dėmesį

Konfigūravimas

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

Būtina atkreipti dėmesį į ClickHouse duomenų bazės valdymo patarimus (https://clickhouse.yandex/docs/ru/operations/tips/)

Bendroji sistemos programinė įranga

OS: „Red Hat Enterprise Linux Server“ („Maipo“)

JRE („Java 8“)

 

Kaip matote, tai yra įprasta darbo vieta.

Rąstų saugojimo lentelės struktūra yra tokia:

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;

Naudojame numatytąjį skaidymą (pagal mėnesį) ir indekso detalumą. Visi laukai praktiškai atitinka IIS žurnalo įrašus, skirtus http užklausoms registruoti. Atskirai pažymime, kad yra atskiri laukai utm žymoms saugoti (jie analizuojami įterpiant į lentelę iš užklausos eilutės lauko).

Taip pat į lentelę buvo įtraukti keli sistemos laukai, kuriuose saugoma informacija apie sistemas, komponentus, serverius. Žemiau esančioje lentelėje rasite šių laukų aprašymą. Vienoje lentelėje saugome kelių sistemų žurnalus.

Pavadinimas

aprašymas

Pavyzdys

fld_programos_pavadinimas

Programos / sistemos pavadinimas
Galiojančios reikšmės:

  • site1.domain.com 1 išorinė svetainė
  • site2.domain.com 2 išorinė svetainė
  • internal-site1.domain.local 1 vidinė svetainė

site1.domain.com

fld_app_module

Sistemos modulis
Galiojančios reikšmės:

  • žiniatinklis – svetainė
  • svc – svetainės paslauga
  • intgr – interneto integravimo paslauga
  • bo – administratorius („BackOffice“)

tinklas

fld_svetainės_pavadinimas

Svetainės pavadinimas IIS

Viename serveryje gali būti įdiegtos kelios sistemos arba net keli vieno sistemos modulio egzemplioriai

interneto pagrindinis

fld_serverio_vardas

Serverio pavadinimas

web1.domain.com

fld_log_file_name

Kelias į žurnalo failą serveryje

C:inetpublogsLogFiles
W3SVC1u_ex190711.log

Tai leidžia efektyviai kurti Grafana grafikus. Pavyzdžiui, peržiūrėti užklausas iš konkrečios sistemos sąsajos. Tai panašu į svetainės skaitiklį Yandex.Metrica.

Štai keletas statistikos apie naudojimąsi duomenų baze per du mėnesius.

Įrašų skaičius, suskirstytas pagal sistemas ir jų komponentus

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

Duomenų kiekis diske

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.

Duomenų suspaudimo stulpeliuose laipsnis

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.

Naudotų komponentų aprašymas

failo ritmas. Failų žurnalų perkėlimas

Šis komponentas seka žurnalo failų pakeitimus diske ir perduoda informaciją „LogStash“. Įdiegta visuose serveriuose, kuriuose rašomi žurnalo failai (dažniausiai IIS). Veikia uodegos režimu (t.y. į failą perkelia tik pridėtus įrašus). Tačiau atskirai jį galima sukonfigūruoti perkelti visus failus. Tai naudinga, kai reikia atsisiųsti duomenis iš ankstesnių mėnesių. Tiesiog įdėkite žurnalo failą į aplanką ir jis perskaitys jį visą.

Sustabdžius paslaugą, duomenys toliau į saugyklą nebeperkeliami.

Konfigūracijos pavyzdys atrodo taip:

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. Rąstų surinkėjas

Šis komponentas skirtas gauti žurnalo įrašus iš FileBeat (arba per RabbitMQ eilę), analizuojant ir įterpiant paketus į ClickHouse duomenų bazę.

Įterpimui į ClickHouse naudojamas Logstash-output-clickhouse papildinys. „Logstash“ papildinys turi užklausos pakartotinio bandymo mechanizmą, tačiau reguliariai išjungus, geriau sustabdyti pačią paslaugą. Sustabdžius pranešimai bus kaupiami RabbitMQ eilėje, todėl jei sustojimas trunka ilgą laiką, geriau sustabdyti „Filebeats“ serveriuose. Schemoje, kurioje RabbitMQ nenaudojamas (vietiniame tinkle Filebeat tiesiogiai siunčia žurnalus į Logstash), Filebeats veikia gana priimtinai ir saugiai, todėl jiems išvesties nepasiekimas praeina be pasekmių.

Konfigūracijos pavyzdys atrodo taip:

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

vamzdynai.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. Rąstų saugykla

Visų sistemų žurnalai saugomi vienoje lentelėje (žr. straipsnio pradžioje). Jis skirtas saugoti informaciją apie užklausas: visi parametrai yra panašūs skirtingiems formatams, tokiems kaip IIS žurnalai, apache ir nginx žurnalai. Paraiškų žurnalams, kuriuose, pavyzdžiui, fiksuojamos klaidos, informaciniai pranešimai, įspėjimai, bus pateikta atskira lentelė su atitinkama struktūra (šiuo metu projektavimo stadijoje).

Kuriant lentelę labai svarbu apsispręsti dėl pirminio rakto (pagal kurį bus rūšiuojami duomenys saugojimo metu). Nuo to priklauso duomenų suspaudimo laipsnis ir užklausos greitis. Mūsų pavyzdyje svarbiausia yra
ORDER BY (fld_app_name, fld_app_module, logdatetime)
Tai yra pagal sistemos pavadinimą, sistemos komponento pavadinimą ir įvykio datą. Iš pradžių įvykio data buvo pirma. Perkėlus jį į paskutinę vietą, užklausos pradėjo veikti maždaug dvigubai greičiau. Norint pakeisti pirminį raktą, reikės iš naujo sukurti lentelę ir iš naujo įkelti duomenis, kad „ClickHouse“ iš naujo surūšiuotų duomenis diske. Tai sunki operacija, todėl verta daug galvoti apie tai, kas turėtų būti įtraukta į rūšiavimo raktą.

Taip pat reikėtų pažymėti, kad LowCardinality duomenų tipas pasirodė palyginti naujausiose versijose. Jį naudojant suglaudintų duomenų dydis smarkiai sumažėja tiems laukams, kurių kardinalumas yra mažas (nedaug variantų).

Šiuo metu naudojama 19.6 versija ir planuojame pabandyti atnaujinti į naujausią versiją. Pavyzdžiui, jie turi tokias nuostabias funkcijas kaip prisitaikantis detalumas, praleidimo indeksai ir „DoubleDelta“ kodekas.

Pagal numatytuosius nustatymus diegimo metu registravimo lygis nustatomas į sekimą. Žurnalai pasukami ir archyvuojami, tačiau tuo pat metu išsiplečia iki gigabaito. Jei nereikia, galite nustatyti įspėjimo lygį, tada rąsto dydis smarkiai sumažėja. Registravimo nustatymas nustatytas faile config.xml:

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

Keletas naudingų komandų

Поскольку оригинальные пакеты установки собираются по 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. Užregistruokite maršrutizatorių iš „FileBeat“ į „RabbitMQ“ eilę

Šis komponentas naudojamas iš FileBeat gaunamiems žurnalams nukreipti į RabbitMQ eilę. Čia yra du punktai:

  1. Deja, „FileBeat“ neturi išvesties papildinio, kad būtų galima rašyti tiesiai į „RabbitMQ“. Ir toks funkcionalumas, sprendžiant iš jų „github“ problemos, nėra planuojamas įdiegti. Yra Kafka įskiepis, bet kažkodėl negalime jo naudoti namuose.
  2. DMZ nustatyti žurnalų rinkimo reikalavimai. Remiantis jais, žurnalai pirmiausia turi būti įtraukti į eilę, o tada LogStash nuskaito įrašus iš eilės iš išorės.

Todėl tuo atveju, kai serveriai yra DMZ, reikia naudoti tokią šiek tiek sudėtingą schemą. Konfigūracijos pavyzdys atrodo taip:

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. pranešimų eilė

Šis komponentas naudojamas žurnalo įrašams DMZ buferizuoti. Įrašymas atliekamas per Filebeat → LogStash krūvą. Skaitymas atliekamas iš DMZ ribų per LogStash. Veikiant per RabboitMQ, per sekundę apdorojama apie 4 tūkst.

Pranešimų maršrutas sukonfigūruojamas pagal sistemos pavadinimą, t. y. remiantis „FileBeat“ konfigūracijos duomenimis. Visi pranešimai patenka į vieną eilę. Jei dėl kokių nors priežasčių eilės paslauga bus sustabdyta, tai nepraras pranešimų: „FileBeats“ gaus ryšio klaidas ir laikinai sustabdys siuntimą. O iš eilės nuskaitantis LogStash taip pat gaus tinklo klaidas ir lauks, kol bus atkurtas ryšys. Tokiu atveju duomenys, žinoma, nebebus įrašomi į duomenų bazę.

Šios instrukcijos naudojamos eilėms kurti ir konfigūruoti:

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. Prietaisų skydeliai

Šis komponentas naudojamas stebėjimo duomenims vizualizuoti. Tokiu atveju turite įdiegti „ClickHouse“ duomenų šaltinį, skirtą „Grafana 4.6+“ papildiniui. Turėjome jį šiek tiek pakoreguoti, kad pagerintume SQL filtrų apdorojimo prietaisų skydelyje efektyvumą.

Pavyzdžiui, naudojame kintamuosius, o jei jie nenustatyti filtro lauke, tai norėtume, kad formos WHERE negeneruotų sąlygos ( uriStem = » AND uriStem != » ). Tokiu atveju ClickHouse nuskaitys stulpelį uriStem. Apskritai išbandėme įvairias parinktis ir galiausiai pataisėme papildinį (makrokomandą $valueIfEmpty), kad tuščios reikšmės atveju būtų pateikta 1, neminint paties stulpelio.

Ir dabar galite naudoti šią užklausą diagramai

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

kuris reiškia šį SQL (atkreipkite dėmesį, kad tušti uriStem laukai buvo konvertuoti tik į 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

išvada

„ClickHouse“ duomenų bazės atsiradimas tapo svarbiu įvykiu rinkoje. Sunku buvo įsivaizduoti, kad visiškai nemokamai akimirksniu apsiginklavome galingu ir praktišku įrankiu dirbti su dideliais duomenimis. Žinoma, didėjant poreikiams (pavyzdžiui, dalijimasis ir replikavimas į kelis serverius), schema taps sudėtingesnė. Tačiau iš pirmo įspūdžio dirbti su šia duomenų baze yra labai malonu. Matyti, kad gaminys sukurtas „žmonėms“.

Palyginti su ElasticSearch, žurnalų saugojimo ir apdorojimo sąnaudos sumažės nuo penkių iki dešimties kartų. Kitaip tariant, jei esamam duomenų kiekiui tektų sukurti kelių mašinų klasterį, tai naudojant ClickHouse mums užtenka vieno mažos galios mašinos. Taip, žinoma, ElasticSearch taip pat turi diske esančius duomenų glaudinimo mechanizmus ir kitas funkcijas, kurios gali žymiai sumažinti resursų suvartojimą, tačiau lyginant su ClickHouse, tai bus brangiau.

Be jokių specialių optimizacijų iš mūsų pusės, pagal numatytuosius nustatymus, duomenų įkėlimas ir pasirinkimas iš duomenų bazės veikia nuostabiu greičiu. Dar neturime daug duomenų (apie 200 mln. įrašų), bet pats serveris silpnas. Ateityje šį įrankį galėsime naudoti kitiems tikslams, nesusijusiems su žurnalų saugojimu. Pavyzdžiui, visapusiškai analizei, saugumo, mašininio mokymosi srityje.

Pabaigoje šiek tiek apie privalumus ir trūkumus.

Trūkumai

  1. Įrašai didelėmis partijomis. Viena vertus, tai yra funkcija, tačiau vis tiek turite naudoti papildomus komponentus įrašams buferizuoti. Ši užduotis ne visada lengva, bet vis tiek išsprendžiama. Ir aš norėčiau supaprastinti schemą.
  2. Kai kurios egzotiškos funkcijos ar naujos funkcijos dažnai sugenda naujose versijose. Tai kelia susirūpinimą, sumažinant norą atnaujinti į naują versiją. Pavyzdžiui, Kafka lentelės variklis yra labai naudinga funkcija, leidžianti tiesiogiai skaityti įvykius iš Kafka, neįdiegiant vartotojų. Tačiau, sprendžiant iš „Github“ problemų skaičiaus, vis tiek stengiamės nenaudoti šio variklio gamyboje. Tačiau jei nedarote staigių gestų į šoną ir naudojatės pagrindine funkcija, tai veikia stabiliai.

Argumentai "už"

  1. Nelėtėja.
  2. Žemas įėjimo slenkstis.
  3. Atviro kodo.
  4. Laisvas.
  5. Gerai svarstyklės (išardymas / replikavimas iš dėžutės)
  6. Įtrauktas į Ryšių ministerijos rekomenduojamą Rusijos programinės įrangos registrą.
  7. Oficialios „Yandex“ paramos buvimas.

Šaltinis: www.habr.com

Добавить комментарий