ClickHouse-database for mennesker, eller fremmede teknologier

Alexey Lizunov, leder for kompetansesenteret for eksterne tjenestekanaler til IT-direktoratet for ICB

ClickHouse-database for mennesker, eller fremmede teknologier

Som et alternativ til ELK-stakken (ElasticSearch, Logstash, Kibana) forsker vi på å bruke ClickHouse-databasen som datalagring for logger.

I denne artikkelen vil vi gjerne snakke om vår erfaring med å bruke ClickHouse-databasen og foreløpige resultater fra pilotdrift. Det er verdt å merke seg med en gang at resultatene var imponerende.


ClickHouse-database for mennesker, eller fremmede teknologier

Deretter vil vi beskrive mer detaljert hvordan systemet vårt er konfigurert og hvilke komponenter det består av. Men nå vil jeg gjerne snakke litt om denne databasen som helhet, og hvorfor det er verdt å ta hensyn til. ClickHouse-databasen er en analytisk kolonnebasert database med høy ytelse fra Yandex. Brukt i Yandex-tjenester, er dette i utgangspunktet hoveddatalagringen for Yandex.Metrica. Åpen kildekode-system, gratis. Fra en utviklers side har jeg alltid lurt på hvordan de implementerte dette, for det er fantastisk store data. Og selve brukergrensesnittet til Metrica er veldig fleksibelt og fungerer raskt. Når du først blir kjent med denne databasen får du inntrykket: «Vel, endelig! Laget "for folket"! Fra installasjonsprosessen til å sende forespørsler."

Denne databasen har en svært lav inngangsbarriere. Selv en gjennomsnittlig dyktig utvikler kan installere denne databasen på noen få minutter og begynne å bruke den. Alt fungerer knirkefritt. Selv folk som er nye til Linux kan raskt håndtere installasjonen og gjøre de enkleste operasjonene. Hvis tidligere, med ordene Big Data, Hadoop, Google BigTable, HDFS, en vanlig utvikler hadde ideer om at det handlet om noen terabyte, petabyte, at noen supermennesker er involvert i innstillinger og utvikling for disse systemene, så med ankomsten av ClickHouse database, har vi et enkelt, forståelig verktøy som du kan løse et tidligere uoppnåelig spekter av oppgaver med. Alt som trengs er en ganske gjennomsnittlig maskin og fem minutter å installere. Det vil si at vi fikk en slik database som for eksempel MySql, men bare for å lagre milliarder av poster! En slags superarkiver med SQL-språk. Det er som om folk har fått fremmede våpen.

Om vårt logginnsamlingssystem

For å samle inn informasjon brukes IIS-loggfiler av nettapplikasjoner av standardformat (vi er også for tiden engasjert i å analysere applikasjonslogger, men vårt hovedmål på pilotstadiet er å samle IIS-logger).

Vi klarte ikke å forlate ELK-stakken fullstendig av ulike årsaker, og vi fortsetter å bruke LogStash- og Filebeat-komponentene, som har vist seg godt og fungerer ganske pålitelig og forutsigbart.

Det generelle loggingsskjemaet er vist i figuren nedenfor:

ClickHouse-database for mennesker, eller fremmede teknologier

En funksjon ved å registrere data i ClickHouse-databasen er sjelden (en gang per sekund) innsetting av poster i store partier. Dette er tilsynelatende den mest "problematiske" delen du møter når du arbeider med ClickHouse-databasen for første gang: ordningen blir litt mer komplisert.
Plugin for LogStash, som direkte setter inn data i ClickHouse, hjalp mye her. Denne komponenten er distribuert på samme server som selve databasen. Så generelt sett anbefales det ikke å gjøre dette, men fra et praktisk synspunkt, for ikke å lage separate servere mens det er distribuert på samme server. Vi har ikke observert noen feil eller ressurskonflikter med databasen. I tillegg bør det bemerkes at plugin-en har en gjenopprettingsmekanisme i tilfelle feil. Og i tilfelle feil, skriver plugin til disken en batch med data som ikke kunne settes inn (filformatet er praktisk: etter redigering kan du enkelt sette inn den korrigerte batchen ved å bruke clickhouse-klient).

En fullstendig liste over programvare som brukes i ordningen er presentert i tabellen:

Liste over programvare som er brukt

Navn

beskrivelse

Link til distribusjon

Nginx

Omvendt proxy for å begrense tilgang ved port og organisering av autorisasjon

