ClickHouse Database for Humans vagy Alien Technologies

Alekszej Lizunov, az MKB Információs Technológiai Igazgatóság Távszolgáltatási Csatornái Kompetencia Központ vezetője

ClickHouse Database for Humans vagy Alien Technologies

Az ELK verem (ElasticSearch, Logstash, Kibana) alternatívájaként kutatunk a ClickHouse adatbázis naplók adattárolójaként való használatával kapcsolatban.

Ebben a cikkben a ClickHouse adatbázis használatának tapasztalatairól és a kísérleti üzemeltetés előzetes eredményeiről szeretnénk beszélni. Azonnal meg kell jegyezni, hogy az eredmények lenyűgözőek voltak.


ClickHouse Database for Humans vagy Alien Technologies

Ezután részletesebben leírjuk, hogyan van beállítva a rendszerünk, és milyen összetevőkből áll. De most erről az adatbázisról, mint egészről szeretnék egy kicsit beszélni, és hogy miért érdemes erre odafigyelni. A ClickHouse adatbázis a Yandex nagy teljesítményű elemző oszlopos adatbázisa. A Yandex szolgáltatásokban használatos, kezdetben a Yandex.Metrica fő adattárolója. Nyílt forráskódú rendszer, ingyenes. Fejlesztői szempontból mindig is kíváncsi voltam, hogyan valósították meg, mert fantasztikusan nagy adatok vannak. Maga a Metrica felhasználói felülete pedig nagyon rugalmas és gyors. Az adatbázis első megismerésekor az a benyomásom, hogy „Na végre! Az embereknek készült! A telepítési folyamattól kezdve a kérések elküldésével.

Ennek az adatbázisnak nagyon alacsony a belépési küszöbe. Még egy átlagosan képzett fejlesztő is néhány perc alatt telepítheti ezt az adatbázist, és elkezdheti használni. Minden egyértelműen működik. Még azok is, akik még nem ismerik a Linuxot, gyorsan tudják kezelni a telepítést és elvégezni a legegyszerűbb műveleteket. Ha korábban a Big Data, Hadoop, Google BigTable, HDFS szavakkal egy hétköznapi fejlesztőnek olyan ötlete támadt, hogy néhány terabájtról, petabájtról van szó, hogy néhány emberfeletti ember foglalkozik ezeknek a rendszereknek a beállításával és fejlesztésével, akkor a ClickHouse megjelenésével adatbázis, kaptunk egy egyszerű, érthető eszközt, amellyel korábban elérhetetlen feladatsort oldhat meg. Csak egy meglehetősen átlagos gépet és öt percet vesz igénybe a telepítés. Vagyis kaptunk egy olyan adatbázist, mint például a MySql, de csak több milliárd rekord tárolására! Egy bizonyos szuper-archiváló SQL nyelvvel. Mintha az emberek kezébe adták volna az idegenek fegyvereit.

Naplórendszerünkről

Az információgyűjtéshez szabványos formátumú webalkalmazások IIS naplófájljait használjuk (jelenleg az alkalmazásnaplók elemzését is végezzük, de a kísérleti szakaszban a fő cél az IIS naplók gyűjtése).

Különféle okok miatt nem tudtuk teljesen elhagyni az ELK stacket, továbbra is a LogStash és Filebeat komponenseket használjuk, amelyek jól beváltak, és meglehetősen megbízhatóan és kiszámíthatóan működnek.

Az általános naplózási séma az alábbi ábrán látható:

ClickHouse Database for Humans vagy Alien Technologies

A ClickHouse adatbázisba való adatírás egyik jellemzője a rekordok ritkán (másodpercenként egyszeri) beillesztése nagy kötegekben. Úgy tűnik, ez a „legproblémásabb” rész, amivel találkozik, amikor először tapasztalja a ClickHouse adatbázissal való munkát: a séma kissé bonyolultabbá válik.
Itt sokat segített a LogStash bővítménye, amely közvetlenül a ClickHouse-ba illeszti be az adatokat. Ez az összetevő ugyanazon a kiszolgálón van telepítve, mint maga az adatbázis. Általánosságban elmondható tehát, hogy nem ajánlatos megtenni, hanem gyakorlati szempontból, hogy ne jöjjön létre külön szerver, miközben ugyanazon a szerveren van telepítve. Nem észleltünk meghibásodást vagy erőforrás-ütközést az adatbázisban. Ezenkívül meg kell jegyezni, hogy a beépülő modulnak van egy újrapróbálkozási mechanizmusa hibák esetén. Hiba esetén a beépülő modul olyan adatköteget ír a lemezre, amelyet nem lehetett beilleszteni (a fájlformátum kényelmes: szerkesztés után egyszerűen beillesztheti a javított köteget a clickhouse-client segítségével).

