ClickHouse-databasen för mÀnniskor, eller Tekniker frÄn utomjordingar

Aleksej Lizunov, chef för avdelningen för kompetenscentrum för fjÀrrservicekanaler vid IT-direktionen för MKB

ClickHouse-databasen för mÀnniskor, eller Tekniker frÄn utomjordingar

Som ett alternativ till ELK-stacken (ElasticSearch, Logstash, Kibana) genomför vi forskningsarbete om anvÀndningen av ClickHouse-databasen som datalager för loggar.

I denna artikel vill vi berÀtta om vÄra erfarenheter av att anvÀnda ClickHouse-databasen och om de preliminÀra resultaten efter den inledande driften. Det Àr vÀrt att notera frÄn början att resultaten har varit imponerande.


ClickHouse-databasen för mÀnniskor, eller Tekniker frÄn utomjordingar

Nedan kommer vi att beskriva mer detaljerat hur vĂ„rt system Ă€r konfigurerat och av vilka komponenter det bestĂ„r. Men vi skulle först vilja berĂ€tta lite om denna databas i allmĂ€nhet och varför den förtjĂ€nar att uppmĂ€rksammas. ClickHouse-databasen Ă€r en högpresterande kolumnorienterad databas frĂ„n Yandex. Den anvĂ€nds i Yandex-tjĂ€nster, och den var frĂ„n början huvudlagret för data för Yandex.Metrica. Systemet Ă€r open-source och gratis. Ur ett utvecklarperspektiv har jag alltid varit nyfiken pĂ„ hur de har implementerat detta, eftersom de hanterar fantastiskt stora data. Och anvĂ€ndargrĂ€nssnittet för Metrica Ă€r mycket flexibelt och snabbt. Vid första bekantskap med denna databas Ă€r intrycket: "Äntligen! Gjord för mĂ€nniskor!" FrĂ„n installationsprocessen till att skicka förfrĂ„gningar.

Denna databas har en mycket lĂ„g intrĂ€deströskel. Även en medelstor utvecklare kan installera denna databas pĂ„ nĂ„gra minuter och börja anvĂ€nda den. Allt fungerar smidigt. Även personer som Ă€r dĂ„ligt bekanta med Linux kan snabbt hantera installationen och utföra grundlĂ€ggande operationer. Tidigare, nĂ€r ordet Big Data nĂ€mndes, hade vanliga utvecklare ofta en uppfattning om att det handlade om terabyte, petabyte, att det var övermĂ€n som sysslade med instĂ€llningar och utveckling för dessa system. Men med framkomsten av ClickHouse-databasen har vi fĂ„tt ett enkelt, begripligt verktyg som gör det möjligt att lösa tidigare oöverkomliga uppgifter. Det rĂ€cker med en tĂ€mligen medelmĂ„ttig maskin och fem minuter för installation. SĂ„ vi har fĂ„tt en databas som MySql, fast för att lagra miljarder poster! En slags superkompressor med SQL-sprĂ„k. Det Ă€r som om mĂ€nniskor har fĂ„tt utomjordisk bevĂ€pning.

Om vÄrt loggsamlingssystem

För insamling av information anvÀnds loggfiler frÄn IIS webbapplikationer i standardformat (vi arbetar Àven med att parsa loggar frÄn applikationer, men vÄrt huvudsyfte under pilotdriften Àr insamling av IIS-loggar).

Vi har inte kunnat helt överge ELK-stacken av olika skÀl, och vi fortsÀtter att anvÀnda komponenter som LogStash och Filebeat, vilka har visat sig pÄlitliga och fungerar stabilt.

Den övergripande loggning schemat presenteras i bilden nedan:

ClickHouse-databasen för mÀnniskor, eller Tekniker frÄn utomjordingar

En specifik egenskap för att skriva data i ClickHouse-databasen Àr den sÀllsynta (en gÄng per sekund) insÀttningen av poster i stora batchar. Detta Àr nÀmligen den mest «problematiska» delen som man stöter pÄ vid första anvÀndning av ClickHouse: schemat blir nÄgot mer komplicerat.
HÀr hjÀlpte en plugin för LogStash, som direkt sÀtter in data i ClickHouse. Denna komponent installeras pÄ samma server som databasen. Generellt sett rekommenderas inte detta, men praktiskt sett, för att undvika att skapa separata servrar, Àr det acceptabelt sÄ lÀnge den Àr installerad pÄ samma server. Vi har inte observerat nÄgra krascher eller resurskonflikter med databasen. Dessutom Àr det vÀrt att nÀmna att plugin har en retry-mekanism vid fel. Vid fel skriver plugin en batch data som inte kunde sÀttas in pÄ disk (filformatet Àr bekvÀmt: efter redigering kan man enkelt ÄterinsÀtta den korrigerade batchen med hjÀlp av clickhouse-client).

