ClickHouse Database for Humans, of Alien Technologies

Aleksey Lizunov, haad fan it Competence Centre for Remote Service Channels fan 'e Direktoraat foar ynformaasjetechnologyen fan' e MKB

ClickHouse Database for Humans, of Alien Technologies

As alternatyf foar de ELK-stapel (ElasticSearch, Logstash, Kibana), dogge wy ûndersyk nei it brûken fan de ClickHouse-database as gegevenswinkel foar logs.

Yn dit artikel wolle wy prate oer ús ûnderfining mei it brûken fan de ClickHouse-database en de foarriedige resultaten fan 'e pilotoperaasje. Dêrby moat opmurken wurde dat de resultaten wiene yndrukwekkend.


ClickHouse Database for Humans, of Alien Technologies

Folgjende sille wy yn mear detail beskriuwe hoe't ús systeem is konfigureare, en út hokker komponinten it bestiet. Mar no soe ik graach prate in bytsje oer dizze databank as gehiel, en wêrom is it wurdich omtinken te jaan. De ClickHouse-database is in hege prestaasjes analytyske kolomdatabase fan Yandex. It wurdt brûkt yn Yandex tsjinsten, yn earste ynstânsje is it de wichtichste gegevens opslach foar Yandex.Metrica. Iepenboarne systeem, fergees. Fanút it eachpunt fan in ûntwikkelder haw ik my altyd ôffrege hoe't se it ymplementearre hawwe, om't d'r fantastysk grutte gegevens binne. En de brûkersynterface fan Metrica sels is heul fleksibel en rap. By de earste kennismaking mei dizze databank is de yndruk: “Nou, einliks! Makke foar de minsken! Begjin by it ynstallaasjeproses en einigje mei it ferstjoeren fan fersiken.

Dizze databank hat in heul lege yngongsdrompel. Sels in trochsneed betûfte ûntwikkelder kin dizze databank yn in pear minuten ynstallearje en begjinne te brûken. Alles wurket dúdlik. Sels minsken dy't nij binne foar Linux kinne de ynstallaasje fluch omgean en de ienfâldichste operaasjes dwaan. As earder, mei de wurden Big Data, Hadoop, Google BigTable, HDFS, in gewoane ûntwikkelder ideeën hie dat it om guon terabytes, petabytes gie, dat guon superminsken belutsen binne by ynstellings en ûntwikkeling foar dizze systemen, dan mei de komst fan it ClickHouse databank, wy krigen in ienfâldich, begryplik ark wêrmei jo kinne oplosse in earder ûnberikber oanbod fan taken. It duorret mar ien frij gemiddelde masine en fiif minuten om te ynstallearjen. Dat is, wy krigen sa'n databank as bygelyks MySql, mar allinich foar it bewarjen fan miljarden records! In bepaalde super-archiver mei de SQL-taal. It is as minsken krigen de wapens fan aliens.

Oer ús logsysteem

Om ynformaasje te sammeljen wurde IIS-logbestannen fan standertformaat webapplikaasjes brûkt (wy binne op it stuit ek oan it parsearjen fan applikaasje-logs, mar it haaddoel op it pilotstadium is om IIS-logs te sammeljen).

Om ferskate redenen koene wy ​​de ELK-stapel net folslein ferlitte, en wy bliuwend de LogStash- en Filebeat-komponinten brûke, dy't harsels goed bewiisd hawwe en frij betrouber en foarsisber wurkje.

It algemiene loggingskema wurdt werjûn yn 'e ûndersteande figuer:

ClickHouse Database for Humans, of Alien Technologies

