ClickHouse-database voor mensen of buitenaardse technologieën

Aleksey Lizunov, Hoofd van het Competentiecentrum voor Remote Service Channels van de Directie Informatietechnologieën van de MKB

ClickHouse-database voor mensen of buitenaardse technologieën

Als alternatief voor de ELK-stack (ElasticSearch, Logstash, Kibana) doen we onderzoek naar het gebruik van de ClickHouse-database als gegevensopslag voor logs.

In dit artikel willen we het hebben over onze ervaringen met het gebruik van de ClickHouse-database en de voorlopige resultaten van de proefoperatie. Meteen moet worden opgemerkt dat de resultaten indrukwekkend waren.


ClickHouse-database voor mensen of buitenaardse technologieën

Vervolgens zullen we in meer detail beschrijven hoe ons systeem is geconfigureerd en uit welke componenten het bestaat. Maar nu wil ik het even hebben over deze database als geheel, en waarom het de moeite waard is om op te letten. De ClickHouse-database is een krachtige analytische kolomdatabase van Yandex. Het wordt gebruikt in Yandex-services, aanvankelijk is het de belangrijkste gegevensopslag voor Yandex.Metrica. Open-source systeem, gratis. Vanuit het oogpunt van een ontwikkelaar heb ik me altijd afgevraagd hoe ze het hebben geïmplementeerd, omdat er fantastische big data zijn. En de gebruikersinterface van Metrica zelf is erg flexibel en snel. Bij de eerste kennismaking met deze database is de indruk: “Nou, eindelijk! Gemaakt voor de mensen! Beginnend bij het installatieproces en eindigend met het verzenden van verzoeken.

Deze database heeft een zeer lage instapdrempel. Zelfs een gemiddeld bekwame ontwikkelaar kan deze database binnen enkele minuten installeren en gebruiken. Alles werkt duidelijk. Zelfs mensen die nieuw zijn met Linux kunnen de installatie snel afhandelen en de eenvoudigste bewerkingen uitvoeren. Als eerder, met de woorden Big Data, Hadoop, Google BigTable, HDFS, een gewone ontwikkelaar het idee had dat het om enkele terabytes, petabytes ging dat sommige supermensen betrokken zijn bij instellingen en ontwikkeling voor deze systemen, dan met de komst van het ClickHouse database hebben we een eenvoudige, begrijpelijke tool waarmee u een voorheen onbereikbare reeks taken kunt oplossen. Het kost slechts één redelijk gemiddelde machine en vijf minuten om te installeren. Dat wil zeggen, we hebben zo'n database als bijvoorbeeld MySql, maar alleen voor het opslaan van miljarden records! Een bepaalde superarchiver met de SQL-taal. Het is alsof mensen de wapens van buitenaardse wezens hebben gekregen.

Over ons logsysteem

Om informatie te verzamelen, worden IIS-logbestanden van webapplicaties in standaardformaat gebruikt (we zijn momenteel ook bezig met het parseren van applicatielogboeken, maar het belangrijkste doel in de pilotfase is het verzamelen van IIS-logboeken).

Om verschillende redenen konden we de ELK-stack niet helemaal verlaten en blijven we de LogStash- en Filebeat-componenten gebruiken, die zich goed hebben bewezen en vrij betrouwbaar en voorspelbaar werken.

Het algemene logboekschema wordt weergegeven in de onderstaande afbeelding:

ClickHouse-database voor mensen of buitenaardse technologieën

Een kenmerk van het schrijven van gegevens naar de ClickHouse-database is het zelden (een keer per seconde) invoegen van records in grote batches. Dit is blijkbaar het meest "problematische" onderdeel dat u tegenkomt wanneer u voor het eerst met de ClickHouse-database werkt: het schema wordt iets gecompliceerder.
De plug-in voor LogStash, die rechtstreeks gegevens in ClickHouse invoegt, heeft hier veel geholpen. Dit onderdeel wordt op dezelfde server geïmplementeerd als de database zelf. Over het algemeen wordt het dus niet aanbevolen om het te doen, maar vanuit praktisch oogpunt, om geen afzonderlijke servers te produceren terwijl het op dezelfde server wordt ingezet. We hebben geen storingen of bronconflicten met de database waargenomen. Bovendien moet worden opgemerkt dat de plug-in een mechanisme voor opnieuw proberen heeft in geval van fouten. En in het geval van fouten, schrijft de plug-in een batch gegevens naar schijf die niet kon worden ingevoegd (het bestandsformaat is handig: na het bewerken kunt u eenvoudig de gecorrigeerde batch invoegen met behulp van clickhouse-client).

