Alexei Lizunov, șeful departamentului centrului de competențe pentru canalele de servicii la distanță din cadrul direcției tehnologiilor informației MKB

Ca alternativă la stiva ELK (ElasticSearch, Logstash, Kibana), desfășurăm lucrări de cercetare privind utilizarea bazei de date ClickHouse ca soluție de stocare a datelor pentru loguri.
În acest articol dorim să vă împărtășim experiența noastră în utilizarea bazei de date ClickHouse și rezultatele preliminare obținute în urma implementării pilot. Este demn de menționat de la bun început că rezultatele au fost impresionante.

Mai departe, vom detalia cum este configurată sistemul nostru și din ce componente este format. Dar acum am dori să oferim câteva informații despre această bază de date în general și de ce merită atenția. Baza de date ClickHouse este o bază de date analitică de înaltă performanță, coloanar, dezvoltată de Yandex. Este utilizată în serviciile Yandex, fiind inițial principala soluție de stocare a datelor pentru Yandex.Metrica. Este un sistem open-source, gratuit. Din perspectiva dezvoltatorului, m-a interesat mereu cum este implementată, având în vedere dimensiunile fantastice ale datelor. Interfața utilizatorului a Metrica este, de asemenea, foarte flexibilă și funcționează rapid. La prima întâlnire cu această bază de date, impresia a fost: „Ei bine, în sfârșit! A fost concepută „pentru oameni”! De la procesul de instalare până la trimiterea interogărilor”,
Această bază de date are un prag de intrare foarte scăzut. Chiar și un dezvoltator de calificare medie poate instala această bază de date în câteva minute și începe să o utilizeze. Totul funcționează perfect. Chiar și persoanele care nu sunt familiarizate bine cu Linux pot gestiona rapid instalarea și efectua operațiuni de bază. Dacă anterior, la auzul termenilor Big Data, Hadoop, Google BigTable, HDFS, un dezvoltator obișnuit își imagina că este vorba despre terabytes, petabytes, iar configurațiile și dezvoltarea pentru aceste sisteme erau lăsate în seama unor super-eroi, odată cu apariția bazei de date ClickHouse am obținut un instrument simplu și clar, cu ajutorul căruia putem rezolva un set de probleme care înainte părea inaccesibil. Este suficient să ai un server destul de mediu și cinci minute pentru instalare. Adică am obținut o bază de date similară cu MySQL, dar adaptată pentru stocarea a miliarde de înregistrări! O super-arhivă cu limbaj SQL. Este ca și cum oamenii ar primi arme extraterestre.
Despre sistemul nostru de colectare a logurilor
Pentru colectarea informațiilor sunt utilizate fișierele de log IIS ale aplicațiilor web în format standard (de asemenea, ne ocupăm și cu parsing-ul logurilor aplicațiilor, dar scopul principal în etapa de testare pilot este colectarea logurilor IIS).
Nu am reușit să abandonăm complet stiva ELK din diverse motive și continuăm să folosim componentele LogStash și Filebeat, care s-au dovedit a fi fiabile și funcționează destul de consistent.
Schema generală de logare este prezentată în figura de mai jos:

Particularitatea înregistrării datelor în baza de date ClickHouse este inserarea rară (o dată pe secundă) a înregistrărilor în grupuri mari. Aceasta, se pare, este cea mai 'problematică' parte, cu care te confrunți la prima experiență de lucru cu baza de date ClickHouse: schema devine puțin mai complicată.
Aici a ajutat foarte mult pluginul pentru LogStash, care inserează direct datele în ClickHouse. Acest component este desfășurat pe același server cu baza de date în sine. De fapt, nu se recomandă să faci asta, dar din punct de vedere practic, pentru a nu genera servere separate, este acceptabil până când este desfășurat pe același server. Nu am observat nici defecțiuni, nici conflicte de resurse cu baza de date. În plus, este important de menționat că pluginul are un mecanism de retry în caz de erori. În cazul erorilor, pluginul scrie pe disc o grupare de date care nu au putut fi inserate (formatul fișierului este convenabil: după corectare, poți insera ușor grupul corectat folosind clickhouse-client).
Lista completă a software-ului utilizat în schemă este prezentată în tabel:
Lista software-ului utilizat
Denumire
Descriere
Link pentru distribuție
NGINX
Reverse-proxy pentru restricționarea accesului pe porturi și organizarea autentificării
În prezent, nu este folosit în schemă
FileBeat
Transmiterea fișierelor de log.
(distribuție pentru Windows 64bit).
LogStash
Colector de loguri.
Este utilizat pentru colectarea logurilor de la FileBeat, precum și pentru colectarea logurilor din coada RabbitMQ (pentru serverele care se află în DMZ).
Logstash-output-clickhouse
Plugin Logstash pentru transmiterea logurilor în baza de date ClickHouse în grupuri
/usr/share/logstash/bin/logstash-plugin install logstash-output-clickhouse
/usr/share/logstash/bin/logstash-plugin install logstash-filter-prune
/usr/share/logstash/bin/logstash-plugin install logstash-filter-multiline
ClickHouse
Depozitul de loguri
Notă. Începând cu august 2018, în repositoul Yandex au apărut "versiunile normale" rpm pentru RHEL, așa că poți încerca să le folosești. La momentul instalării, am folosit pachete construite de Altinity.
Grafana
Vizualizarea logurilor. Configurarea dashboard-urilor
Redhat & Centos (64 Bit) – cea mai recentă versiune
Sursa de date ClickHouse pentru Grafana 4.6+
Plugin pentru Grafana cu sursa de date ClickHouse
LogStash
Routerul de loguri de la FileBeat în coada RabbitMQ.
Observație. Din păcate, FileBeat nu are o ieșire directă în RabbitMQ, așa că este necesar un intermediar sub formă de Logstash.
RabbitMQ
Coada mesajelor. Acesta este un buffer pentru înregistrările de loguri în DMZ.
Erlang Runtime (Necesar pentru RabbitMQ)
Mediul de execuție Erlang. Este necesar pentru funcționarea RabbitMQ.
Configurarea serverului cu baza de date ClickHouse este prezentată în următorul tabel:
Denumire
Valoare
Notă
Configurație
HDD: 40GB
RAM: 8GB
Procesor: Core 2 2Ghz
Este necesar să se țină cont de sfaturile privind utilizarea bazei de date ClickHouse ()
Software de sistem general
OS: Red Hat Enterprise Linux Server (Maipo)
JRE (Java 8)
Așa cum se vede, acesta este un post de lucru obișnuit.
Structura tabelului pentru stocarea logurilor arată astfel:
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;Folosim valorile implicite pentru partiționare (pe luni) și granularitatea indexului. Toate câmpurile corespund practic înregistrărilor de log IIS pentru înregistrarea cererilor http. De asemenea, notăm câmpurile separate pentru stocarea etichetelor utm (acestea sunt analizate în timpul inserării în tabel din câmpul lanțului de interogare).
De asemenea, în tabel au fost adăugate câteva câmpuri sistemice pentru stocarea informațiilor despre sisteme, componente, servere. Descrierea acestor câmpuri se găsește mai jos în tabel. Într-un singur tabel stocăm logurile pentru mai multe sisteme.
Denumire
Descriere
Exemplu
fld_app_name
Numele aplicației/sistemului
Valorile acceptate:
- site1.domain.com Site extern 1
- site2.domain.com Site extern 2
- internal-site1.domain.local Site intern 1
site1.domain.com
fld_app_module
Modulul sistemului
Valorile acceptate:
- web — Website
- svc — Serviciul web al site-ului
- intgr — Serviciul web de integrare
- bo — Administrație (BackOffice)
web
fld_website_name
Numele site-ului în IIS
Pe un singur server pot fi desfășurate mai multe sisteme sau chiar mai multe instanțe ale unui modul de sistem.
web-main
fld_server_name
Numele serverului
web1.domain.com
fld_log_file_name
Calea către fișierul de log pe server
C:inetpublogsLogFiles
W3SVC1u_ex190711.log
Acest lucru permite construirea eficientă a graficelor în Grafana. De exemplu, vizualizarea cererilor din frontendul unui sistem specific. Este similar cu un contor de site în Yandex.Metrica.
Iată câteva statistici privind utilizarea Bazei de Date în ultimele două luni.
Numărul de înregistrări împărțit pe sisteme și componentele acestora
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.ro │ web │ 131441 │
│ site2.domain.ro │ web │ 1751081 │
│ site3.domain.ro │ web │ 106887543 │
│ site3.domain.ro │ svc │ 44908603 │
│ site3.domain.ro │ intgr │ 9813911 │
│ site4.domain.ro │ web │ 772095 │
│ site5.domain.ro │ web │ 17037221 │
│ site5.domain.ro │ intgr │ 838559 │
│ site5.domain.ro │ bo │ 7404 │
│ site6.domain.ro │ web │ 595877 │
│ site7.domain.ro │ 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.)Volumul de date pe disc
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.Gradul de compresie a datelor în coloane
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.Descrierea componentelor utilizate
FileBeat. Transmiterea fișierelor de log
Această componentă monitorizează modificările din fișierele de log de pe disc și trimite informațiile către LogStash. Se instalează pe toate serverele unde se scriu fișiere de log (de obicei, IIS). Funcționează în modul tail (adică transmite doar înregistrările adăugate în fișier). Totuși, se poate configura separat pentru a transmite fișiere întregi. Este convenabil atunci când trebuie să încărcați datele din lunile anterioare. Este suficient să puneți fișierul de log în folder și el va fi citit integral.
Când serviciul este oprit, datele nu mai sunt transmise mai departe în stocare.
Exemplul de configurare arată astfel:
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.ro"
fld_app_name: "site1.domain.ro"
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.ro"
fld_app_name: "site2.domain.ro"
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.ro.cer"
ssl.key: "C:/filebeat/certs/site1.domain.ro.key"
#================================ Processors =====================================
processors:
- add_host_metadata: ~
- add_cloud_metadata: ~LogStash. Colector de loguri
Acest component este destinat pentru a primi înregistrări de loguri de la FileBeat (sau prin intermediul cozii RabbitMQ), parsarea și inserția în loturi în baza de date ClickHouse.
Pentru inserția în ClickHouse se folosește pluginul Logstash-output-clickhouse. Pluginul Logstash are un mecanism de retry pentru cereri, dar la oprite normale, este mai bine să opriți totuși serviciul în sine. La oprire, mesajele se vor acumula în coada RabbitMQ, așa că, dacă oprirea durează mult timp, este mai bine să opriți Filebeat-urile de pe servere. În schema în care nu se folosește RabbitMQ (în rețeaua locală, Filebeat trimite direct logurile în Logstash), Filebeat-urile funcționează destul de acceptabil și sigur, așa că pentru ele indisponibilitatea output-ului trece fără consecințe.
Exemplul de configurare arată astfel:
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. Depozitar de jurnale
Jurnalele din toate sistemele sunt stocate într-o singură tabelă (vezi la începutul articolului). Aceasta este destinată stocării informațiilor despre solicitări: toate parametrii fiind similari pentru diferite formate, de exemplu jurnalele IIS, jurnalele Apache și Nginx. Pentru jurnalele aplicațiilor, în care sunt înregistrate, de exemplu, erori, mesaje informative, avertizări, va exista o tabelă separat, cu structura corespunzătoare (în prezent, în faza de proiectare).
Atunci când se proiectează tabelul, este foarte important să se stabilească cheia primară (pe baza căreia vor fi sortate datele la stocare). De aici depinde gradul de comprimare a datelor și viteza interogărilor. În exemplul nostru, cheia este
ORDER BY (fld_app_name, fld_app_module, logdatetime)
Adică, după numele sistemului, numele componentului sistemului și data evenimentului. Inițial, data evenimentului era pe primul loc. După mutarea acesteia pe ultimul loc, interogările au început să funcționeze de aproximativ două ori mai repede. Schimbarea cheii primare va necesita recrearea tabelului și reutilizarea datelor, astfel încât ClickHouse să re-sorteze datele pe disc. Aceasta este o operațiune grea, așa că este de dorit să se gândească cu mult înainte la ce ar trebui să intre în cheia de sortare.
De asemenea, este important de menționat că, în versiunile recente, a apărut tipul de date LowCardinality. Prin utilizarea acestuia, dimensiunea datelor comprimate pentru câmpurile cu cardinalitate scăzută (puține opțiuni) se reduce drastic.
În prezent, se folosește versiunea 19.6, iar noi plănuim să încercăm să facem upgrade la cea mai recentă versiune. Au apărut caracteristici minunate precum Granularitate adaptivă, Indici de sărituri și Codec DoubleDelta, de exemplu.
În mod implicit, la instalare, nivelul de logare este setat la trace în configurație. Jurnalele sunt rotite și arhivate, dar se extind până la un gigabyte. Dacă nu este necesar, se poate seta nivelul warning, iar dimensiunea jurnalului se reduce drastic. Configurarea logării se stabilește în fișierul config.xml:
<!-- Niveluri posibile: https://github.com/pocoproject/poco/blob/develop/Foundation/include/Poco/Logger.h#L105 -->
<level>warning</level>Unele comenzi utile
Deoarece pachetele originale de instalare sunt construite pe Debian, pentru alte versiuni de Linux trebuie să folosiți pachete construite de compania Altinity.
Puteți găsi instrucțiuni cu linkuri la depozitul lor pe acest link: https://www.altinity.com/blog/2017/12/18/logstash-with-clickhouse
sudo yum search clickhouse-server
sudo yum install clickhouse-server.noarch
1. verificarea stării
sudo systemctl status clickhouse-server
2. oprirea serverului
sudo systemctl stop clickhouse-server
3. pornirea serverului
sudo systemctl start clickhouse-server
Pornire pentru execuția interogărilor în modul multiline (executare după semnul ";")
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
Pluginul ClickHouse pentru Logstash, în caz de eroare într-o singură linie, salvează întreaga serie într-un fișier /tmp/log_web_failed.json
Puteți corecta manual acest fișier și încerca să-l încărcați manual în baza de date:
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
out din linia de comandă
quit;
## Configurarea TLS
https://www.altinity.com/blog/2019/3/5/clickhouse-networking-part-2
openssl s_client -connect log.domain.com:9440 < /dev/nullLogStash. Router de loguri de la FileBeat în coada RabbitMQ
Acest component este utilizat pentru a rutele loguri provenite de la FileBeat în coada RabbitMQ. Aici sunt două puncte:
- Din păcate, FileBeat nu dispune de un plugin de ieșire pentru a scrie direct în RabbitMQ. Și această funcționalitate, judecând după problemele de pe GitHub-ul lor, nu este planificată pentru implementare. Există un plugin pentru Kafka, dar din anumite motive nu putem să-l folosim.
- Există cerințe pentru colectarea logurilor în DMZ. În funcție de acestea, logurile trebuie să fie mai întâi stocate într-o coadă, iar apoi LogStash le citește din afară din acea coadă.
De aceea, pentru cazul amplasării serverelor în DMZ, trebuie să utilizăm o schemă ușor mai complicată. Un exemplu de configurație arată astfel:
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. Coada de mesaje
Acest component este folosit pentru bufferizarea înregistrărilor de loguri în DMZ. Înregistrarea se face prin intermediul conexiunii Filebeat → LogStash. Citirea se efectuează din afara DMZ prin LogStash. În exploatarea prin RabbitMQ, se procesează aproximativ 4.000 de mesaje pe secundă.
Routarea mesajelor este configurată pe baza numelui sistemului, adică pe baza datelor de configurare FileBeat. Toate mesajele ajung într-o singură coadă. Dacă din orice motiv serviciul de cozi este oprit, acest lucru nu va duce la pierderea mesajelor: FileBeat-urile vor primi erori de conexiune și vor suspenda temporar trimiterea. Iar LogStash, care citește din coadă, va primi de asemenea erori de rețea și va aștepta restabilirea conexiunii. Datele, în acest interval, nu vor mai fi scrise în baza de date.
Următoarele instrucțiuni sunt utilizate pentru crearea și configurarea cozilor:
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. Panouri de control
Acest component este utilizat pentru vizualizarea datelor de monitorizare. În acest context, este necesar să instalați pluginul ClickHouse datasource for Grafana 4.6+. A trebuit să-l ajustăm puțin pentru a îmbunătăți eficiența procesării filtrelor SQL pe tabloul de bord.
De exemplu, folosim variabile și, dacă acestea nu sunt definite în câmpul filtrului, ne-ar plăcea să nu genereze o condiție în WHERE de tipul (uriStem = » AND uriStem != »). În acest caz, ClickHouse va citi coloana uriStem. În general, am încercat diferite variante și, în cele din urmă, am modificat pluginul (macro-ul $valueIfEmpty) pentru a returna 1 în cazul unei valori goale, fără a menționa efectiv coloana.
Și acum putem utiliza o astfel de interogare pentru grafic
$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')care se transformă într-un SQL de acest fel (observați că câmpurile goale uriStem au fost transformate în pur și simplu 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.ro') 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 ASCConcluzie
Apariția bazei de date ClickHouse a fost un eveniment semnificativ pe piață. Era greu de imaginat că, complet gratuit, ne-am echipat instantaneu cu un instrument puternic și practic pentru lucrul cu date mari. În mod clar, odată cu creșterea cerințelor (de exemplu, sharding și replicare pe mai multe servere), schema se va complica. Dar, din primele impresii, lucrul cu această bază de date este foarte plăcut. Se vede că produsul este făcut „pentru oameni”.
Comparativ cu ElasticSearch, costurile de stocare și procesare a jurnalelor, conform estimărilor preliminare, se reduc de la cinci la zece ori. Cu alte cuvinte, dacă pentru volumul actual de date ar fi fost necesar să configurăm un cluster format din mai multe mașini, atunci utilizând ClickHouse ne ajunge o singură mașină slabă. Da, desigur, și în ElasticSearch există mecanisme de comprimare a datelor pe disc și alte caracteristici care permit reducerea semnificativă a consumului de resurse, dar comparativ cu ClickHouse, acest lucru va necesita cheltuieli mai mari.
Fără optimizări speciale din partea noastră, cu setările implicite, încărcarea datelor și interogările din baza de date funcționează cu o viteză impresionantă. Datele deocamdată sunt puține (aproximativ 200 de milioane de înregistrări), dar serverul este slab. Acest instrument îl putem folosi în viitor și pentru alte scopuri, nelegate de stocarea jurnalelor. De exemplu, pentru analize complete, în domeniul securității, învățare automată.
La final, câteva cuvinte despre dezavantaje și avantaje.
Dezavantaje
- Încărcarea înregistrărilor în loturi mari. Aceasta, pe de o parte, este o caracteristică, dar totuși trebuie să folosim componente suplimentare pentru bufferizarea înregistrărilor. Această sarcină nu este întotdeauna simplă, dar totuși soluționabilă. Și ne-ar plăcea să simplificăm schema.
- Unele funcții exotice sau caracteristici noi se strică adesea în versiunile noi. Acest lucru generează îngrijorări, diminuând dorința de a face upgrade la noua versiune. De exemplu, motorul de tabele Kafka – o caracteristică foarte utilă, care permite citirea directă a evenimentelor din Kafka, fără a implementa consumatori. Însă, având în vedere numărul de probleme pe GitHub, ne ferim deocamdată să folosim acest motor în producție. Totuși, dacă nu facem mișcări bruste și folosim funcționalitatea principală, atunci acesta funcționează stabil.
Advantages
- Nu se blochează.
- Prag de intrare scăzut.
- Open-source.
- Gratuit.
- Se scalează bine (sharding/replicare „din cutie”).
- Face parte din registrul software-ului rus, recomandat de Ministerul Comunicațiilor.
- Există suport oficial de la Yandex.
Sursa: habr.com
