Aleksej Lizunov, voditelj odjela za kompetencije udaljenih kanala usluge u Direkciji informacijskih tehnologija MKB

Kao alternativu ELK стеку (ElasticSearch, Logstash, Kibana) provodimo istraživačke radove na korištenju ClickHouse DB-a kao skladišta podataka za logove.
U ovom članku bismo željeli podijeliti naše iskustvo korištenja ClickHouse DB-a i preliminarne rezultate nakon pilotne eksploatacije. Treba odmah napomenuti da su rezultati bili impresivni.

Dalje ćemo detaljnije opisati kako je naš sustav podešen i od kojih se komponenti sastoji. No najprije bismo voljeli malo pričati o ovoj bazi podataka u cjelini i zašto vrijedi obratiti pažnju na nju. ClickHouse DB je visoko performantna analitička kolumnarna baza podataka iz Yandexa. Koristi se u Yandexovim servisima, a izvorno je to glavno skladište podataka za Yandex.Metriku. Sustav je open-source, besplatan. Sa stanovišta programera, oduvijek me zanimalo kako su to realizirali, jer su tamo fantastički veliki podaci. A sam korisnički sučelje Metrike vrlo je fleksibilno i brzo radi. Prilikom prvog upoznavanja s ovom bazom podataka, dojam je: 'Oh, napokon! Napravljeno je 'za ljude!' Počevši od procesa instalacije pa do slanja upita.
Ova baza podataka ima vrlo nisku barijeru ulaska. Čak i programer srednje kvalifikacije može je instalirati za nekoliko minuta i početi je koristiti. Sve radi besprijekorno. Čak i ljudi koji slabo poznaju Linux mogu se brzo nositi s instalacijom i izvršavati jednostavne operacije. Ako su prije, pri riječi Big Data, Hadoop, Google BigTable, HDFS, uobičajeni programeri imali dojam da je tu riječ o terabajtima, petabajtima, i da se konfiguracijom i razvojem za te sustave bave nekakvi nadljudi, s pojavljivanjem ClickHouse DB-a dobili smo jednostavan, razumljiv alat kojim možemo rješavati do tada nedostižan krug zadataka. Dovoljna je samo jedna sasvim prosječna mašina i pet minuta za instalaciju. Tako smo dobili bazu podataka kao što je MySql, ali samo za pohranu milijardi zapisa! Neki super arhivator s SQL jezikom. Kao da su ljudima predali oružje vanzemaljaca.
O našem sustavu prikupljanja logova
Za prikupljanje informacija koriste se log datoteke IIS web aplikacija u standardnom formatu (trenutno se bavimo i parsiranjem logova aplikacija, ali je naš glavni cilj u fazi pilotne eksploatacije prikupljanje IIS logova).
Nismo mogli potpuno napustiti ELK stog iz raznih razloga i nastavljamo koristiti komponente LogStash i Filebeat, koje su se dobro pokazale i rade pouzdano i predvidivo.
Opća shema logiranja prikazana je u nastavku:

Karakteristika unosa podataka u ClickHouse bazu podataka je rijetka (jednom u sekundi) masovna umetanja zapisa. Očigledno, ovo je najproblematičniji dio s kojim se suočavate pri prvom radu s ClickHouse bazom podataka: shema je malo kompliciranija.
Ovdje je značajno pomogao LogStash plugin koji direktno umetne podatke u ClickHouse. Ova komponenta se postavlja na istom serveru kao i baza podataka. Generalno gledano, to se ne preporučuje, ali s praktične točke gledišta, kako ne bi stvorili dodatne servere, dok je postavljen na istom serveru. Nismo primijetili nikakve greške niti sukobe resursa s bazom podataka. Također, potrebno je napomenuti da plugin ima mehanizam ponovne prenositve u slučaju grešaka. U slučaju grešaka, plugin zapisuje na disk paket podataka koji nije uspio umetnuti (format datoteke je zgodan: nakon ispravke, lako je umetnuti ispravljeni paket pomoću clickhouse-client).
Puni popis softvera koji se koristi u shemi prikazan je u tablici:
Popis korištenog softvera
Naziv
Opis
Link na distribuciju
NGINX
Reverse-proxy za ograničavanje pristupa po portovima i organizaciju autorizacije
Trenutno se ne koristi u shemi
FileBeat
Prijenos datoteka s logovima.
(distribucija za Windows 64bit).
LogStash
Sakupljač logova.
Koristi se za prikupljanje logova od FileBeat-a, kao i za prikupljanje logova iz RabbitMQ reda (za servere koji se nalaze u DMZ-u).
Logstash-output-clickhouse
Logstash plugin za prijenos logova u ClickHouse bazu podataka u paketima
/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
Skladište logova
Napomena. Od kolovoza 2018. u Yandex repozitoriju pojavile su se "normalne" rpm build verzije za RHEL, pa ih možete probati koristiti. U vrijeme instalacije koristili smo pakete koje je izradio Altinity.
Grafana
Vizualizacija logova. Postavljanje dashboarda
Redhat & Centos (64 Bit) – posljednja verzija
ClickHouse izvor podataka za Grafanu 4.6+
Plugin za Grafanu s izvorom podataka ClickHouse
LogStash
Router logova od FileBeata u RedQueue RabbitMQ.
Napomena. Nažalost, FileBeat nema direktni izlaz u RabbitMQ, stoga je potrebno posredničko rješenje u obliku Logstasha.
RabbitMQ
Red poruka. Ovo je međuspremnik zapisa logova u DMZ.
Erlang Runtime (neophodan za RabbitMQ).
Okruženje za izvršavanje Erlang. Potrebno za rad RabbitMQ.
Konfiguracija poslužitelja s ClickHouse bazom podataka predstavljena je u sljedećoj tabeli:
Naziv
Vrijednost
Napomena
Konfiguracija
HDD: 40GB
RAM: 8GB
Procesor: Core 2 2Ghz
Važno je obratiti pažnju na savjete za korištenje ClickHouse baze podataka ()
Opći softver sustava.
OS: Red Hat Enterprise Linux Server (Maipo).
JRE (Java 8).
Kao što se može vidjeti, ovo je obična radna stanica.
Struktura tabele za pohranu logova izgleda ovako:
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;Koristimo zadane vrijednosti za particioniranje (po mjesecima) i granularity indeksa. Sva polja praktički odgovaraju zapisima loga IIS za evidentiranje http zahtjeva. Dodatno napominjemo, posebna polja za pohranu utm oznaka (one se parsiraju u trenutku umetanja u tabelu iz polja upita).
Također su u tabelu dodana neka sistemska polja za pohranu informacija o sistemima, komponentama, poslužiteljima. Opis tih polja može se vidjeti u tabeli ispod. U jednoj tabeli pohranjujemo logove za nekoliko sistema.
Naziv
Opis
Primjer
fld_app_name
Naziv aplikacije/sistema.
Dozvoljene vrijednosti:
- site1.domain.com Vanjski sajt 1.
- site2.domain.com Vanjski sajt 2.
- internal-site1.domain.local Unutrašnji sajt 1.
site1.domain.com
fld_app_module
Modul sistema.
Dozvoljene vrijednosti:
- web — Veb-sajt.
- svc — Veb-servis sajt.
- intgr — Veb-servis integracije.
- bo — Administrativna platforma (BackOffice).
web
fld_website_name
Naziv sajta u IIS.
Na jednom poslužitelju može biti raspoređeno nekoliko sistema, ili čak nekoliko instanci jednog modula sistema.
web-main
fld_server_name
Ime poslužitelja
web1.domain.com
fld_log_file_name
Putanja do datoteke loga na poslužitelju.
C:inetpublogsLogFiles
W3SVC1u_ex190711.log
To omogućuje učinkovito izradu grafikona u Grafani. Na primjer, pregled zahtjeva s frontenda određene sustave. To je slično mjeraču posjeta u Yandex.Metrica.
Evo neke statistike o korištenju baze podataka tijekom dva mjeseca.
Broj zapisa prema sustavima i njihovim komponentama
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.hr │ web │ 131441 │
│ site2.domain.hr │ web │ 1751081 │
│ site3.domain.hr │ web │ 106887543 │
│ site3.domain.hr │ svc │ 44908603 │
│ site3.domain.hr │ intgr │ 9813911 │
│ site4.domain.hr │ web │ 772095 │
│ site5.domain.hr │ web │ 17037221 │
│ site5.domain.hr │ intgr │ 838559 │
│ site5.domain.hr │ bo │ 7404 │
│ site6.domain.hr │ web │ 595877 │
│ site7.domain.hr │ 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.)Volumen podataka na disku
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.Stupanj kompresije podataka u stupcima
ODABERI
naziv,
formatReadableSize(data_uncompressed_bytes) AS nekomprimirano,
formatReadableSize(data_compressed_bytes) AS komprimirano,
data_uncompressed_bytes / data_compressed_bytes AS omjer_kompresije
IZ sustav.kolonice
GDJE tablica = 'log_web'
┌─naziv───────────────────┬─nekomprimirano─┬─komprimirano─┬─────omjer_kompresije─┐
│ logdatum │ 401.53 MiB │ 1.80 MiB │ 223.16665968777315 │
│ logvrijeme │ 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 │
│ metoda │ 201.53 MiB │ 43.64 MiB │ 4.617721053304486 │
│ uriStablo │ 5.13 GiB │ 832.51 MiB │ 6.311522291936919 │
│ uriUpit │ 2.58 GiB │ 501.06 MiB │ 5.269731450124478 │
│ port │ 803.06 MiB │ 3.98 MiB │ 201.91673864241824 │
│ korisničkoIme │ 318.08 MiB │ 26.93 MiB │ 11.812513794583598 │
│ klijentIP │ 2.35 GiB │ 82.59 MiB │ 29.132328640073343 │
│ klijentPraviIP │ 2.49 GiB │ 465.05 MiB │ 5.478382297052563 │
│ korisničkiAgent │ 18.34 GiB │ 764.08 MiB │ 24.57905114484208 │
│ referer │ 14.71 GiB │ 1.37 GiB │ 10.736792723669906 │
│ odgovor │ 803.06 MiB │ 83.81 MiB │ 9.582334090987247 │
│ pododgovor │ 399.87 MiB │ 1.83 MiB │ 218.4831068635027 │
│ win32odgovor │ 407.86 MiB │ 7.41 MiB │ 55.050315514606815 │
│ vrijemeOduzeto │ 1.57 GiB │ 402.06 MiB │ 3.9947395692010637 │
│ uriUpit__utm_medium │ 208.17 MiB │ 12.29 MiB │ 16.936148912472955 │
│ uriUpit__utm_source │ 215.18 MiB │ 13.00 MiB │ 16.548367623199912 │
│ uriUpit__utm_campaign │ 381.46 MiB │ 37.94 MiB │ 10.055156353418509 │
│ uriUpit__utm_term │ 231.82 MiB │ 10.78 MiB │ 21.502540454070672 │
│ uriUpit__utm_content │ 441.34 MiB │ 87.60 MiB │ 5.038260760449327 │
│ uriUpit__yclid │ 216.88 MiB │ 16.58 MiB │ 13.07721335008116 │
│ uriUpit__regija │ 204.35 MiB │ 9.49 MiB │ 21.52661903446796 │
└────────────────────────┴──────────────┴────────────┴────────────────────┘
28 redaka u skupu. Prošlo: 0.005 sekundi.Opis korištenih komponenti
FileBeat. Prijenos datoteka s logovima
Ova komponenta prati promjene u log datotekama na disku i prenosi informacije u LogStash. Instalira se na svim serverima gdje se pišu log datoteke (obično IIS). Radi u režimu tail (tj. prenosi samo dodane zapise u datoteci). No, može se posebno postaviti i za prijenos cijelih datoteka. To je zgodno kada je potrebno učitati podatke za prethodne mjesece. Jednostavno stavite datoteku s logovima u mapu i ona će je sama potpuno pročitati.
Kada se usluga zaustavi, podaci prestaju dalje da se šalju u skladište.
Primer konfiguracije izgleda ovako:
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.hr"
fld_app_name: "site1.domain.hr"
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.hr"
fld_app_name: "site2.domain.hr"
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.hr.cer"
ssl.key: "C:/filebeat/certs/site1.domain.hr.key"
#================================ Procesori =====================================
processors:
- add_host_metadata: ~
- add_cloud_metadata: ~LogStash. Skupljač logova
Ova komponenta je namenjena za prikupljanje zapisa logova od FileBeat-a (ili putem reda RabbitMQ), parsiranje i umetanje u serijama u Bazu podataka ClickHouse.
Za umetanje u ClickHouse koristi se dodatak Logstash-output-clickhouse. Dodatak Logstash ima mehanizam za ponavljanje zahteva, ali pri normalnom zaustavljanju, bolje je ipak da se zaustavi sama usluga. Kada se zaustavi, poruke će se gomilati u redu RabbitMQ, stoga ako je zaustavljanje na duži vremenski period, bolje je zaustaviti Filebeat-e na serverima. U šemi gde se ne koristi RabbitMQ (u lokalnoj mreži Filebeat direktno šalje logove u Logstash), Filebeat-i rade sasvim prihvatljivo i sigurno, stoga za njih nedostupnost output-a prolazi bez posledica.
Primer konfiguracije izgleda ovako:
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. Skladište logova
Logovi svih sustava pohranjuju se u jednu tablicu (vidi na početku članka). Ona je namijenjena za pohranu informacija o zahtjevima: svi parametri su slični za različite formate, poput IIS logova, apache i nginx logova. Za logove aplikacija, u kojima se bilježe, na primjer, greške, informativne poruke, upozorenja, bit će predviđena zasebna tablica s odgovarajućom strukturom (trenutno u fazi projektiranja).
Prilikom projektiranja tablice vrlo je važno odrediti primarni ključ (prema kojem će se podaci sortirati prilikom pohrane). Od toga ovisi stupanj kompresije podataka i brzina upita. U našem primjeru ključ je
ORDER BY (fld_app_name, fld_app_module, logdatetime)
Dakle, prema nazivu sustava, nazivu komponente sustava i datumu događaja. Izvorno je datum događaja bio na prvom mjestu. Nakon premještanja na posljednje mjesto, upiti su postali brži otprilike dvostruko. Promjena primarnog ključa zahtijeva ponovnu izradu tablice i ponovnu uplatu podataka, kako bi ClickHouse ponovo sortirao podatke na disku. To je teška operacija, stoga je poželjno unaprijed dobro razmisliti što bi trebalo uključiti u ključ sortiranja.
Također je potrebno napomenuti da je u posljednjim verzijama uveden tip podataka LowCardinality. Njegovom upotrebom naglo se smanjuje veličina komprimiranih podataka za ona polja koja imaju nisku kardinalnost (malo varijacija).
Trenutno se koristi verzija 19.6, a planiramo pokušati nadograditi verziju na najnoviju. U njima su uvedene sjajne značajke poput Adaptive Granularity, Skipping indices i kodiranja DoubleDelta, na primjer.
Po defaultu, prilikom instalacije u konfiguraciji postavljen je nivo logiranja trace. Logovi se rotiraju i arhiviraju, ali se pritom proširuju do jednog gigabajta. Ako nije potrebna, može se postaviti nivo warning, tada se veličina loga naglo smanjuje. Postavke logiranja definiraju se u datoteci config.xml:
<!-- Mogući nivoi: https://github.com/pocoproject/poco/blob/develop/Foundation/include/Poco/Logger.h#L105 -->
<level>warning</level>Neke korisne komande
Budući da se izvorni instalacijski paketi sastavljaju prema Debianu, za druge verzije Linuxa potrebno je koristiti pakete koje je sastavila tvrtka Altinity.
U ovom linku nalaze se upute s poveznicama na njihovu pohranu: https://www.altinity.com/blog/2017/12/18/logstash-with-clickhouse
sudo yum search clickhouse-server
sudo yum install clickhouse-server.noarch
1. provjera statusa
sudo systemctl status clickhouse-server
2. zaustavljanje poslužitelja
sudo systemctl stop clickhouse-server
3. pokretanje poslužitelja
sudo systemctl start clickhouse-server
Pokretanje za izvršenje upita u višelinijskom načinu (izvršavanje nakon znaka ";")
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
ClickHouse plugin za Logstash u slučaju greške u jednom redu čuva cijelu seriju u datoteku /tmp/log_web_failed.json
Možete ručno ispraviti tu datoteku i pokušati je umetnuti u Bazu podataka ručno:
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
izlaz iz naredbenog retka
quit;
## Postavke TLS
https://www.altinity.com/blog/2019/3/5/clickhouse-networking-part-2
openssl s_client -connect log.domain.com:9440 < /dev/nullLogStash. Usmjerivač logova od FileBeata do queue RabbitMQ
Ova komponenta se koristi za usmjeravanje logova primljenih od FileBeata do queue RabbitMQ. Ovdje su dva aspekta:
- Nažalost, FileBeat nema output plugin za izravno zapisivanje u RabbitMQ. Takva funkcionalnost, sudeći po problemu na njihovom GitHubu, ne planira se implementirati. Postoji plugin za Kafka, ali iz određenih razloga je ne možemo koristiti kod nas.
- Postoje zahtjevi za sakupljanje logova u DMZ. Prema njima, logovi prvo moraju biti smješteni u queue, a zatim LogStash izvana čita iz queuea zapise.
Stoga, upravo za slučaj kada su poslužitelji smješteni u DMZ, moramo koristiti malo složeniju shemu. Primjer konfiguracije izgleda ovako:
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. Red queue
Ovaj komponent se koristi za bufferiranje log zapisnika u DMZ-u. Zapis se vrši preko veze Filebeat → LogStash. Čitanje se odvija izvan DMZ-a putem LogStasha. U radu preko RabbitMQ obrađuje se oko 4 tisuće poruka u sekundi.
Ruting poruka podešen je prema nazivu sustava, tj. na osnovi podataka iz konfiguracije FileBeat. Sve poruke idu u jedan red. Ako iz nekog razloga usluga redova bude zaustavljena, to neće dovesti do gubitka poruka: FileBeat će primati greške u vezi i privremeno obustaviti slanje. A LogStash, koji čita iz reda, također će primati mrežne greške i čekati da se veza obnovi. Podaci se u tom slučaju, naravno, prestaju zapisivati u bazu podataka.
Sljedeće upute se koriste za izradu i postavljanje redova:
sudo /usr/local/bin/rabbitmqadmin declare exchange --vhost=/ name=monitor.direct type=direct sudo /usr/local/bin/rabbitmqadmin declare queue --vhost=/ name=web_log durable=true
sudo /usr/local/bin/rabbitmqadmin --vhost="/" declare binding source="monitor.direct" destination_type="queue" destination="web_log" routing_key="site1.domain.ru"
sudo /usr/local/bin/rabbitmqadmin --vhost="/" declare binding source="monitor.direct" destination_type="queue" destination="web_log" routing_key="site2.domain.ru"Grafana. Dashboardi
Ovaj komponent se koristi za vizualizaciju podataka monitoringa. U tu svrhu potrebno je instalirati plug-in ClickHouse datasource for Grafana 4.6+. Morali smo ga malo prilagoditi kako bismo poboljšali učinkovitost obrade SQL filtriranjem na dashboardu.
Na primjer, koristimo varijable, a ako nisu postavljene u polju filtra, voljeli bismo da ne generira uvjet u WHERE-u koji izgleda kao ( uriStem = » AND uriStem != » ). U tom slučaju, ClickHouse će čitati kolonu uriStem. Uglavnom, isprobali smo različite opcije i na kraju prilagodili plug-in (makros $valueIfEmpty), tako da u slučaju prazne vrijednosti vraća 1, bez pominjanja same kolone.
I sada možemo koristiti ovakav upit za grafikon
$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')koji se pretvara u takav SQL (primijetite da su prazna polja uriStem pretvorena samo u 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 ASCZaključak
Pojava ClickHouse baze podataka bila je značajan događaj na tržištu. Teško je bilo zamisliti da ćemo potpuno besplatno u jednom trenutku nabaviti moćan i praktičan alat za rad s velikim podacima. Naravno, s povećanjem potreba (na primjer, shardiranje i replikacija na nekoliko servera) shema će postati složenija. No, prema prvim utiscima, rad s ovom bazom podataka vrlo je ugodan. Vidljivo je da je proizvod napravljen "za ljude".
U usporedbi s ElasticSearch-om, troškovi pohrane i obrade logova, prema preliminarnim procjenama, smanjuju se od pet do deset puta. Drugim riječima, ako bismo za trenutni obujam podataka morali postaviti klaster od nekoliko strojeva, uz upotrebu ClickHouse-a nam potrebna samo jedna slaba mašina. Da, naravno, u ElasticSearch-u također postoje mehanizmi za kompresiju podataka na disku i druge značajke koje omogućuju značajno smanjenje potrošnje resursa, ali u usporedbi s ClickHouse-om to bi zahtijevalo veće troškove.
Bez ikakvih posebnih optimizacija s naše strane, s zadanim postavkama, učitavanje podataka i upiti iz baze podataka rade nevjerojatnom brzinom. Podataka trenutno imamo malo (oko 200 milijuna zapisa), ali server je slab. Ovaj alat možemo u budućnosti koristiti i za druge svrhe, koje nemaju veze s pohranom logova. Na primjer, za cjelovitu analitiku, u području sigurnosti, strojnom učenju.
Na kraju malo o minusima i plusima.
Nedostaci
- Učitavanje zapisa u velikim paketima. S jedne strane, to je značajka, ali svejedno je potrebno koristiti dodatne komponente za međuspremanje zapisa. Ova zadaća nije uvijek jednostavna, ali je ipak rješiva. I volio bih pojednostaviti shemu.
- Neki egzotični funkcionalnosti ili nove značajke često se u novim verzijama pokvare. To izaziva zabrinutost, smanjujući želju za nadogradnjom na novu verziju. Na primjer, Kafka tablični motor – vrlo korisna značajka koja omogućava izravno čitanje događaja iz Kafke, bez implementacije potrošača. No, sudeći po broju problema na GitHubu, zasad se klonimo korištenja tog motora u produkciji. Ipak, ako ne radimo nagle pomake i koristimo osnovnu funkcionalnost, radi stabilno.
Prednosti
- Ne usporava.
- Nizak prag ulaska.
- Open-source.
- Besplatno.
- Dobro se skalira (shardiranje/replikacija "iz kutije")
- Uvršteno u registar ruskog softvera preporučenog od strane Ministra za komunikacije.
- Postojanje službene podrške od Yandexa.
Izvor: habr.com