Een volledige lijst van software die in het schema wordt gebruikt, wordt weergegeven in de tabel:

Lijst met gebruikte software

Naam

beschrijving

Distributie koppeling

NGINX

Reverse-proxy om toegang per poort te beperken en autorisatie te organiseren

Momenteel niet gebruikt in het schema

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

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

BestandBeat

Overdracht van bestandslogboeken.

https://www.elastic.co/downloads/beats/filebeat (distributiekit voor Windows 64bit).

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

logstash

Log verzamelaar.

Gebruikt om logboeken van FileBeat te verzamelen, evenals om logboeken van de RabbitMQ-wachtrij te verzamelen (voor servers die zich in de DMZ bevinden.)

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

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

Logstash-output-klikhuis

Loagstash-plug-in voor het in batches overbrengen van logboeken naar de ClickHouse-database

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

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

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

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

Klik op Huis

Opslag van logboeken 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

Opmerking. Vanaf augustus 2018 verschenen "normale" rpm-builds voor RHEL in de Yandex-repository, dus u kunt proberen ze te gebruiken. Op het moment van installatie gebruikten we pakketten die waren gebouwd door Altinity.

grafana

Log visualisatie. Dashboards opzetten

https://grafana.com/

https://grafana.com/grafana/download

Redhat & Centos (64 Bit) - laatste versie

ClickHouse-gegevensbron voor Grafana 4.6+

Plug-in voor Grafana met ClickHouse-gegevensbron

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

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

logstash

Logrouter van FileBeat naar RabbitMQ-wachtrij.

Opmerking. Helaas heeft FileBeat geen directe uitvoer naar RabbitMQ, dus een tussenliggende link in de vorm van Logstash is vereist

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

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

RabbitMQ

berichtenwachtrij. Dit is de logboekbuffer in de 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 (vereist voor RabbitMQ)

Erlang looptijd. Vereist om RabbitMQ te laten werken

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

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

De serverconfiguratie met de ClickHouse-database wordt weergegeven in de volgende tabel:

Naam

Waarde

Noot

Configuratie

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