Foreløpig ikke brukt i ordningen

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

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

FileBeat

Overføring av fillogger.

https://www.elastic.co/downloads/beats/filebeat (distribusjon for Windows 64bit).

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

LogStash

Loggsamler.

Brukes til å samle logger fra FileBeat, samt til å samle logger fra RabbitMQ-køen (for servere som er i DMZ.)

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

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

Logstash- output- clickhouse

Loagstash-plugin for overføring av logger til ClickHouse-databasen i grupper

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

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

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

/usr/share/logstash/bin/logstash-plugin installer 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

Merk. Fra og med august 2018 dukket "normale" rpm-bygg for RHEL opp i Yandex-depotet, så du kan prøve å bruke dem. På installasjonstidspunktet brukte vi pakker kompilert av Altinity.

grafana

Visualisering av logger. Sette opp dashbord

https://grafana.com/

https://grafana.com/grafana/download

Redhat & Centos (64 Bit) – siste versjon

ClickHouse-datakilde for Grafana 4.6+

Plugin for Grafana med ClickHouse-datakilde

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

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

LogStash

Logg ruter fra FileBeat til RabbitMQ kø.

Merk. FileBeat har dessverre ikke utgang direkte til RabbitMQ, så en mellomkobling i form av Logstash kreves

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

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

Kanin MQ

Meldingskø. Dette er en buffer av loggoppføringer 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 (påkrevd for RabbitMQ)

Erlang kjøretid. Nødvendig for at RabbitMQ skal fungere

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

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

Serverkonfigurasjonen med ClickHouse-databasen er presentert i følgende tabell:

Navn

Verdi

Note

Konfigurasjon

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