In skaaimerk fan it skriuwen fan gegevens nei de ClickHouse-database is selden (ien kear per sekonde) ynfoegje fan records yn grutte batches. Dit is blykber it meast "problematyske" diel dat jo tsjinkomme as jo foar it earst ûnderfine mei wurkjen mei de ClickHouse-database: it skema wurdt in bytsje yngewikkelder.
De plugin foar LogStash, dy't direkt gegevens yn ClickHouse ynfoeget, holp hjir in protte. Dizze komponint wurdt ynset op deselde tsjinner as de databank sels. Dat, yn 't algemien, is it net oan te rieden om it te dwaan, mar út in praktysk eachpunt, om gjin aparte servers te produsearjen wylst it op deselde server wurdt ynset. Wy hawwe gjin mislearrings of boarnekonflikten mei de databank waarnommen. Dêrby moat opmurken wurde dat de plugin hat in opnij meganisme yn gefal fan flaters. En yn gefal fan flaters skriuwt de plugin op skiif in batch fan gegevens dy't net koe wurde ynfoege (it bestânsformaat is handich: nei it bewurkjen kinne jo de korrizjearre batch maklik ynfoegje mei clickhouse-client).

In folsleine list fan software brûkt yn it skema wurdt presintearre yn 'e tabel:

List fan brûkte software

Titel

beskriuwing

Ferdieling keppeling

NGINX

Reverse-proxy om tagong te beheinen troch havens en autorisaasje te organisearjen

Op it stuit net brûkt yn it skema

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

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

FileBeat

Oerdracht fan triem logs.

https://www.elastic.co/downloads/beats/filebeat (distribúsje kit foar Windows 64bit).

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

logstash

Log samler.

Wurdt brûkt om logs te sammeljen fan FileBeat, en ek om logs te sammeljen fan 'e RabbitMQ-wachtrige (foar servers dy't yn' e DMZ binne.)

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

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

Logstash-útfier-klikhûs

Loagstash-plugin foar it oerbringen fan logs nei de ClickHouse-database yn batches

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

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

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

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

klikhûs

Log opslach 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

Noat. Fanôf augustus 2018 ferskynden "normale" rpm-builds foar RHEL yn it Yandex-repository, dus jo kinne besykje se te brûken. Op it momint fan ynstallaasje brûkten wy pakketten boud troch Altinity.

grafana

Logfisualisaasje. Dashboards ynstelle

https://grafana.com/

https://grafana.com/grafana/download

Redhat & Centos (64 Bit) - lêste ferzje

ClickHouse-gegevensboarne foar Grafana 4.6+

Plugin foar Grafana mei ClickHouse gegevensboarne

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

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

logstash

Log router fan FileBeat nei RabbitMQ-wachtrige.

Noat. Spitigernôch hat FileBeat gjin útfier direkt nei RabbitMQ, dus in tuskenlizzende keppeling yn 'e foarm fan Logstash is ferplicht

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

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

Konyn MQ

berjocht wachtrige. Dit is de logbuffer yn 'e 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 (fereaske foar RabbitMQ)

Erlang runtime. Fereaske foar RabbitMQ om te wurkjen

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

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

De serverkonfiguraasje mei de ClickHouse-database wurdt presintearre yn 'e folgjende tabel:

Titel

wearde

remark

Konfiguraasje

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

It is needsaaklik om omtinken te jaan oan de tips foar it operearjen fan de ClickHouse-database (https://clickhouse.yandex/docs/ru/operations/tips/)

Algemiene systeem software

OS: Red Hat Enterprise Linux Server (Maipo)

JRE (Java 8)

 

Sa't jo sjen kinne, is dit in gewoan wurkstasjon.

De struktuer fan 'e tabel foar it opslaan fan logs is as folget:

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;

Wy brûke standert partitionearring (per moanne) en yndeksgranulariteit. Alle fjilden oerienkomme praktysk mei IIS-log-yngongen foar it loggen fan http-oanfragen. Apart merken wy op dat d'r aparte fjilden binne foar it bewarjen fan utm-tags (se wurde parseard op it poadium fan ynfoegje yn 'e tabel út it query stringfjild).

Ek binne ferskate systeemfjilden oan 'e tabel tafoege om ynformaasje oer systemen, komponinten, servers op te slaan. Sjoch de tabel hjirûnder foar in beskriuwing fan dizze fjilden. Yn ien tabel bewarje wy logs foar ferskate systemen.