Den fullstÀndiga listan över programvara som anvÀnds i schemat presenteras i tabellen:

Lista över anvÀnda programvaror

Namn

Beskrivning

LĂ€nk till distributionen

NGINX

Reverse-proxy för att begrÀnsa Ätkomst via portar och organisera autentisering

AnvÀnds för nÀrvarande inte i schemat

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

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

FileBeat

Överföring av loggfiler.

https://www.elastic.co/downloads/beats/filebeat (distribution för Windows 64bit).

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

LogStash

Loggsamlare.

AnvÀnds för insamling av loggar frÄn FileBeat samt för att samla loggar frÄn RabbitMQ-kön (för servrar som finns i DMZ).

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

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

Logstash-output-clickhouse

Logstash-plugin för att överföra loggar till ClickHouse-databasen i batchar

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

Logglagring 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

AnmÀrkning. FrÄn och med augusti 2018 finns det "normala" rpm-byggnader i Yandex-repositoriet för RHEL, sÄ de kan provas. Vid installationstillfÀllet anvÀnde vi paket byggda av Altinity.

Grafana

Visualisering av loggar. InstÀllning av instrumentpaneler

https://grafana.com/

https://grafana.com/grafana/download

Redhat & Centos (64 Bit) – senaste versionen

ClickHouse-datakÀlla för Grafana 4.6+

Plugin för Grafana med ClickHouse datakÀlla

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

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

LogStash

Loggrouter frÄn FileBeat till RabbitMQ-kön.

Observera. TyvÀrr har FileBeat ingen direkt output till RabbitMQ, sÄ en mellanhand i form av Logstash krÀvs.

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

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

RabbitMQ

Meddelandekö. Detta Àr en buffert för loggposter i 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 (NödvÀndigt för RabbitMQ)

Erlang-miljö. KrÀvs för att köra RabbitMQ.

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

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

Serverkonfiguration med ClickHouse-databas redovisas i följande tabell:

Namn

VĂ€rde

AnmÀrkning

Konfiguration

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