Du bør være oppmerksom på tipsene for bruk av ClickHouse-databasen (https://clickhouse.yandex/docs/ru/operations/tips/)

Programvare for hele systemet

OS: Red Hat Enterprise Linux Server (Maipo)

JRE (Java 8)

 

Som du ser er dette en vanlig arbeidsstasjon.

Strukturen til tabellen for lagring av logger er som følger:

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 bruker standardverdier for partisjonering (månedlig) og indeksgranularitet. Alle felt tilsvarer praktisk talt IIS-loggoppføringer for registrering av http-forespørsler. Separat legger vi merke til at det er separate felt for lagring av utm-tagger (de blir analysert på stadiet for innsetting i tabellen fra spørringsstrengfeltet).

Det er også lagt til flere systemfelt i tabellen for å lagre informasjon om systemer, komponenter og servere. For en beskrivelse av disse feltene, se tabellen nedenfor. I en tabell lagrer vi logger for flere systemer.

Navn

beskrivelse

Eksempel

fld_app_name

Navn på applikasjon/system
Gyldige verdier:

  • site1.domain.com Eksternt nettsted 1
  • site2.domain.com Eksternt nettsted 2
  • internal-site1.domain.local Intern site 1

site1.domain.com

fld_app_module

Systemmodul
Gyldige verdier:

  • web - Nettside
  • svc — Nettstedets webtjeneste
  • intgr — Webintegrasjonstjeneste
  • bo – Administrator (BackOffice)

web

fld_website_name

Navn på nettsted i IIS

Flere systemer kan distribueres på én server, eller til og med flere forekomster av én systemmodul

web-main

fld_server_name

Server navn

web1.domene.com

fld_log_file_name

Banen til loggfilen på serveren

Fra:inetpublogsLogFiles
W3SVC1u_ex190711.log

Dette lar deg bygge grafer effektivt i Grafana. Se for eksempel forespørsler fra frontenden av et spesifikt system. Dette ligner på sidetelleren i Yandex.Metrica.

Her er litt statistikk om databasebruk i to måneder.

Antall poster etter system og komponent

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

Diskdatavolum

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.

Kompresjonsforhold for kolonnedata

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.

Beskrivelse av komponenter som brukes

FileBeat. Overføring av fillogger

Denne komponenten overvåker endringer i loggfiler på disken og sender informasjonen til LogStash. Installert på alle servere der loggfiler er skrevet (vanligvis IIS). Fungerer i halemodus (dvs. den overfører bare lagt til poster til filen). Men du kan separat konfigurere den til å overføre hele filer. Dette er praktisk når du trenger å laste ned data for tidligere måneder. Bare legg loggfilen i en mappe og den vil lese den i sin helhet.

Når tjenesten stopper, slutter data å overføres videre til lageret.

Et eksempel på konfigurasjon ser slik ut:

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

Denne komponenten er designet for å motta loggoppføringer fra FileBeat (eller gjennom RabbitMQ-køen), analysere og sette inn batcher i ClickHouse-databasen.

For å sette inn i ClickHouse, bruk Logstash-output-clickhouse-plugin. Logstash-pluginen har en mekanisme for å spore forespørsler, men under en vanlig nedleggelse er det bedre å stoppe selve tjenesten. Når den stoppes, vil meldinger samle seg i RabbitMQ-køen, så hvis stoppet er over lang tid, er det bedre å stoppe Filebeats på serverne. I et opplegg der RabbitMQ ikke brukes (på det lokale nettverket sender Filebeat logger direkte til Logstash), fungerer Filebeats ganske akseptabelt og trygt, så for dem har utilgjengelighet av utdata ingen konsekvenser.

Et eksempel på konfigurasjon ser slik ut:

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

Logger for alle systemer lagres i én tabell (se i begynnelsen av artikkelen). Den er designet for å lagre informasjon om forespørsler: alle parametere er like for forskjellige formater, for eksempel IIS-logger, apache- og nginx-logger. For applikasjonslogger der for eksempel feil, informasjonsmeldinger, advarsler registreres, vil det bli gitt en egen tabell med passende struktur (for øyeblikket på designstadiet).

Når du designer en tabell, er det veldig viktig å bestemme primærnøkkelen (som dataene skal sorteres etter under lagring). Graden av datakomprimering og spørringshastighet avhenger av dette. I vårt eksempel er nøkkelen
BESTILL ETTER (fld_app_name, fld_app_module, logdatetime)
Det vil si ved navnet på systemet, navnet på systemkomponenten og datoen for hendelsen. I utgangspunktet kom datoen for arrangementet først. Etter å ha flyttet den til det siste stedet, begynte spørringene å fungere omtrent dobbelt så raskt. Endring av primærnøkkelen vil kreve å gjenskape tabellen og laste opp dataene på nytt slik at ClickHouse vil omsortere dataene på disken. Dette er en vanskelig operasjon, så det er lurt å tenke nøye gjennom på forhånd hva som skal være med i sorteringsnøkkelen.

Det bør også bemerkes at LowCardinality-datatypen dukket opp i relativt nyere versjoner. Når du bruker det, reduseres størrelsen på komprimerte data kraftig for de feltene som har lav kardinalitet (få alternativer).

Vi bruker for øyeblikket versjon 19.6 og vi planlegger å prøve å oppdatere til siste versjon. De har så fantastiske funksjoner som Adaptive Granularity, Skipping-indekser og DoubleDelta-kodeken, for eksempel.

Som standard er konfigurasjonsloggingsnivået satt til sporing under installasjonen. Logger roteres og arkiveres, men de utvides samtidig opp til en gigabyte. Hvis det ikke er behov, kan du stille inn advarselsnivået, da reduseres størrelsen på loggen drastisk. Logginnstillingene er spesifisert i config.xml-filen:

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

Noen nyttige kommandoer

Поскольку оригинальные пакеты установки собираются по 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. Logg ruter fra FileBeat til RabbitMQ kø

Denne komponenten brukes til å rute logger som kommer fra FileBeat til RabbitMQ-køen. Det er to punkter her:

  1. Dessverre har ikke FileBeat en utdataplugin for å skrive direkte til RabbitMQ. Og slik funksjonalitet, etter innlegget på githuben deres, er ikke planlagt for implementering. Det finnes en plugin for Kafka, men av visse grunner kan vi ikke bruke den selv.
  2. Det er krav til innsamling av logger i DMZ. Basert på dem må loggene først settes i kø og deretter leser LogStash poster fra køen eksternt.

Derfor, spesifikt for servere plassert i en DMZ, er det nødvendig å bruke et så litt komplisert opplegg. Et eksempel på konfigurasjon ser slik ut:

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. Meldingskø

Denne komponenten brukes til å bufre loggoppføringer i DMZ. Opptak gjøres gjennom Filebeat → LogStash-lenken. Lesing gjøres fra utenfor DMZ via LogStash. Når du opererer gjennom RabbitMQ, behandles omtrent 4 tusen meldinger per sekund.

Meldingsruting konfigureres etter systemnavn, dvs. basert på FileBeat-konfigurasjonsdata. Alle meldinger går i én kø. Hvis køtjenesten av en eller annen grunn stoppes, vil dette ikke føre til tap av meldinger: FileBeats vil motta tilkoblingsfeil og vil midlertidig slutte å sende. Og LogStash, som leser fra køen, vil også motta nettverksfeil og vente på at forbindelsen skal gjenopprettes. I dette tilfellet vil dataene selvfølgelig ikke lenger skrives til databasen.

Følgende instruksjoner brukes til å opprette og konfigurere 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. Dashboards

Denne komponenten brukes til å visualisere overvåkingsdata. I dette tilfellet må du installere ClickHouse-datakilden for Grafana 4.6+ plugin. Vi måtte finpusse det litt for å forbedre effektiviteten til å behandle SQL-filtre på dashbordet.

For eksempel bruker vi variabler, og hvis de ikke er satt i filterfeltet, vil vi gjerne at det ikke genererer en betingelse i skjemaets WHERE ( uriStem = » OG uriStem != » ). I dette tilfellet vil ClickHouse lese uriStem-kolonnen. Generelt prøvde vi forskjellige alternativer og korrigerte til slutt plugin-en ($valueIfEmpty-makroen) slik at i tilfelle en tom verdi returnerer den 1, uten å nevne selve kolonnen.

Og nå kan du bruke denne spørringen for grafen

$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 konverteres til SQL slik (merk at tomme uriStem-felt konverteres til bare 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

Konklusjon

Utseendet til ClickHouse-databasen har blitt en landemerkebegivenhet i markedet. Det var vanskelig å forestille seg at vi på et øyeblikk, helt gratis, var bevæpnet med et kraftig og praktisk verktøy for å jobbe med big data. Selvfølgelig, ettersom behovene øker (for eksempel sharding og replikering til flere servere), vil ordningen bli mer kompleks. Men ifølge førsteinntrykket er det veldig hyggelig å jobbe med denne databasen. Det er tydelig at produktet er laget "for mennesker".

Sammenlignet med ElasticSearch er kostnadene for lagring og behandling av logger, ifølge foreløpige estimater, redusert med fem til ti ganger. Med andre ord, hvis vi for det nåværende datavolumet må sette opp en klynge med flere maskiner, trenger vi bare én laveffektsmaskin når vi bruker ClickHouse. Ja, selvfølgelig har ElasticSearch også datakomprimeringsmekanismer på disken og andre funksjoner som kan redusere ressursforbruket betydelig, men sammenlignet med ClickHouse vil dette kreve større kostnader.

Uten noen spesielle optimaliseringer fra vår side, med standardinnstillinger, fungerer lasting av data og henting av data fra databasen med utrolig hastighet. Vi har ikke mye data ennå (omtrent 200 millioner poster), men selve serveren er svak. Vi kan bruke dette verktøyet i fremtiden til andre formål som ikke er relatert til lagring av logger. For eksempel for ende-til-ende-analyse, innen sikkerhet, maskinlæring.

Til slutt, litt om fordeler og ulemper.

Cons

  1. Laster poster i store partier. På den ene siden er dette en funksjon, men du må fortsatt bruke tilleggskomponenter for å buffere poster. Denne oppgaven er ikke alltid enkel, men likevel løsbar. Og jeg vil gjerne forenkle ordningen.
  2. Noen eksotiske funksjoner eller nye funksjoner bryter ofte i nye versjoner. Dette vekker bekymring, og reduserer ønsket om å oppgradere til en ny versjon. For eksempel er Kafka-bordmotoren en veldig nyttig funksjon som lar deg lese hendelser fra Kafka direkte, uten å implementere forbrukere. Men å dømme etter antall utgaver på Github, er vi fortsatt forsiktige med å bruke denne motoren i produksjon. Men hvis du ikke gjør brå bevegelser til siden og bruker den grunnleggende funksjonaliteten, så fungerer det stabilt.

Pros

  1. Brekker ikke farten.
  2. Lav inngangsgrense.
  3. Åpen kilde.
  4. Gratis.
  5. Skalerbar (sharding/out-of-the-box replikering)
  6. Inkludert i registeret over russisk programvare anbefalt av kommunikasjonsdepartementet.
  7. Tilgjengelighet av offisiell støtte fra Yandex.

Kilde: www.habr.com

Legg til en kommentar