Titel

beskriuwing

Foarbyld:

fld_app_name

Applikaasje / systeem namme
Jildige wearden:

  • site1.domain.com Eksterne side 1
  • site2.domain.com Eksterne side 2
  • internal-site1.domain.local Ynterne side 1

site1.domain.com

fld_app_module

Systeem module
Jildige wearden:

  • web - Webside
  • svc - Webside tsjinst
  • intgr - Yntegraasje Web Service
  • bo - Admin (BackOffice)

reach

fld_website_name

Site namme yn IIS

Ferskate systemen kinne wurde ynset op ien tsjinner, of sels ferskate eksimplaren fan ien systeem module

web haad

fld_server_name

Server Namme

web1.domain.com

fld_log_file_name

Paad nei it logbestân op de tsjinner

C:inetpublogsLogFiles
W3SVC1u_ex190711.log

Hjirmei kinne jo effisjint grafiken bouwe yn Grafana. Besjoch bygelyks fersiken fan 'e frontend fan in bepaald systeem. Dit is fergelykber mei de sideteller yn Yandex.Metrica.

Hjir binne wat statistiken oer it gebrûk fan 'e databank foar twa moannen.

Oantal records ferdield troch systemen en har komponinten

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 hoemannichte gegevens op 'e skiif

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.

Graad fan gegevenskompresje yn 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.

Beskriuwing fan brûkte komponinten

FileBeat. Oerdracht fan triem logs

Dizze komponint folget feroaringen oan logbestannen op skiif en jout de ynformaasje troch oan LogStash. Ynstallearre op alle tsjinners dêr't log triemmen wurde skreaun (meastentiids IIS). Wurket yn sturtmodus (d.w.s. draacht allinich de tafoege records oer nei it bestân). Mar apart kin it ynsteld wurde om folsleine bestannen oer te dragen. Dit is handich as jo gegevens fan eardere moannen moatte downloade. Set it lochbestân gewoan yn in map en it sil it yn syn gehiel lêze.

As de tsjinst stoppe wurdt, wurde de gegevens net mear nei de opslach oerbrocht.

In foarbyldkonfiguraasje sjocht der sa út:

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 Samler

Dizze komponint is ûntworpen om log-yngongen te ûntfangen fan FileBeat (of fia de RabbitMQ-wachtrige), parsearjen en ynfoegje fan batches yn 'e ClickHouse-database.

Foar ynfoegje yn ClickHouse wurdt de Logstash-output-clickhouse-plugin brûkt. De Logstash-plugin hat in meganisme foar opnij besykjen fan fersyk, mar mei in reguliere shutdown is it better om de tsjinst sels te stopjen. Wannear't stoppe wurdt, wurde berjochten sammele yn 'e RabbitMQ-wachtrige, dus as de stop is foar in lange tiid, dan is it better om Filebeats op' e servers te stopjen. Yn in skema dêr't RabbitMQ net wurdt brûkt (op it lokale netwurk stjoert Filebeat direkt logs nei Logstash), wurkje Filebeats frij akseptabel en feilich, dus foar har giet de net-beskikberens fan útfier sûnder gefolgen troch.

In foarbyldkonfiguraasje sjocht der sa út:

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"

klikhûs. Log opslach

Logs foar alle systemen wurde opslein yn ien tabel (sjoch oan it begjin fan it artikel). It is bedoeld om ynformaasje oer oanfragen op te slaan: alle parameters binne ferlykber foar ferskate formaten, lykas IIS-logs, apache en nginx-logs. Foar applikaasje logs, wêryn bygelyks flaters, ynformaasjeberjochten, warskôgings wurde opnomd, sil in aparte tabel wurde foarsjoen mei de passende struktuer (op it stuit yn it ûntwerpstadium).