Det Àr viktigt att följa rÄden för anvÀndning av ClickHouse-databasen (https://clickhouse.yandex/docs/ru/operations/tips/)

Systemprogramvara

OS: Red Hat Enterprise Linux Server (Maipo)

JRE (Java 8)

 

Som synes Àr det en vanlig arbetsstation.

Tabellstrukturen för att lagra loggar ser ut pÄ följande sÀtt:

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;

Vi anvÀnder standardvÀrden för partitionering (per mÄnad) och indexgranularitet. Alla fÀlt stÀmmer praktiskt taget överens med loggposterna frÄn IIS för registrering av http-förfrÄgningar. SÀrskilt mÀrkta Àr separata fÀlt för lagring av utm-taggar (de parsas vid insÀttning i tabellen frÄn förfrÄgningsstrÀngen).

I tabellen har Àven flera systemfÀlt lagts till för att lagra information om system, komponenter, servrar. Beskrivning av dessa fÀlt finns nedan i tabellen. I en tabell lagrar vi loggar frÄn flera system.

Namn

Beskrivning

Exempel

fld_app_name

Namn pÄ applikationen/systemet
TillÄtna vÀrden:

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

site1.domain.com

fld_app_module

Systemmodul
TillÄtna vÀrden:

  • web — Webbplats
  • svc — Webbservice för webbplatsen
  • intgr — Integrations-webbservice
  • bo — Admin (BackOffice)

web

fld_website_name

Namn pÄ webbplatsen i IIS

PĂ„ en server kan flera system vara installerade, eller till och med flera instanser av en modul.

web-main

fld_server_name

Servernamn

web1.domain.com

fld_log_file_name

SökvÀg till loggfilen pÄ servern

C:inetpublogsLogFiles
W3SVC1u_ex190711.log

Det hÀr gör det möjligt att effektivt bygga diagram i Grafana. Till exempel, att se förfrÄgningar frÄn frontend av ett visst system. Det liknar en webbplatsrÀknare i Yandex.Metrika.

HÀr Àr lite statistik om databasanvÀndning under tvÄ mÄnader.

Antal poster uppdelade efter system och deras komponenter

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

DataomfÄng pÄ disk

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.

Kompressionen av data i kolumner

VÄLJ
    namn,
    formatReadableSize(data_uncompressed_bytes) SOM okomprimerad,
    formatReadableSize(data_compressed_bytes) SOM komprimerad,
    data_uncompressed_bytes / data_compressed_bytes SOM komprimeringsförhÄllande
FRÅN system.columns
DÄR tabell = 'log_web'
 
┌─namn────────────────────┬─okomprimerad─┬─komprimerad─┬─────komprimeringsförhĂ„llande─┐
│ logdatum                │ 401.53 MiB   │ 1.80 MiB    │ 223.16665968777315 │
│ logdatumtid            │ 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 │
│ metod                  │ 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 │
│ anvĂ€ndarnamn           │ 318.08 MiB   │ 26.93 MiB   │ 11.812513794583598 │
│ klientIP               │ 2.35 GiB     │ 82.59 MiB   │ 29.132328640073343 │
│ klientRealIP           │ 2.49 GiB     │ 465.05 MiB  │ 5.478382297052563 │
│ anvĂ€ndarAgent          │ 18.34 GiB    │ 764.08 MiB  │ 24.57905114484208 │
│ referens               │ 14.71 GiB    │ 1.37 GiB    │ 10.736792723669906 │
│ svar                   │ 803.06 MiB   │ 83.81 MiB   │ 9.582334090987247 │
│ delat svar             │ 399.87 MiB   │ 1.83 MiB    │ 218.4831068635027 │
│ win32svar             │ 407.86 MiB   │ 7.41 MiB    │ 55.050315514606815 │
│ tidsĂ„tgĂ„ng             │ 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 rader i uppsÀttning. Förfluten tid: 0.005 sek.

Beskrivning av anvÀnda komponenter

FileBeat. Överföring av filloggar

Denna komponent övervakar Àndringar i loggfiler pÄ disken och skickar information till LogStash. Installationen görs pÄ alla servrar dÀr loggfiler skrives (vanligtvis IIS). Arbetar i tail-lÀge (dvs skickar endast tillagda poster i filen). Men kan Àven konfigureras för att överföra hela filer. Detta Àr praktiskt nÀr du behöver ladda upp data frÄn föregÄende mÄnader. SÀtt bara loggfilen i mappen sÄ lÀser den automatiskt hela filen.

NÀr tjÀnsten stÀngs av slutar data att överföras vidare till lagringsutrymmet.

Ett exempel pÄ konfigurationen ser ut som följer:

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"
 
#================================ Processorer =====================================
 
processors:
  - add_host_metadata: ~
  - add_cloud_metadata: ~

LogStash. Logsamlaren

Den hÀr komponenten Àr avsedd att ta emot loggar frÄn FileBeat (antingen via RabbitMQ-kö), parsning och batchinmatning i ClickHouse-databasen.

För insÀttning i ClickHouse anvÀnds Logstash-output-clickhouse-plugin. Logstash-plugin har en mekanism för att Äterförsöka förfrÄgningar, men vid normal avstÀngning Àr det bÀttre att stÀnga sjÀlva tjÀnsten. Vid avstÀngning kommer meddelanden att samlas i RabbitMQ-kö, sÄ om avstÀngningen Àr lÄngvarig Àr det bÀttre att stÀnga av Filebeat pÄ servrarna. I schemat dÀr RabbitMQ inte anvÀnds (i det lokala nÀtverket skickar Filebeat loggar direkt till Logstash) fungerar Filebeat fullt acceptabelt och sÀkert, sÄ för dem gÄr avsaknaden av output utan konsekvenser.

Ett exempel pÄ konfigurationen ser ut som följer:

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. Logg förvaring

Loggar frÄn alla system sparas i en och samma tabell (se i början av artikeln). Den Àr avsedd för lagring av förfrÄgningsinformation: alla parametrar Àr liknande för olika format, till exempel IIS-loggar, apache-loggar och nginx-loggar. För applikationsloggar, dÀr till exempel fel, informationsmeddelanden och varningar registreras, kommer det att finnas en separat tabell med motsvarande struktur (just nu under utveckling).

Vid utformningen av tabellen Àr det mycket viktigt att bestÀmma primÀrnyckeln (som kommer att anvÀndas för att sortera data vid lagring). Detta pÄverkar graden av datakomprimering och hastigheten pÄ förfrÄgningar. I vÄrt exempel Àr nyckeln
ORDER BY (fld_app_name, fld_app_module, logdatetime)
Det vill sÀga baserat pÄ systemnamnet, komponentnamnet för systemet och hÀndelsedatumet. Ursprungligen var hÀndelsedatumet först. Efter att ha flyttat det till sista platsen blev förfrÄgningarna ungefÀr dubbelt sÄ snabba. Att Àndra primÀrnyckeln krÀver att tabellen Äterskapas och att data laddas om sÄ att ClickHouse kan omordna data pÄ disken. Detta Àr en tung operation, sÄ det Àr bÀst att noga övervÀga vad som ska ingÄ i sorteringsnyckeln i god tid.

Det Àr ocksÄ vÀrt att notera att i de senaste versionerna har datatypen LowCardinality introducerats. Med dess anvÀndning minskar storleken pÄ de komprimerade data drastiskt för de fÀlt som har lÄg kardinalitet (fÄ alternativ).

För nÀrvarande anvÀnds version 19.6, och vi planerar att försöka uppgradera till den senaste versionen. I dem har det dykt upp fantastiska funktioner som Adaptiv granularitet, Skipping indices och DoubleDelta-kodek, till exempel.

Som standard Àr loggnivÄn trace instÀlld vid installation i konfigurationen. Loggar roteras och arkiveras, men expanderar samtidigt till en gigabyte. Om det inte Àr nödvÀndigt kan loggnivÄn sÀttas till warning, vilket kraftigt minskar loggens storlek. LogginstÀllningarna anges i filen config.xml:


warning

NÄgra anvÀndbara kommandon

Eftersom de ursprungliga installationspaketen Àr samlade frÄn Debian, mÄste paket som samlas av Altinity anvÀndas för andra versioner av Linux.

HÀr Àr instruktioner med lÀnkar till deras repository: https://www.altinity.com/blog/2017/12/18/logstash-with-clickhouse
sudo yum search clickhouse-server
sudo yum install clickhouse-server.noarch

1. kontrollera status
sudo systemctl status clickhouse-server

2. stoppa servern
sudo systemctl stop clickhouse-server

3. starta servern
sudo systemctl start clickhouse-server

Starta för att utföra frÄgor i flermoduslÀge (körs efter tecknet ";")
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

Logstash ClickHouse-plugin sparar hela batchen i filen /tmp/log_web_failed.json i hÀndelse av ett fel pÄ en rad.
Denna fil kan manuellt korrigeras och laddas upp till databasen manuellt:
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

avsluta kommandoraden
quit;
## TLS Konfiguration
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 frÄn FileBeat till RabbitMQ-kö

Denna komponent anvÀnds för att vidarebefordra loggar som kommer frÄn FileBeat till RabbitMQ-kön. HÀr finns tvÄ frÄgor:

  1. TyvÀrr har FileBeat ingen output-plugin för att skriva direkt till RabbitMQ. Den funktionen, enligt issue pÄ deras GitHub, planeras inte att implementeras. Det finns en plugin för Kafka, men av vissa skÀl kan vi inte anvÀnda den hos oss.
  2. Det finns krav för insamling av loggar i DMZ. UtifrÄn dessa krav mÄste loggar först placeras i en kö, och sedan lÀser LogStash externt frÄn kön.

DÀrför mÄste en nÄgot mer komplicerad schema anvÀndas nÀr servrarna Àr placerade i DMZ. Ett exempel pÄ konfiguration ser ut pÄ följande sÀtt:

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. Meddelandekö

Denna komponent anvĂ€nds för att buffra loggposter i DMZ. Inspelningen görs genom kombinationen Filebeat → LogStash. LĂ€sning sker utanför DMZ via LogStash. Vid drift via RabbitMQ bearbetas cirka 4 000 meddelanden per sekund.

Meddelandena routas baserat pÄ systemets namn, det vill sÀga baserat pÄ konfigurationsdata frÄn FileBeat. Alla meddelanden hamnar i en kö. Om meddelandeköservicen av nÄgon anledning stoppas, leder det inte till meddelandeförlust: FileBeat kommer att fÄ anslutningsfel och tillfÀlligt pausa sÀndningen. LogStash, som lÀser frÄn kön, kommer ocksÄ att fÄ nÀtverksfel och vÀnta pÄ att anslutningen ska ÄterstÀllas. Under tiden kommer data naturligtvis att sluta skrivas till databasen.

Följande instruktioner anvÀnds för att skapa och konfigurera köer:

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

Denna komponent anvÀnds för att visualisera övervakningsdata. Det Àr nödvÀndigt att installera pluginen ClickHouse datasource for Grafana 4.6+. Vi var tvungna att justera den nÄgot för att öka effektiviteten i hanteringen av SQL-filter pÄ instrumentpanelen.

Till exempel anvÀnder vi variabler och om de inte Àr angivna i filtreringsfÀltet, skulle vi gÀrna se att det inte genererade ett villkor i WHERE av typen ( uriStem = » AND uriStem != » ). I sÄ fall kommer ClickHouse att lÀsa kolumnen uriStem. Generellt prövade vi olika alternativ och slutligen justerade vi pluginen (makroet $valueIfEmpty), sÄ att den vid tomt vÀrde returnerade 1, utan att nÀmna sjÀlva kolumnen.

Och nu kan vi anvÀnda en sÄdan frÄga för diagrammet

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

som som omvandlas till följande SQL (notera att tomma fÀlt uriStem har omvandlats till bara 1)

VÄLj

t,
groupArray((response, c)) AS groupArr
FRÅN (
VÄLj
(intDiv(toUInt32(logdatetime), 60) * 60) * 1000 AS t, response,
count(*) AS c FRÅN default.log_web
VAR (logdate >= toDate(1565061982)) OCH (logdatetime >= toDateTime(1565061982)) OCH 1 OCH (fld_app_name = 'site1.domain.ru') OCH (fld_app_module = 'web') OCH 1 OCH 1 OCH 1
GRUPPERA EFTER
t, response
ORDNA EFTER
t ASC,
response ASC
)
GRUPPERA EFTER t ORDNA EFTER t ASC

Slutsats

Införandet av ClickHouse-databasen var en betydande hÀndelse pÄ marknaden. Det var svÄrt att förestÀlla sig att vi plötsligt fick ett kraftfullt och praktiskt verktyg för arbete med stora datamÀngder helt gratis. SjÀlvklart kommer schemat att bli mer komplext nÀr kraven ökar (som sharding och replikering pÄ flera servrar). Men vid första intrycket Àr det mycket trevligt att arbeta med denna databas. Det Àr tydligt att produkten Àr gjord "för mÀnniskor".

JÀmfört med ElasticSearch berÀknas kostnaderna för lagring och bearbetning av loggar minska mellan fem och tio gÄnger. Med andra ord, om vi behövde konfigurera ett kluster av flera maskiner för den aktuella datavolymen, skulle vi med ClickHouse rÀcka med en svag maskin. Ja, det finns Àven mekanismer för datakomprimering pÄ disken i ElasticSearch och andra funktioner som kraftigt kan minska resursförbrukningen, men jÀmfört med ClickHouse krÀver det högre kostnader.

Utan nÄgra speciella optimeringar frÄn vÄr sida, med standardinstÀllningar, fungerar dataladdning och frÄgor mot databasen med fantastisk hastighet. Vi har för tillfÀllet inte mycket data (ungefÀr 200 miljoner poster), men sjÀlva servern Àr svag. Detta verktyg kan vi i framtiden Àven anvÀnda för andra ÀndamÄl som Àr orelaterade till logglagring. Till exempel för end-to-end-analys, inom sÀkerhet, maskininlÀrning.

Slutligen, lite om för- och nackdelar.

Nackdelar

  1. Laddning av poster i stora partier. Å ena sidan Ă€r detta en funktion, men det krĂ€vs Ă€ndĂ„ ytterligare komponenter för buffring av poster. Denna uppgift Ă€r inte alltid enkel, men den Ă€r Ă€ndĂ„ lösbar. Och vi skulle vilja förenkla schemat.
  2. Vissa exotiska funktioner eller nya funktioner bryter ofta i nya versioner. Detta vÀcker oro och minskar viljan att uppgradera till den nya versionen. Till exempel, Kafka-tabellmotorn Àr en mycket anvÀndbar funktion som lÄter dig lÀsa hÀndelser direkt frÄn Kafka, utan att implementera konsumenter. Men med tanke pÄ antalet problem pÄ GitHub, Àr vi osÀkra pÄ att anvÀnda denna motor i produktion. Men om man undviker hastiga förÀndringar och anvÀnder den grundlÀggande funktionaliteten, fungerar den stabilt.

Fördelar

  1. Ingen försening.
  2. LÄg tröskel för intrÀde.
  3. Öppen kĂ€llkod.
  4. Gratis.
  5. Skalar bra (sharding/replicering "ur lÄdan")
  6. Inkluderad i registret över ryska mjukvaror rekommenderade av MinComSvyaz.
  7. Officiellt stöd frÄn Yandex.

KĂ€lla: habr.com

Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar đŸ”„ Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar | ProHoster