A sémában használt szoftverek teljes listája a táblázatban látható:

A használt szoftverek listája

Név

Leírás

Terjesztési link

nginx

Fordított proxy a portok hozzáférésének korlátozásához és az engedélyezés megszervezéséhez

Jelenleg nem használják a rendszerben

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

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

FileBeat

Fájlnaplók átvitele.

https://www.elastic.co/downloads/beats/filebeat (terjesztési készlet Windows 64 bithez).

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

logstash

Rönkgyűjtő.

A FileBeat naplóinak gyűjtésére, valamint a RabbitMQ sorból való naplók gyűjtésére szolgál (a DMZ-ben lévő szerverekhez).

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

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

Logstash-output-clickhouse

Loagstash bővítmény a naplók kötegelt átviteléhez a ClickHouse adatbázisba

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

Kattintson a Ház gombra

Rönktárolás 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

Jegyzet. 2018 augusztusától a Yandex adattárában megjelentek az RHEL „normál” rpm buildjei, így megpróbálhatja használni őket. A telepítés idején az Altinity által készített csomagokat használtuk.

grafana

Napló vizualizáció. Irányítópultok beállítása

https://grafana.com/

https://grafana.com/grafana/download

Redhat & Centos (64 bites) - legújabb verzió

ClickHouse adatforrás a Grafana 4.6+-hoz

Grafana bővítmény ClickHouse adatforrással

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

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

logstash

Az útválasztó naplózása a FileBeatből a RabbitMQ sorba.

Jegyzet. Sajnos a FileBeatnek nincs közvetlen kimenete a RabbitMQ-hoz, ezért szükség van egy köztes hivatkozásra Logstash formájában

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

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

Nyúl MQ

üzenetsor. Ez a napló puffer a DMZ-ben

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 (szükséges a RabbitMQ-hoz)

Erlang futási idő. Szükséges a RabbitMQ működéséhez

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

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

A szerver konfigurációja a ClickHouse adatbázissal az alábbi táblázatban látható:

Név

Érték

Megjegyzés

Configuration

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