By it ûntwerpen fan in tabel is it heul wichtich om te besluten oer de primêre kaai (wêrmei de gegevens sille wurde sorteare tidens opslach). De graad fan gegevenskompresje en query-snelheid hinget hjirfan ôf. Yn ús foarbyld is de kaai
ORDER BY (fld_app_name, fld_app_module, logdatetime)
Dat is, troch de namme fan it systeem, de namme fan it systeemkomponint en de datum fan it evenemint. Yn it earstoan kaam de datum fan it evenemint earst. Nei it ferpleatsen nei it lêste plak, begûnen fragen sawat twa kear sa fluch te wurkjen. It feroarjen fan de primêre kaai sil de tabel opnij oanmeitsje en de gegevens opnij laden, sadat ClickHouse de gegevens op skiif opnij sortearret. Dit is in swiere operaasje, dus it is in goed idee om in protte nei te tinken oer wat yn 'e sortearringskaai opnommen wurde moat.

It moat ek opmurken wurde dat it gegevenstype LowCardinality relatyf yn resinte ferzjes ferskynde. By it brûken wurdt de grutte fan komprimearre gegevens drastysk fermindere foar dy fjilden dy't lege kardinaliteit hawwe (in pear opsjes).

Ferzje 19.6 is op it stuit yn gebrûk en wy binne fan plan om te besykjen bywurkjen nei de lêste ferzje. Se hawwe sokke prachtige funksjes lykas Adaptive Granularity, Skipping yndeksen en de DoubleDelta codec, bygelyks.

Standert, tidens de ynstallaasje, wurdt it lognivo ynsteld om te trace. De logs wurde rotearre en argivearre, mar tagelyk wreidzje se út oant in gigabyte. As der gjin need is, kinne jo it warskôgingsnivo ynstelle, dan wurdt de grutte fan it log drastysk fermindere. De logging ynstelling is ynsteld yn de config.xml triem:

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

Guon nuttige kommando'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. Log router fan FileBeat nei RabbitMQ-wachtrige

Dizze komponint wurdt brûkt om logs dy't komme fan FileBeat nei de RabbitMQ-wachtrige te routeren. Hjir binne twa punten:

  1. Spitigernôch hat FileBeat gjin útfierplugin om direkt nei RabbitMQ te skriuwen. En sokke funksjonaliteit, beoardielje troch it probleem op har github, is net pland foar ymplemintaasje. D'r is in plugin foar Kafka, mar om ien of oare reden kinne wy ​​it net thús brûke.
  2. D'r binne easken foar it sammeljen fan logs yn 'e DMZ. Op grûn dêrfan moatte de logs earst tafoege wurde oan 'e wachtrige en dan lêst LogStash de yngongen út' e wachtrige fan bûten.

Dêrom is it foar it gefal wêr't servers yn 'e DMZ lizze dat men sa'n wat komplisearre skema moat brûke. In foarbyldkonfiguraasje sjocht der sa út:

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. berjocht wachtrige

Dizze komponint wurdt brûkt om log-yngongen yn 'e DMZ te bufferen. Opname wurdt dien fia in boskje Filebeat → LogStash. Lêzen wurdt dien fan bûten de DMZ fia LogStash. By it operearjen fia RabboitMQ wurde sawat 4 tûzen berjochten per sekonde ferwurke.

Berjochtrouting is konfigureare troch systeemnamme, dus basearre op FileBeat-konfiguraasjegegevens. Alle berjochten geane nei ien wachtrige. As om ien of oare reden de wachtrige tsjinst wurdt stoppe, dan sil dit net liede ta it ferlies fan berjochten: FileBeats sil ferbiningsflaters ûntfange en it ferstjoeren tydlik ophâlde. En LogStash dy't lêst fan 'e wachtrige sil ek netwurkflaters ûntfange en wachtsje op' e ferbining weromsette. Yn dit gefal wurde de gegevens fansels net mear nei de databank skreaun.

De folgjende ynstruksjes wurde brûkt om wachtrijen te meitsjen en te konfigurearjen:

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

Dizze komponint wurdt brûkt om tafersjochgegevens te visualisearjen. Yn dit gefal moatte jo de ClickHouse-gegevensboarne foar Grafana 4.6+ plugin ynstallearje. Wy moasten it in bytsje oanpasse om de effisjinsje fan it ferwurkjen fan SQL-filters op it dashboard te ferbetterjen.