Het is noodzakelijk om aandacht te besteden aan de tips voor het bedienen van de ClickHouse-database (https://clickhouse.yandex/docs/ru/operations/tips/)

Algemene systeemsoftware

Besturingssysteem: Red Hat Enterprise Linux Server (Maipo)

JRE (Java 8)

 

Zoals je kunt zien is dit een gewoon werkstation.

De structuur van de tabel voor het opslaan van logboeken is als volgt:

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;

We gebruiken standaardpartitionering (per maand) en indexgranulariteit. Alle velden komen praktisch overeen met IIS-logboekvermeldingen voor het loggen van http-verzoeken. Afzonderlijk merken we op dat er afzonderlijke velden zijn voor het opslaan van utm-tags (deze worden geparseerd in het stadium van invoegen in de tabel vanuit het queryreeksveld).

Ook zijn er verschillende systeemvelden aan de tabel toegevoegd om informatie over systemen, componenten en servers op te slaan. Zie onderstaande tabel voor een beschrijving van deze velden. In één tabel slaan we logs op voor meerdere systemen.

Naam

beschrijving

Voorbeeld

fld_app_naam

Applicatie-/systeemnaam
Geldige waarden:

  • site1.domain.com Externe site 1
  • site2.domain.com Externe site 2
  • internal-site1.domain.local Interne site 1

site1.domein.com

fld_app_module

Systeemmodule
Geldige waarden:

  • internet - Website
  • svc - Websiteservice
  • intgr - Integratiewebservice
  • bo - Admin (BackOffice)

web

fld_website_naam

Sitenaam in IIS

Er kunnen meerdere systemen op één server worden geïmplementeerd, of zelfs meerdere exemplaren van één systeemmodule

web hoofd

fld_server_naam

Server naam

web1.domein.com

fld_log_bestandsnaam

Pad naar het logbestand op de server

C:inetpublogsLogFiles
W3SVC1u_ex190711.log

Hierdoor kun je efficiënt grafieken bouwen in Grafana. Bekijk bijvoorbeeld verzoeken van de frontend van een bepaald systeem. Dit is vergelijkbaar met de siteteller in Yandex.Metrica.

Hier zijn enkele statistieken over het gebruik van de database gedurende twee maanden.

Aantal records uitgesplitst naar systemen en hun componenten

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

De hoeveelheid gegevens op de schijf

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.

Mate van datacompressie in kolommen

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.

Beschrijving van gebruikte componenten

FileBeat. Bestandslogboeken overzetten

Dit onderdeel volgt wijzigingen in logbestanden op schijf en geeft de informatie door aan LogStash. Geïnstalleerd op alle servers waar logbestanden worden geschreven (meestal IIS). Werkt in staartmodus (d.w.z. brengt alleen de toegevoegde records over naar het bestand). Maar afzonderlijk kan het worden geconfigureerd om volledige bestanden over te dragen. Dit is handig wanneer u gegevens van voorgaande maanden moet downloaden. Plaats het logbestand gewoon in een map en het zal het in zijn geheel lezen.

Wanneer de service wordt gestopt, worden de gegevens niet meer verder naar de opslag overgedragen.

Een voorbeeldconfiguratie ziet er als volgt uit:

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. Log verzamelaar

Dit onderdeel is ontworpen om loggegevens van FileBeat (of via de RabbitMQ-wachtrij) te ontvangen, batches te parseren en in te voegen in de ClickHouse-database.

Voor invoeging in ClickHouse wordt de plug-in Logstash-output-clickhouse gebruikt. De Logstash-plug-in heeft een mechanisme voor het opnieuw proberen van verzoeken, maar bij een regelmatige afsluiting is het beter om de service zelf te stoppen. Wanneer gestopt, worden berichten verzameld in de RabbitMQ-wachtrij, dus als de stop voor een lange tijd is, is het beter om Filebeats op de servers te stoppen. In een schema waarbij RabbitMQ niet wordt gebruikt (op het lokale netwerk stuurt Filebeat rechtstreeks logs naar Logstash), werkt Filebeats redelijk acceptabel en veilig, dus voor hen gaat de onbeschikbaarheid van uitvoer zonder gevolgen voorbij.

Een voorbeeldconfiguratie ziet er als volgt uit:

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

pijplijnen.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"

klikhuis. Opslag van logboeken

Logboeken voor alle systemen worden in één tabel opgeslagen (zie aan het begin van het artikel). Het is bedoeld om informatie over verzoeken op te slaan: alle parameters zijn vergelijkbaar voor verschillende formaten, zoals IIS-logboeken, apache- en nginx-logboeken. Voor applicatielogboeken, waarin bijvoorbeeld fouten, informatiemeldingen, waarschuwingen worden vastgelegd, zal een aparte tabel worden voorzien met de juiste structuur (momenteel in ontwerpfase).

Bij het ontwerpen van een tabel is het erg belangrijk om te beslissen over de primaire sleutel (waarop de gegevens tijdens opslag worden gesorteerd). De mate van datacompressie en querysnelheid zijn hiervan afhankelijk. In ons voorbeeld is de sleutel
BESTEL OP (fld_app_name, fld_app_module, logdatetime)
Dat wil zeggen op de naam van het systeem, de naam van het systeemonderdeel en de datum van de gebeurtenis. Aanvankelijk kwam de datum van het evenement op de eerste plaats. Nadat het naar de laatste plaats was verplaatst, begonnen zoekopdrachten ongeveer twee keer zo snel te werken. Als u de primaire sleutel wijzigt, moet u de tabel opnieuw maken en de gegevens opnieuw laden, zodat ClickHouse de gegevens op schijf opnieuw sorteert. Dit is een zware operatie, dus het is een goed idee om goed na te denken over wat er in de sorteersleutel moet worden opgenomen.

Er moet ook worden opgemerkt dat het gegevenstype LowCardinality relatief in recente versies is verschenen. Bij gebruik wordt de grootte van gecomprimeerde gegevens drastisch verkleind voor die velden met een lage cardinaliteit (weinig opties).

Versie 19.6 is momenteel in gebruik en we zijn van plan om te updaten naar de nieuwste versie. Ze hebben bijvoorbeeld geweldige functies als Adaptive Granularity, Skip indices en de DoubleDelta-codec.

Tijdens de installatie is het logniveau standaard ingesteld op traceren. De logs worden geroteerd en gearchiveerd, maar tegelijkertijd breiden ze uit tot een gigabyte. Als het niet nodig is, kunt u het waarschuwingsniveau instellen, waarna de grootte van het logboek drastisch wordt verkleind. De logboekinstelling wordt ingesteld in het bestand config.xml:

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

Enkele handige commando's

Поскольку оригинальные пакеты установки собираются по 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. Logrouter van FileBeat naar RabbitMQ-wachtrij

Deze component wordt gebruikt om logboeken die afkomstig zijn van FileBeat naar de RabbitMQ-wachtrij te routeren. Er zijn hier twee punten:

  1. Helaas heeft FileBeat geen uitvoerplug-in om rechtstreeks naar RabbitMQ te schrijven. En dergelijke functionaliteit, te oordelen naar het probleem op hun github, is niet gepland voor implementatie. Er is een plug-in voor Kafka, maar om de een of andere reden kunnen we die thuis niet gebruiken.
  2. Er zijn vereisten voor het verzamelen van logboeken in de DMZ. Op basis daarvan moeten de logs eerst aan de wachtrij worden toegevoegd en vervolgens leest LogStash de ingangen uit de wachtrij van buitenaf.

Daarom is het voor het geval dat servers zich in de DMZ bevinden dat men zo'n ietwat gecompliceerd schema moet gebruiken. Een voorbeeldconfiguratie ziet er als volgt uit:

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

KonijnMQ. berichtenwachtrij

Deze component wordt gebruikt om logboekvermeldingen in de DMZ te bufferen. Opnemen gebeurt via een aantal Filebeat → LogStash. Het uitlezen gebeurt van buiten de DMZ via LogStash. Bij het werken via RabboitMQ worden ongeveer 4 duizend berichten per seconde verwerkt.

Berichtroutering wordt geconfigureerd op systeemnaam, d.w.z. op basis van FileBeat-configuratiegegevens. Alle berichten gaan naar één wachtrij. Als om de een of andere reden de wachtrijservice wordt gestopt, leidt dit niet tot het verlies van berichten: FileBeats ontvangt verbindingsfouten en onderbreekt het verzenden tijdelijk. En LogStash die uit de wachtrij leest, ontvangt ook netwerkfouten en wacht tot de verbinding is hersteld. In dit geval worden de gegevens uiteraard niet meer naar de database geschreven.

De volgende instructies worden gebruikt om wachtrijen te maken en te configureren:

sudo /usr/local/bin/rabbitmqadmin/rabbitmqadmin declare exchange --vhost=/ name=monitor.direct type=direct sudo /usr/local/bin/rabbitmqadmin/rabbitmqadmin declare queue --vhost=/ name=web_log durable=true
sudo /usr/local/bin/rabbitmqadmin/rabbitmqadmin --vhost="/" declare binding source="monitor.direct" destination_type="queue" destination="web_log" routing_key="site1.domain.ru"
sudo /usr/local/bin/rabbitmqadmin/rabbitmqadmin --vhost="/" declare binding source="monitor.direct" destination_type="queue" destination="web_log" routing_key="site2.domain.ru"

grafana. Dashboards

Deze component wordt gebruikt om monitoringgegevens te visualiseren. In dit geval moet u de ClickHouse-gegevensbron voor Grafana 4.6+ plug-in installeren. We moesten het een beetje aanpassen om de efficiëntie van het verwerken van SQL-filters op het dashboard te verbeteren.

We gebruiken bijvoorbeeld variabelen en als ze niet zijn ingesteld in het filterveld, willen we dat er geen voorwaarde wordt gegenereerd in de WHERE van het formulier ( uriStem = » EN uriStem != » ). In dit geval leest ClickHouse de kolom uriStem. Over het algemeen hebben we verschillende opties geprobeerd en uiteindelijk de plug-in (de macro $valueIfEmpty) gecorrigeerd zodat deze in het geval van een lege waarde 1 retourneert, zonder de kolom zelf te vermelden.

En nu kunt u deze query gebruiken voor de grafiek

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

wat zich vertaalt naar deze SQL (merk op dat de lege uriStem-velden zijn geconverteerd naar slechts 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

Conclusie

Het uiterlijk van de ClickHouse-database is een mijlpaal in de markt geworden. Het was moeilijk voor te stellen dat we in een oogwenk, geheel gratis, gewapend waren met een krachtige en praktische tool om met big data te werken. Met toenemende behoeften (bijvoorbeeld sharding en replicatie naar meerdere servers) wordt het schema natuurlijk ingewikkelder. Maar bij de eerste indrukken is het werken met deze database erg prettig. Het is te zien dat het product is gemaakt "voor mensen".

In vergelijking met ElasticSearch worden de kosten voor het opslaan en verwerken van logboeken naar schatting vijf tot tien keer verlaagd. Met andere woorden, als we voor de huidige hoeveelheid data een cluster van meerdere machines zouden moeten opzetten, dan hebben we bij ClickHouse aan één energiezuinige machine genoeg. Ja, natuurlijk heeft ElasticSearch ook on-disk datacompressiemechanismen en andere functies die het verbruik van bronnen aanzienlijk kunnen verminderen, maar in vergelijking met ClickHouse zal dit duurder zijn.

Zonder enige speciale optimalisaties van onze kant, op standaardinstellingen, het laden van gegevens en het selecteren uit de database gaat het met een verbazingwekkende snelheid. We hebben nog niet veel gegevens (ongeveer 200 miljoen records), maar de server zelf is zwak. We kunnen deze tool in de toekomst gebruiken voor andere doeleinden die geen verband houden met het opslaan van logboeken. Bijvoorbeeld voor end-to-end analytics, op het gebied van security, machine learning.

Tot slot iets over de voor- en nadelen.

Tegens

  1. Records in grote batches laden. Aan de ene kant is dit een feature, maar voor het bufferen van records moet je nog extra componenten gebruiken. Deze taak is niet altijd gemakkelijk, maar nog steeds oplosbaar. En ik zou het schema willen vereenvoudigen.
  2. Sommige exotische functionaliteit of nieuwe functies breken vaak in nieuwe versies. Dit baart zorgen, waardoor de wens om naar een nieuwe versie te upgraden afneemt. De Kafka-tabelengine is bijvoorbeeld een zeer handige functie waarmee u rechtstreeks gebeurtenissen uit Kafka kunt lezen, zonder consumenten te implementeren. Maar te oordelen naar het aantal problemen op de github, zijn we nog steeds voorzichtig om deze engine niet in productie te gebruiken. Als u echter geen plotselinge zijwaartse gebaren maakt en de hoofdfunctionaliteit gebruikt, werkt het stabiel.

Voors

  1. Vertraagt ​​niet.
  2. Lage instapdrempel.
  3. Open source.
  4. Vrij.
  5. Schaalt goed (sharding/replicatie out of the box)
  6. Inbegrepen in het register van Russische software aanbevolen door het Ministerie van Communicatie.
  7. De aanwezigheid van officiële ondersteuning van Yandex.

Bron: www.habr.com

Voeg een reactie