Aleksej Lizunov, voditelj Centra kompetencija za kanale daljinskih usluga Uprave za informacijske tehnologije MKB-a
Kao alternativu ELK stacku (ElasticSearch, Logstash, Kibana), istražujemo korištenje baze podataka ClickHouse kao pohrane podataka za zapise.
U ovom članku želimo govoriti o našem iskustvu korištenja baze podataka ClickHouse i preliminarnim rezultatima pilot operacije. Odmah treba napomenuti da su rezultati bili impresivni.
Zatim ćemo detaljnije opisati kako je naš sustav konfiguriran i od kojih se komponenti sastoji. Ali sada bih želio govoriti malo o ovoj bazi podataka u cjelini i zašto je vrijedno pažnje. Baza podataka ClickHouse je visokoučinkovita analitička baza podataka u stupcima tvrtke Yandex. Koristi se u uslugama Yandex, u početku je glavna pohrana podataka za Yandex.Metricu. Sustav otvorenog koda, besplatan. Sa stajališta programera, uvijek sam se pitao kako su to implementirali, jer ima fantastično velikih podataka. I samo korisničko sučelje Metrice vrlo je fleksibilno i brzo. Pri prvom upoznavanju s ovom bazom podataka dojam je: „E, konačno! Stvoreno za ljude! Počevši od procesa instalacije pa sve do slanja zahtjeva.
Ova baza podataka ima vrlo nizak ulazni prag. Čak i prosječno vješt programer može instalirati ovu bazu podataka u nekoliko minuta i početi je koristiti. Sve radi jasno. Čak i ljudi koji su novi u Linuxu mogu brzo obaviti instalaciju i izvesti najjednostavnije operacije. Ako je ranije uz riječi Big Data, Hadoop, Google BigTable, HDFS obični programer imao ideje da se radi o nekim terabajtima, petabajtima, da se nekim nadljudima bave postavkama i razvojem za te sustave, onda je pojavom ClickHousea baze podataka, dobili smo jednostavan, razumljiv alat s kojim možete riješiti dosad nedostižan niz zadataka. Za instalaciju je potreban samo jedan prilično prosječan stroj i pet minuta. Odnosno, dobili smo takvu bazu podataka kao što je, na primjer, MySql, ali samo za pohranjivanje milijardi zapisa! Određeni super-arhivator sa SQL jezikom. Kao da je ljudima predano oružje vanzemaljaca.
O našem sustavu zapisivanja
Za prikupljanje informacija koriste se IIS log datoteke web aplikacija standardnog formata (trenutačno analiziramo i logove aplikacija, ali glavni cilj u pilot fazi je prikupljanje IIS logova).
Iz različitih razloga nismo mogli u potpunosti napustiti ELK stack, te nastavljamo koristiti LogStash i Filebeat komponente, koje su se dobro pokazale i rade prilično pouzdano i predvidljivo.
Opća shema zapisivanja prikazana je na donjoj slici:
Značajka pisanja podataka u bazu podataka ClickHouse je rijetko (jednom u sekundi) umetanje zapisa u velikim serijama. Ovo je, očito, "najproblematičniji" dio s kojim se susrećete kada prvi put iskusite rad s bazom podataka ClickHouse: shema postaje malo kompliciranija.
Tu je puno pomogao dodatak za LogStash koji izravno ubacuje podatke u ClickHouse. Ova komponenta je postavljena na istom poslužitelju kao i sama baza podataka. Dakle, općenito govoreći, nije preporučljivo to raditi, ali s praktične točke gledišta, kako se ne bi proizvodili zasebni poslužitelji dok je raspoređen na istom poslužitelju. Nismo primijetili nikakve kvarove ili sukobe resursa s bazom podataka. Osim toga, treba napomenuti da dodatak ima mehanizam ponovnog pokušaja u slučaju pogreške. A u slučaju pogrešaka, dodatak zapisuje na disk skup podataka koji se ne mogu umetnuti (format datoteke je prikladan: nakon uređivanja možete jednostavno umetnuti ispravljeni paket pomoću clickhouse-clienta).
Kompletan popis softvera koji se koristi u shemi prikazan je u tablici:
Popis korištenog softvera
ime
Opis
Distribucijska veza
Nginx
Reverse-proxy za ograničavanje pristupa portovima i organiziranje autorizacije
Trenutno se ne koristi u shemi
FileBeat
Prijenos zapisa datoteka.
logstash
Sakupljač trupaca.
Koristi se za prikupljanje zapisa iz FileBeata, kao i za prikupljanje zapisa iz RabbitMQ reda (za poslužitelje koji su u DMZ-u.)
Logstash-output-clickhouse
Dodatak Loagstash za prijenos zapisa u bazu podataka ClickHouse u serijama
/usr/share/logstash/bin/logstash-plugin instalacija logstash-output-clickhouse
/usr/share/logstash/bin/logstash-plugin instalacija logstash-filter-prune
/usr/share/logstash/bin/logstash-plugin instalacija logstash-filter-multiline
klikanica
Pohranjivanje dnevnika
Bilješka. Počevši od kolovoza 2018., "normalne" rpm verzije za RHEL pojavile su se u Yandex repozitoriju, tako da ih možete pokušati koristiti. U vrijeme instalacije koristili smo pakete koje je izradio Altinity.
grafana
Vizualizacija dnevnika. Postavljanje nadzornih ploča
Redhat & Centos (64 Bit) - najnovija verzija
ClickHouse izvor podataka za Grafana 4.6+
Dodatak za Grafanu s izvorom podataka ClickHouse
logstash
Zapišite usmjerivač iz FileBeata u RabbitMQ red čekanja.
Bilješka. Nažalost, FileBeat nema izlaz izravno na RabbitMQ, pa je potrebna posredna poveznica u obliku Logstasha
Zec MQ
red poruka. Ovo je međuspremnik dnevnika u DMZ-u
Erlang Runtime (Potrebno za RabbitMQ)
Erlang runtime. Potreban za rad RabbitMQ-a
Konfiguracija poslužitelja s bazom podataka ClickHouse prikazana je u sljedećoj tablici:
ime
Vrijednost
Primijetiti
Konfiguracija
HDD: 40 GB
RAM: 8GB
Procesor: Core 2 2Ghz
Potrebno je obratiti pažnju na savjete za rad baze podataka ClickHouse (
Opći sistemski softver
OS: Red Hat Enterprise Linux Server (Maipo)
JRE (Java 8)
Kao što vidite, ovo je obična radna stanica.
Struktura tablice za pohranjivanje dnevnika je sljedeća:
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 zadanu particiju (po mjesecima) i granularnost indeksa. Sva polja praktički odgovaraju IIS log unosima za bilježenje http zahtjeva. Zasebno napominjemo da postoje zasebna polja za pohranjivanje utm-oznaka (raščlanjuju se u fazi umetanja u tablicu iz polja niza upita).
Također, u tablicu je dodano nekoliko sistemskih polja za pohranu informacija o sustavima, komponentama, poslužiteljima. Za opis ovih polja pogledajte tablicu u nastavku. U jednoj tablici pohranjujemo zapise za nekoliko sustava.
ime
Opis
Primjer
naziv_fld_aplikacije
Naziv aplikacije/sustava
Važeće vrijednosti:
- site1.domain.com Vanjska stranica 1
- site2.domain.com Vanjska stranica 2
- interna-stranica1.domena.lokalno Interna stranica 1
site1.domain.com
fld_app_module
Modul sustava
Važeće vrijednosti:
- web - Web stranica
- svc - Usluga web stranice
- intgr - Integracijska web usluga
- bo - Administrator (BackOffice)
tkanje
fld_website_name
Naziv stranice u IIS-u
Na jednom poslužitelju može se postaviti nekoliko sustava ili čak nekoliko instanci jednog modula sustava
web glavni
ime_poslužitelja_fld
Naziv poslužitelja
web1.domena.com
fld_log_file_name
Put do datoteke dnevnika na poslužitelju
C:inetpublogsLogFiles
W3SVC1u_ex190711.log
To vam omogućuje učinkovitu izradu grafikona u Grafani. Na primjer, pregledajte zahtjeve sa sučelja određenog sustava. Ovo je slično brojaču stranica u Yandex.Metrici.
Evo nekoliko statistika o korištenju baze podataka za dva mjeseca.
Broj zapisa raščlanjenih po 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.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.)
Količina 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
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.
Opis korištenih komponenti
FileBeat. Prijenos zapisnika datoteka
Ova komponenta prati promjene u log datotekama na disku i prosljeđuje informacije LogStashu. Instalirano na svim poslužiteljima na kojima se pišu datoteke dnevnika (obično IIS). Radi u repnom načinu (tj. prenosi samo dodane zapise u datoteku). Ali zasebno se može konfigurirati za prijenos cijelih datoteka. Ovo je korisno kada trebate preuzeti podatke iz prethodnih mjeseci. Samo stavite log datoteku u mapu i on će je pročitati u cijelosti.
Kada se usluga zaustavi, podaci se više ne prenose dalje u pohranu.
Primjer 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.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. Sakupljač dnevnika
Ova je komponenta dizajnirana za primanje unosa dnevnika od FileBeata (ili kroz RabbitMQ red čekanja), analiziranje i umetanje serija u bazu podataka ClickHouse.
Za umetanje u ClickHouse koristi se dodatak Logstash-output-clickhouse. Dodatak Logstash ima mehanizam za ponovni pokušaj zahtjeva, ali s redovitim gašenjem bolje je zaustaviti sam servis. Kada se zaustave, poruke će se akumulirati u RabbitMQ redu čekanja, pa ako je zaustavljanje na duže vrijeme, onda je bolje zaustaviti Filebeats na poslužiteljima. U shemi gdje se RabbitMQ ne koristi (na lokalnoj mreži Filebeat izravno šalje logove u Logstash), Filebeati rade sasvim prihvatljivo i sigurno, pa za njih nedostupnost izlaza prolazi bez posljedica.
Primjer 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"
}
}
}
cjevovodi.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"
klikanica. Pohranjivanje dnevnika
Dnevnici za sve sustave pohranjuju se u jednu tablicu (vidi na početku članka). Namijenjen je pohrani informacija o zahtjevima: svi parametri su slični za različite formate, kao što su IIS zapisnici, apache i nginx zapisnici. Za zapise aplikacija, u koje se bilježe npr. pogreške, informativne poruke, upozorenja, bit će osigurana posebna tablica s odgovarajućom strukturom (trenutačno u fazi projektiranja).
Prilikom izrade tablice vrlo je važno odlučiti se o primarnom ključu (po kojem će se podaci sortirati tijekom pohrane). O tome ovisi stupanj kompresije podataka i brzina upita. U našem primjeru, ključ je
ORDER BY (fld_app_name, fld_app_module, logdatetime)
Odnosno prema nazivu sustava, nazivu komponente sustava i datumu događaja. U početku je na prvom mjestu bio datum događaja. Nakon što su ga premjestili na posljednje mjesto, upiti su počeli raditi otprilike dvostruko brže. Promjena primarnog ključa zahtijevat će ponovno stvaranje tablice i ponovno učitavanje podataka tako da ClickHouse ponovno sortira podatke na disku. Ovo je teška operacija, stoga je dobra ideja puno razmišljati o tome što bi trebalo biti uključeno u ključ sortiranja.
Također treba napomenuti da se tip podataka LowCardinality relativno pojavio u novijim verzijama. Kada ga koristite, veličina komprimiranih podataka je drastično smanjena za ona polja koja imaju nisku kardinalnost (malo opcija).
Trenutno je u upotrebi verzija 19.6 i planiramo pokušati ažurirati na najnoviju verziju. Imaju tako divne značajke kao što su Adaptive Granularity, Skipping indeksi i DoubleDelta kodek, na primjer.
Prema zadanim postavkama, tijekom instalacije, razina zapisivanja postavljena je na praćenje. Dnevnici se rotiraju i arhiviraju, ali se istovremeno proširuju do gigabajta. Ako nema potrebe, možete postaviti razinu upozorenja, tada se veličina dnevnika drastično smanjuje. Postavka zapisivanja postavljena je u datoteci config.xml:
<!-- Possible levels: https://github.com/pocoproject/poco/blob/develop/Foundation/include/Poco/Logger. h#L105 -->
<level>warning</level>
Neke korisne naredbe
Поскольку оригинальные пакеты установки собираются по 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. Zapišite usmjerivač iz FileBeata u RabbitMQ red čekanja
Ova se komponenta koristi za usmjeravanje zapisa koji dolaze iz FileBeata u RabbitMQ red čekanja. Ovdje postoje dvije točke:
- Nažalost, FileBeat nema izlazni dodatak za izravno pisanje u RabbitMQ. A takva funkcionalnost, sudeći po pitanju na njihovom githubu, nije planirana za implementaciju. Postoji dodatak za Kafku, ali ga iz nekog razloga ne možemo koristiti kod kuće.
- Postoje zahtjevi za prikupljanje trupaca u DMZ. Na temelju njih, dnevnici se prvo moraju dodati u red čekanja, a zatim LogStash izvana čita unose iz reda čekanja.
Stoga se za slučaj kada se poslužitelji nalaze u DMZ-u mora koristiti ovakva pomalo komplicirana shema. 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 poruka
Ova se komponenta koristi za međuspremnik unosa dnevnika u DMZ. Snimanje se vrši kroz hrpu Filebeat → LogStash. Čitanje se vrši izvan DMZ-a putem LogStasha. Pri radu preko RabboitMQ-a obrađuje se oko 4 tisuće poruka u sekundi.
Usmjeravanje poruka konfigurirano je prema nazivu sustava, tj. na temelju FileBeat konfiguracijskih podataka. Sve poruke idu u jedan red. Ako se iz nekog razloga usluga čekanja zaustavi, to neće dovesti do gubitka poruka: FileBeats će primiti pogreške veze i privremeno obustaviti slanje. A LogStash koji čita iz reda čekanja također će primati mrežne pogreške i čekati da se veza uspostavi. U tom slučaju podaci, naravno, više neće biti upisani u bazu podataka.
Za izradu i konfiguraciju redova čekanja koriste se sljedeće upute:
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. Nadzorne ploče
Ova se komponenta koristi za vizualizaciju podataka praćenja. U tom slučaju trebate instalirati izvor podataka ClickHouse za Grafana 4.6+ dodatak. Morali smo ga malo prilagoditi kako bismo poboljšali učinkovitost obrade SQL filtara na nadzornoj ploči.
Na primjer, koristimo varijable, a ako one nisu postavljene u polje filtera, tada bismo željeli da ne generira uvjet u WHERE obrasca ( uriStem = » AND uriStem != » ). U ovom slučaju, ClickHouse će pročitati stupac uriStem. Općenito, isprobali smo različite opcije i na kraju ispravili dodatak (makronaredba $valueIfEmpty) tako da u slučaju prazne vrijednosti vraća 1, bez spominjanja samog stupca.
Sada možete koristiti ovaj 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')
što se prevodi u ovaj SQL (imajte na umu da su prazna uriStem polja pretvorena u samo 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
Zaključak
Pojava baze podataka ClickHouse postala je značajan događaj na tržištu. Bilo je teško zamisliti da smo, potpuno besplatno, u trenu dobili moćan i praktičan alat za rad s velikim podacima. Naravno, s povećanjem potreba (na primjer, dijeljenje i replikacija na više poslužitelja), shema će postati kompliciranija. Ali na prvi dojam, rad s ovom bazom podataka je vrlo ugodan. Vidi se da je proizvod napravljen "za ljude".
U usporedbi s ElasticSearchom, procjenjuje se da su troškovi pohrane i obrade zapisa smanjeni pet do deset puta. Drugim riječima, ako bismo za trenutnu količinu podataka morali postaviti klaster od nekoliko strojeva, onda nam je kod ClickHousea dovoljan jedan stroj male snage. Da, naravno, ElasticSearch također ima mehanizme kompresije podataka na disku i druge značajke koje mogu značajno smanjiti potrošnju resursa, ali u usporedbi s ClickHouseom, to će biti skuplje.
Bez ikakvih posebnih optimizacija s naše strane, na zadanim postavkama, učitavanje podataka i odabir iz baze radi nevjerojatnom brzinom. Još nemamo puno podataka (oko 200 milijuna zapisa), ali sam poslužitelj je slab. Ovaj alat možemo koristiti u budućnosti u druge svrhe koje nisu povezane s pohranjivanjem dnevnika. Na primjer, za end-to-end analitiku, u području sigurnosti, strojnog učenja.
Na kraju, malo o prednostima i manama.
Cons
- Učitavanje zapisa u velikim serijama. S jedne strane, ovo je značajka, ali još uvijek morate koristiti dodatne komponente za međuspremnik zapisa. Ovaj zadatak nije uvijek lak, ali ipak rješiv. I želio bih pojednostaviti shemu.
- Neke egzotične funkcije ili nove značajke često se kvare u novim verzijama. To izaziva zabrinutost, smanjujući želju za nadogradnjom na novu verziju. Na primjer, Kafka table engine je vrlo korisna značajka koja vam omogućuje izravno čitanje događaja iz Kafke, bez implementacije potrošača. No, sudeći po broju problema na githubu, još uvijek pazimo da ne koristimo ovaj mehanizam u proizvodnji. Međutim, ako ne radite nagle geste u stranu i koristite glavnu funkcionalnost, tada radi stabilno.
Prozodija
- Ne usporava.
- Nizak prag ulaska.
- Otvoreni izvor.
- Besplatno.
- Dobro se skalira (sharding/replikacija izvan kutije)
- Uključeno u registar ruskog softvera koje je preporučilo Ministarstvo komunikacija.
- Prisutnost službene podrške od Yandex.
Izvor: www.habr.com