Figyelni kell a ClickHouse adatbázis kezelésével kapcsolatos tippekre (https://clickhouse.yandex/docs/ru/operations/tips/)

Általános rendszerszoftver

OS: Red Hat Enterprise Linux Server (Maipo)

JRE (Java 8)

 

Amint látja, ez egy közönséges munkaállomás.

A naplók tárolására szolgáló táblázat felépítése a következő:

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;

Alapértelmezett particionálást (havi) és indexrészletezést használunk. Az összes mező gyakorlatilag megfelel az IIS naplóbejegyzéseinek a http kérések naplózására. Külön megjegyezzük, hogy külön mezők vannak az utm-címkék tárolására (a lekérdezési karakterlánc mezőből a táblázatba történő beszúrás szakaszában kerülnek elemzésre).

Emellett több rendszermező is hozzáadásra került a táblához a rendszerekről, összetevőkről és szerverekről szóló információk tárolására. A mezők leírását lásd az alábbi táblázatban. Egy táblázatban több rendszer naplóit tároljuk.

Név

Leírás

Példa

fld_app_name

Alkalmazás/rendszer neve
Érvényes értékek:

  • site1.domain.com Külső webhely 1
  • site2.domain.com Külső webhely 2
  • belső-hely1.domain.local 1. belső webhely

site1.domain.com

fld_app_module

Rendszer modul
Érvényes értékek:

  • web - Weboldal
  • svc – Webhelyszolgáltatás
  • intgr – Integrációs webszolgáltatás
  • bo - Adminisztrátor (BackOffice)

háló

fld_webhely_neve

A webhely neve az IIS-ben

Egy kiszolgálón több rendszer, vagy akár egy rendszermodul több példánya is telepíthető

web fő

fld_szerver_neve

Szerver név

web1.domain.com

fld_log_file_name

A szerveren lévő naplófájl elérési útja

C:inetpublogsLogFiles
W3SVC1u_ex190711.log

Ez lehetővé teszi, hogy hatékonyan készítsen grafikonokat a Grafanában. Például megtekintheti egy adott rendszer frontendjétől érkező kéréseket. Ez hasonló a Yandex.Metrica webhelyszámlálójához.

Íme néhány statisztikai adat az adatbázis két hónapos használatáról.

A rekordok száma rendszerek és összetevőik szerinti bontásban

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

A lemezen lévő adatmennyiség

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.

Az adattömörítés mértéke oszlopokban

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.

A használt alkatrészek leírása

FileBeat. Fájlnaplók átvitele

Ez az összetevő nyomon követi a lemezen lévő naplófájlok változásait, és továbbítja az információkat a LogStash-nak. Telepítve minden olyan szerveren, ahol naplófájlok vannak írva (általában IIS). Tail módban működik (azaz csak a hozzáadott rekordokat viszi át a fájlba). De külön-külön is beállítható teljes fájlok átvitelére. Ez akkor hasznos, ha előző hónapok adatait kell letöltenie. Csak helyezze a naplófájlt egy mappába, és a teljes egészében elolvassa.

A szolgáltatás leállításakor az adatok már nem kerülnek tovább a tárolóba.

Egy példa konfiguráció így néz ki:

filebeat.yml

filebeat.inputs:
- type: log
  enabled: true
  paths:
    - C:/inetpub/logs/LogFiles/W3SVC1/*.log
  exclude_files: ['.gz$','.zip$']
  tail_files: true
  ignore_older: 24h
  fields:
    fld_server_name: "site1.domain.ru"
    fld_app_name: "site1.domain.ru"
    fld_app_module: "web"
    fld_website_name: "web-main"
 
- type: log
  enabled: true
  paths:
    - C:/inetpub/logs/LogFiles/__Import/access_log-*
  exclude_files: ['.gz$','.zip$']
  tail_files: false
  fields:
    fld_server_name: "site2.domain.ru"
    fld_app_name: "site2.domain.ru"
    fld_app_module: "web"
    fld_website_name: "web-main"
    fld_logformat: "logformat__apache"
 
 
filebeat.config.modules:
  path: ${path.config}/modules.d/*.yml
  reload.enabled: false
  reload.period: 2s
 
output.logstash:
  hosts: ["log.domain.com:5044"]
 
  ssl.enabled: true
  ssl.certificate_authorities: ["C:/filebeat/certs/ca.pem", "C:/filebeat/certs/ca-issuing.pem"]
  ssl.certificate: "C:/filebeat/certs/site1.domain.ru.cer"
  ssl.key: "C:/filebeat/certs/site1.domain.ru.key"
 
#================================ Processors =====================================
 
processors:
  - add_host_metadata: ~
  - add_cloud_metadata: ~

logstash. Rönkgyűjtő

Ezt az összetevőt úgy tervezték, hogy fogadja a naplóbejegyzéseket a FileBeattől (vagy a RabbitMQ soron keresztül), elemezze és beilleszti a kötegeket a ClickHouse adatbázisba.

A ClickHouse-ba való beillesztéshez a Logstash-output-clickhouse bővítményt kell használni. A Logstash beépülő modul rendelkezik egy kérési újrapróbálkozási mechanizmussal, de rendszeres leállítás esetén jobb magát a szolgáltatást leállítani. Leállításkor az üzenetek felhalmozódnak a RabbitMQ sorban, így ha a leállás hosszú ideig tart, akkor jobb, ha leállítja a Filebeats-et a szervereken. Egy olyan sémában, ahol a RabbitMQ-t nem használják (a helyi hálózaton a Filebeat közvetlenül küld naplókat a Logstash-nak), a Filebeats meglehetősen elfogadhatóan és biztonságosan működik, így számukra a kimenet elérhetetlensége következmények nélkül múlik el.

Egy példa konfiguráció így néz ki:

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

csővezetékek.yml

# This file is where you define your pipelines. You can define multiple.
# For more information on multiple pipelines, see the documentation:
#   https://www.elastic.co/guide/en/logstash/current/multiple-pipelines.html
 
- pipeline.id: log_web__filebeat_clickhouse
  path.config: "/etc/logstash/log_web__filebeat_clickhouse.conf"

clickhouse. Rönktárolás

Az összes rendszer naplói egy táblázatban vannak tárolva (lásd a cikk elején). Célja a kérésekkel kapcsolatos információk tárolása: minden paraméter hasonló a különböző formátumokhoz, például az IIS-naplókhoz, az apache- és az nginx-naplókhoz. Az alkalmazási naplókhoz, amelyekben például hibák, információs üzenetek, figyelmeztetések vannak rögzítve, külön táblázatot biztosítunk a megfelelő szerkezettel (jelenleg tervezési szakaszban).

A táblázat megtervezésekor nagyon fontos eldönteni, hogy melyik elsődleges kulcs (mely alapján lesznek rendezve az adatok a tárolás során). Ettől függ az adattömörítés mértéke és a lekérdezési sebesség. Példánkban a kulcs az
ORDER BY (fld_app_name, fld_app_module, logdatetime)
Vagyis a rendszer nevével, a rendszerkomponens nevével és az esemény dátumával. Kezdetben az esemény dátuma volt az első. Miután áthelyezte az utolsó helyre, a lekérdezések körülbelül kétszer gyorsabban kezdtek működni. Az elsődleges kulcs megváltoztatásához újra létre kell hozni a táblát, és újra kell tölteni az adatokat, hogy a ClickHouse újrarendezze az adatokat a lemezen. Ez egy nehéz művelet, ezért érdemes sokat gondolkozni azon, hogy mi kerüljön bele a rendezési kulcsba.

Azt is meg kell jegyezni, hogy a LowCardinality adattípus viszonylag friss verziókban jelent meg. Használatakor a tömörített adatok mérete drasztikusan lecsökken azoknál a mezőknél, amelyeknek alacsony a számossága (kevés lehetőség).

Jelenleg a 19.6-os verzió használatban van, és azt tervezzük, hogy megpróbáljuk frissíteni a legújabb verzióra. Olyan csodálatos tulajdonságokkal rendelkeznek, mint például az Adaptive Granularity, a Skipping indexek és a DoubleDelta kodek.

Alapértelmezés szerint a telepítés során a naplózási szint nyomkövetésre van állítva. A naplókat elforgatják és archiválják, ugyanakkor akár egy gigabájtra bővülnek. Ha nincs rá szükség, akkor beállíthatja a figyelmeztetési szintet, ekkor a rönk mérete drasztikusan csökken. A naplózási beállítás a config.xml fájlban van beállítva:

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

Néhány hasznos parancs

Поскольку оригинальные пакеты установки собираются по 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. Az útválasztó naplózása a FileBeatből a RabbitMQ sorba

Ez az összetevő a FileBeatből érkező naplók RabbitMQ-sorba irányítására szolgál. Itt két pont van:

  1. Sajnos a FileBeat nem rendelkezik kimeneti beépülő modullal, amely közvetlenül írhatna a RabbitMQ-ba. És az ilyen funkcionalitást a githubon lévő probléma alapján nem tervezik implementálni. Van egy plugin a Kafkához, de valamiért nem tudjuk otthon használni.
  2. A DMZ-ben követelmények vonatkoznak a naplók gyűjtésére. Ezek alapján először a naplókat kell hozzáadni a sorhoz, majd a LogStash kívülről beolvassa a sor bejegyzéseit.

Ezért arra az esetre, ha a szerverek a DMZ-ben találhatók, egy ilyen kissé bonyolult sémát kell alkalmazni. Egy példa konfiguráció így néz ki:

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. üzenetsor

Ez az összetevő a naplóbejegyzések pufferelésére szolgál a DMZ-ben. A rögzítés egy csomó Filebeat → LogStash segítségével történik. Az olvasás a DMZ-n kívülről történik a LogStash segítségével. Ha a RabboitMQ-n keresztül működik, másodpercenként körülbelül 4 ezer üzenet kerül feldolgozásra.

Az üzenetek továbbítása a rendszernév szerint van konfigurálva, azaz a FileBeat konfigurációs adatai alapján. Minden üzenet egy sorba kerül. Ha valamilyen oknál fogva a sorbaállítási szolgáltatás leáll, akkor ez nem vezet az üzenetek elvesztéséhez: a FileBeats csatlakozási hibákat kap, és ideiglenesen felfüggeszti a küldést. A sorból olvasó LogStash pedig hálózati hibákat is kap, és várja a kapcsolat helyreállítását. Ebben az esetben az adatok természetesen már nem kerülnek be az adatbázisba.

A sorok létrehozásához és konfigurálásához a következő utasításokat kell használni:

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. Irányítópultok

Ez az összetevő a megfigyelési adatok megjelenítésére szolgál. Ebben az esetben telepítenie kell a ClickHouse adatforrást a Grafana 4.6+ bővítményhez. Kicsit módosítanunk kellett, hogy javítsuk az SQL-szűrők feldolgozásának hatékonyságát az irányítópulton.

Például változókat használunk, és ha ezek nincsenek beállítva a szűrőmezőben, akkor szeretnénk, ha nem generálna feltételt az űrlap WHERE részében ( uriStem = » AND uriStem != » ). Ebben az esetben a ClickHouse beolvassa az uriStem oszlopot. Általában különböző lehetőségeket próbáltunk ki, és végül kijavítottuk a beépülő modult (a $valueIfEmpty makrót), hogy üres érték esetén 1-et adjon vissza anélkül, hogy magát az oszlopot említené.

És most már használhatja ezt a lekérdezést a grafikonhoz

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

ami lefordítja ezt az SQL-t (megjegyzendő, hogy az üres uriStem mezők csak 1-re lettek konvertálva)

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

Következtetés

A ClickHouse adatbázis megjelenése mérföldkővé vált a piacon. Nehéz volt elképzelni, hogy teljesen ingyenesen egy pillanat alatt felvérteztünk egy hatékony és praktikus eszközt a big data kezeléséhez. Természetesen a növekvő igények miatt (például felosztás és replikáció több szerverre) a séma bonyolultabbá válik. De első benyomásra nagyon kellemes ezzel az adatbázissal dolgozni. Látható, hogy a termék "emberek számára" készült.

Az ElasticSearch-hez képest a naplók tárolásának és feldolgozásának költsége a becslések szerint öt-tízszeresére csökken. Vagyis ha a jelenlegi adatmennyiséghez több gépből álló klasztert kellene felállítanunk, akkor ClickHouse használatakor elég nekünk egy kis fogyasztású gép. Igen, természetesen az ElasticSearch is rendelkezik lemezen található adattömörítési mechanizmusokkal és egyéb funkciókkal, amelyek jelentősen csökkenthetik az erőforrás-felhasználást, de a ClickHouse-hoz képest ez drágább lesz.

Részünkről különösebb optimalizálás nélkül, alapbeállítások mellett az adatok betöltése és az adatbázisból való kiválasztás elképesztő sebességgel működik. Még nincs sok adatunk (kb. 200 millió rekord), de maga a szerver gyenge. Ezt az eszközt a jövőben más, nem a naplók tárolásával kapcsolatos célokra is használhatjuk. Például a végpontok közötti elemzéshez, a biztonság, a gépi tanulás területén.

A végén egy kicsit az előnyeiről és hátrányairól.

Hátrányok

  1. Rekordok betöltése nagy tételekben. Ez egyrészt egy szolgáltatás, de a rekordok puffereléséhez továbbra is további összetevőket kell használni. Ez a feladat nem mindig könnyű, de mégis megoldható. És szeretném leegyszerűsíteni a sémát.
  2. Egyes egzotikus funkciók vagy új funkciók gyakran megszakadnak az új verziókban. Ez aggodalomra ad okot, csökkentve az új verzióra való frissítés iránti vágyat. Például a Kafka táblázatmotor egy nagyon hasznos funkció, amely lehetővé teszi a Kafka események közvetlen olvasását anélkül, hogy fogyasztókat kellene alkalmazni. De a githubon megjelenő problémák számából ítélve továbbra is ügyelünk arra, hogy ne használjuk ezt a motort a gyártás során. Ha azonban nem tesz hirtelen gesztusokat oldalra, és használja a fő funkciót, akkor stabilan működik.

Érvek

  1. Nem lassít.
  2. Alacsony belépési küszöb.
  3. Nyílt forráskód.
  4. Ingyenes.
  5. Jól skálázható (szilánkolás/replikáció a dobozból)
  6. Szerepel a Hírközlési Minisztérium által ajánlott orosz szoftverek nyilvántartásában.
  7. A Yandex hivatalos támogatásának jelenléte.

Forrás: will.com

Hozzászólás