Wy brûke bygelyks fariabelen, en as se net yn it filterfjild ynsteld binne, dan wolle wy graach dat it gjin betingst genereart yn 'e WHERE fan it formulier ( uriStem = » EN uriStem != » ). Yn dit gefal sil ClickHouse de kolom uriStem lêze. Yn 't algemien hawwe wy ferskate opsjes besocht en úteinlik de plugin korrizjearre (de makro $valueIfEmpty) sadat it yn it gefal fan in lege wearde 1 weromkomt, sûnder de kolom sels te neamen.

En no kinne jo dizze query brûke foar de grafyk

$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 oerset nei dizze SQL (notysje dat de lege uriStem-fjilden binne omboud ta mar 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

konklúzje

It uterlik fan 'e ClickHouse-database is in oriïntaasjepunt wurden op' e merke. It wie dreech foar te stellen dat wy, folslein fergees, yn in momint bewapene wiene mei in krêftich en praktysk ark foar it wurkjen mei grutte data. Fansels, mei tanimmende behoeften (bygelyks sharding en replikaasje nei meardere servers), sil it skema yngewikkelder wurde. Mar op earste yndrukken is it wurkjen mei dizze databank heul noflik. It kin sjoen wurde dat it produkt is makke "foar minsken."

Yn ferliking mei ElasticSearch wurde de kosten foar it opslaan en ferwurkjen fan logs rûsd om fiif oant tsien kear te ferminderjen. Mei oare wurden, as wy foar de aktuele hoemannichte gegevens in kluster fan ferskate masines moatte ynstelle, dan is by it brûken fan ClickHouse ien lege macht masine genôch foar ús. Ja, fansels, ElasticSearch hat ek gegevenskompresjemeganismen op skiif en oare funksjes dy't boarneferbrûk signifikant kinne ferminderje, mar yn ferliking mei ClickHouse sil dit djoerder wêze.

Sûnder spesjale optimalisaasjes fan ús kant, op standertynstellingen, it laden fan gegevens en selektearjen út 'e database wurket op in geweldige snelheid. Wy hawwe noch net folle gegevens (sawat 200 miljoen records), mar de tsjinner sels is swak. Wy kinne dit ark yn 'e takomst brûke foar oare doelen dy't net relatearre binne oan it opslaan fan logs. Bygelyks foar end-to-end analytics, op it mêd fan feiligens, masine learen.

Oan 'e ein, in bytsje oer de foar- en neidielen.

Минусы

  1. It laden fan records yn grutte batches. Oan 'e iene kant is dit in funksje, mar jo moatte noch ekstra komponinten brûke foar buffering fan records. Dizze taak is net altyd maklik, mar dochs oplosber. En ik soe graach ferienfâldigje it skema.
  2. Guon eksoatyske funksjonaliteit as nije funksjes brekke faak yn nije ferzjes. Dit soarget foar soarch, en ferminderet de winsk om te upgrade nei in nije ferzje. Bygelyks, de Kafka-tafelmotor is in heul nuttige funksje wêrmei jo direkt eveneminten fan Kafka kinne lêze, sûnder konsuminten te ymplementearjen. Mar te beoardieljen troch it oantal Issues op 'e github, binne wy ​​​​noch foarsichtich om dizze motor net te brûken yn produksje. As jo ​​​​lykwols gjin hommelse gebaren oan 'e kant meitsje en de haadfunksjonaliteit brûke, dan wurket it stabyl.

Плюсы

  1. Fertraget net.
  2. Lege yngongsdrompel.
  3. Iepen Boarne.
  4. Frij.
  5. Skale goed (sharding / replikaasje út 'e doaze)
  6. Opnaam yn it register fan Russyske software oanrikkemandearre troch it Ministearje fan Kommunikaasje.
  7. De oanwêzigens fan offisjele stipe fan Yandex.

Boarne: www.habr.com

Add a comment