Aleksejus Lizunovas, MKB Informacinių technologijų direkcijos Nuotolinių paslaugų kanalų kompetencijos centro vadovas
Kaip alternatyvą ELK kaminui (ElasticSearch, Logstash, Kibana), atliekame ClickHouse duomenų bazės, kaip žurnalų duomenų saugyklos, naudojimą.
Šiame straipsnyje norėtume pakalbėti apie mūsų patirtį naudojantis ClickHouse duomenų baze ir preliminarius bandomosios operacijos rezultatus. Iš karto reikia pažymėti, kad rezultatai buvo įspūdingi.
Toliau išsamiau apibūdinsime, kaip mūsų sistema sukonfigūruota ir iš kokių komponentų ji susideda. Bet dabar norėčiau šiek tiek pakalbėti apie šią duomenų bazę kaip visumą ir kodėl verta į ją atkreipti dėmesį. „ClickHouse“ duomenų bazė yra didelio našumo analitinė stulpelių duomenų bazė iš „Yandex“. Jis naudojamas „Yandex“ paslaugose, iš pradžių tai yra pagrindinė „Yandex.Metrica“ duomenų saugykla. Atvirojo kodo sistema, nemokama. Žvelgiant iš kūrėjo pusės, man visada buvo įdomu, kaip jie tai įgyvendino, nes yra fantastiškai didelių duomenų. O pati Metrica vartotojo sąsaja yra labai lanksti ir greita. Pirmą kartą susipažinus su šia duomenų baze, susidaro įspūdis: „Na, pagaliau! Sukurta žmonėms! Pradedant nuo diegimo proceso ir baigiant užklausų siuntimu.
Ši duomenų bazė turi labai žemą įėjimo slenkstį. Net ir vidutinės kvalifikacijos kūrėjas gali per kelias minutes įdiegti šią duomenų bazę ir pradėti ja naudotis. Viskas veikia aiškiai. Netgi žmonės, kurie dar nesinaudojo Linux, gali greitai atlikti diegimą ir atlikti paprasčiausias operacijas. Jei anksčiau, naudojant žodžius „Big Data“, „Hadoop“, „Google BigTable“, HDFS, paprastas kūrėjas turėjo minčių, kad kalbama apie keletą terabaitų, petabaitų, kad kai kurie antžmogiai užsiima šių sistemų nustatymais ir kūrimu, tai atsiradus „ClickHouse“ duomenų bazę, gavome paprastą, suprantamą įrankį, su kuriuo galite išspręsti anksčiau nepasiekiamą užduočių spektrą. Įdiegti užtrunka tik vieną gana vidutinį įrenginį ir penkias minutes. Tai yra, mes turime tokią duomenų bazę kaip, pavyzdžiui, MySql, bet tik milijardams įrašų saugojimui! Tam tikras super archyvatorius su SQL kalba. Lyg žmonėms būtų įteikti ateivių ginklai.
Apie mūsų registravimo sistemą
Informacijai rinkti naudojami standartinio formato žiniatinklio programų IIS žurnalų failai (šiuo metu taip pat analizuojame programų žurnalus, tačiau pagrindinis tikslas bandomajame etape yra rinkti IIS žurnalus).
Dėl įvairių priežasčių negalėjome visiškai atsisakyti ELK stacko ir toliau naudojame LogStash ir Filebeat komponentus, kurie pasiteisino ir veikia gana patikimai ir nuspėjamai.
Bendra registravimo schema parodyta paveikslėlyje žemiau:
Duomenų rašymo į ClickHouse duomenų bazę ypatybė yra nedažnas (kartą per sekundę) įrašų įterpimas didelėmis partijomis. Tai, matyt, yra „problemiškiausia“ dalis, su kuria susiduriate pirmą kartą dirbant su ClickHouse duomenų baze: schema tampa šiek tiek sudėtingesnė.
Čia labai padėjo LogStash įskiepis, kuris tiesiogiai įterpia duomenis į ClickHouse. Šis komponentas yra įdiegtas tame pačiame serveryje kaip ir pati duomenų bazė. Taigi, paprastai kalbant, tai daryti nerekomenduojama, o praktiniu požiūriu, kad nebūtų gaminami atskiri serveriai, kol jis yra dislokuotas tame pačiame serveryje. Nepastebėjome jokių gedimų ar išteklių konfliktų su duomenų baze. Be to, reikia pažymėti, kad įskiepis turi pakartotinio bandymo mechanizmą klaidų atveju. O esant klaidoms, įskiepis įrašo į diską duomenų, kurių nepavyko įterpti, paketą (failo formatas patogus: po redagavimo galite lengvai įterpti pataisytą paketą naudodami clickhouse-client).
Visas schemoje naudojamos programinės įrangos sąrašas pateiktas lentelėje:
Naudotos programinės įrangos sąrašas
Pavadinimas
aprašymas
Platinimo nuoroda
nginx
Atvirkštinis tarpinis serveris, skirtas apriboti prieigą prie prievadų ir organizuoti autorizavimą
Šiuo metu schemoje nenaudojamas
FileBeat
Failų žurnalų perkėlimas.
logstash
Rąstų surinkėjas.
Naudojamas žurnalams iš FileBeat, taip pat žurnalams iš RabbitMQ eilės (serveriams, kurie yra DMZ) rinkti.
Logstash-output-clickhouse
Loagstash įskiepis, skirtas žurnalų siuntimui į ClickHouse duomenų bazę partijomis
/usr/share/logstash/bin/logstash-plugin įdiegti logstash-output-clickhouse
/usr/share/logstash/bin/logstash-plugin įdiegti logstash-filter-prune
/usr/share/logstash/bin/logstash-plugin įdiegti logstash-filter-multiline
„ClickHouse“
Rąstų saugykla
Pastaba. Nuo 2018 m. rugpjūčio mėn. „Yandex“ saugykloje pasirodė „įprasti“ RHEL rpm versijos, todėl galite pabandyti jas naudoti. Diegimo metu naudojome „Altinity“ sukurtus paketus.
grafana
Žurnalo vizualizacija. Prietaisų skydelių nustatymas
Redhat & Centos (64 bitų) – naujausia versija
„ClickHouse“ duomenų šaltinis, skirtas „Grafana 4.6+“.
„Grafana“ papildinys su „ClickHouse“ duomenų šaltiniu
logstash
Užregistruokite maršrutizatorių iš „FileBeat“ į „RabbitMQ“ eilę.
Pastaba. Deja, FileBeat neturi išvesties tiesiai į RabbitMQ, todėl reikalinga tarpinė nuoroda Logstash forma
TriušisMQ
pranešimų eilė. Tai yra žurnalo buferis DMZ
„Erlang Runtime“ (būtina „RabbitMQ“)
Erlang vykdymo laikas. Būtina, kad RabbitMQ veiktų
Serverio konfigūracija su ClickHouse duomenų baze pateikta šioje lentelėje:
Pavadinimas
Vertė
Atkreipti dėmesį
Konfigūravimas
HDD: 40GB
RAM: 8GB
Procesorius: Core 2 2GHz
Būtina atkreipti dėmesį į ClickHouse duomenų bazės valdymo patarimus (
Bendroji sistemos programinė įranga
OS: „Red Hat Enterprise Linux Server“ („Maipo“)
JRE („Java 8“)
Kaip matote, tai yra įprasta darbo vieta.
Rąstų saugojimo lentelės struktūra yra tokia:
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;
Naudojame numatytąjį skaidymą (pagal mėnesį) ir indekso detalumą. Visi laukai praktiškai atitinka IIS žurnalo įrašus, skirtus http užklausoms registruoti. Atskirai pažymime, kad yra atskiri laukai utm žymoms saugoti (jie analizuojami įterpiant į lentelę iš užklausos eilutės lauko).
Taip pat į lentelę buvo įtraukti keli sistemos laukai, kuriuose saugoma informacija apie sistemas, komponentus, serverius. Žemiau esančioje lentelėje rasite šių laukų aprašymą. Vienoje lentelėje saugome kelių sistemų žurnalus.
Pavadinimas
aprašymas
Pavyzdys
fld_programos_pavadinimas
Programos / sistemos pavadinimas
Galiojančios reikšmės:
- site1.domain.com 1 išorinė svetainė
- site2.domain.com 2 išorinė svetainė
- internal-site1.domain.local 1 vidinė svetainė
site1.domain.com
fld_app_module
Sistemos modulis
Galiojančios reikšmės:
- žiniatinklis – svetainė
- svc – svetainės paslauga
- intgr – interneto integravimo paslauga
- bo – administratorius („BackOffice“)
tinklas
fld_svetainės_pavadinimas
Svetainės pavadinimas IIS
Viename serveryje gali būti įdiegtos kelios sistemos arba net keli vieno sistemos modulio egzemplioriai
interneto pagrindinis
fld_serverio_vardas
Serverio pavadinimas
web1.domain.com
fld_log_file_name
Kelias į žurnalo failą serveryje
C:inetpublogsLogFiles
W3SVC1u_ex190711.log
Tai leidžia efektyviai kurti Grafana grafikus. Pavyzdžiui, peržiūrėti užklausas iš konkrečios sistemos sąsajos. Tai panašu į svetainės skaitiklį Yandex.Metrica.
Štai keletas statistikos apie naudojimąsi duomenų baze per du mėnesius.
Įrašų skaičius, suskirstytas pagal sistemas ir jų komponentus
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.)
Duomenų kiekis diske
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.
Duomenų suspaudimo stulpeliuose laipsnis
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.
Naudotų komponentų aprašymas
failo ritmas. Failų žurnalų perkėlimas
Šis komponentas seka žurnalo failų pakeitimus diske ir perduoda informaciją „LogStash“. Įdiegta visuose serveriuose, kuriuose rašomi žurnalo failai (dažniausiai IIS). Veikia uodegos režimu (t.y. į failą perkelia tik pridėtus įrašus). Tačiau atskirai jį galima sukonfigūruoti perkelti visus failus. Tai naudinga, kai reikia atsisiųsti duomenis iš ankstesnių mėnesių. Tiesiog įdėkite žurnalo failą į aplanką ir jis perskaitys jį visą.
Sustabdžius paslaugą, duomenys toliau į saugyklą nebeperkeliami.
Konfigūracijos pavyzdys atrodo taip:
filebeat.yml
filebeat.inputs:
- type: log
enabled: true
paths:
- C:/inetpub/logs/LogFiles/W3SVC1/*.log
exclude_files: ['.gz$','.zip$']
tail_files: true
ignore_older: 24h
fields:
fld_server_name: "site1.domain.ru"
fld_app_name: "site1.domain.ru"
fld_app_module: "web"
fld_website_name: "web-main"
- type: log
enabled: true
paths:
- C:/inetpub/logs/LogFiles/__Import/access_log-*
exclude_files: ['.gz$','.zip$']
tail_files: false
fields:
fld_server_name: "site2.domain.ru"
fld_app_name: "site2.domain.ru"
fld_app_module: "web"
fld_website_name: "web-main"
fld_logformat: "logformat__apache"
filebeat.config.modules:
path: ${path.config}/modules.d/*.yml
reload.enabled: false
reload.period: 2s
output.logstash:
hosts: ["log.domain.com:5044"]
ssl.enabled: true
ssl.certificate_authorities: ["C:/filebeat/certs/ca.pem", "C:/filebeat/certs/ca-issuing.pem"]
ssl.certificate: "C:/filebeat/certs/site1.domain.ru.cer"
ssl.key: "C:/filebeat/certs/site1.domain.ru.key"
#================================ Processors =====================================
processors:
- add_host_metadata: ~
- add_cloud_metadata: ~
logstash. Rąstų surinkėjas
Šis komponentas skirtas gauti žurnalo įrašus iš FileBeat (arba per RabbitMQ eilę), analizuojant ir įterpiant paketus į ClickHouse duomenų bazę.
Įterpimui į ClickHouse naudojamas Logstash-output-clickhouse papildinys. „Logstash“ papildinys turi užklausos pakartotinio bandymo mechanizmą, tačiau reguliariai išjungus, geriau sustabdyti pačią paslaugą. Sustabdžius pranešimai bus kaupiami RabbitMQ eilėje, todėl jei sustojimas trunka ilgą laiką, geriau sustabdyti „Filebeats“ serveriuose. Schemoje, kurioje RabbitMQ nenaudojamas (vietiniame tinkle Filebeat tiesiogiai siunčia žurnalus į Logstash), Filebeats veikia gana priimtinai ir saugiai, todėl jiems išvesties nepasiekimas praeina be pasekmių.
Konfigūracijos pavyzdys atrodo taip:
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"
}
}
}
vamzdynai.yml
# This file is where you define your pipelines. You can define multiple.
# For more information on multiple pipelines, see the documentation:
# https://www.elastic.co/guide/en/logstash/current/multiple-pipelines.html
- pipeline.id: log_web__filebeat_clickhouse
path.config: "/etc/logstash/log_web__filebeat_clickhouse.conf"
clickhouse. Rąstų saugykla
Visų sistemų žurnalai saugomi vienoje lentelėje (žr. straipsnio pradžioje). Jis skirtas saugoti informaciją apie užklausas: visi parametrai yra panašūs skirtingiems formatams, tokiems kaip IIS žurnalai, apache ir nginx žurnalai. Paraiškų žurnalams, kuriuose, pavyzdžiui, fiksuojamos klaidos, informaciniai pranešimai, įspėjimai, bus pateikta atskira lentelė su atitinkama struktūra (šiuo metu projektavimo stadijoje).
Kuriant lentelę labai svarbu apsispręsti dėl pirminio rakto (pagal kurį bus rūšiuojami duomenys saugojimo metu). Nuo to priklauso duomenų suspaudimo laipsnis ir užklausos greitis. Mūsų pavyzdyje svarbiausia yra
ORDER BY (fld_app_name, fld_app_module, logdatetime)
Tai yra pagal sistemos pavadinimą, sistemos komponento pavadinimą ir įvykio datą. Iš pradžių įvykio data buvo pirma. Perkėlus jį į paskutinę vietą, užklausos pradėjo veikti maždaug dvigubai greičiau. Norint pakeisti pirminį raktą, reikės iš naujo sukurti lentelę ir iš naujo įkelti duomenis, kad „ClickHouse“ iš naujo surūšiuotų duomenis diske. Tai sunki operacija, todėl verta daug galvoti apie tai, kas turėtų būti įtraukta į rūšiavimo raktą.
Taip pat reikėtų pažymėti, kad LowCardinality duomenų tipas pasirodė palyginti naujausiose versijose. Jį naudojant suglaudintų duomenų dydis smarkiai sumažėja tiems laukams, kurių kardinalumas yra mažas (nedaug variantų).
Šiuo metu naudojama 19.6 versija ir planuojame pabandyti atnaujinti į naujausią versiją. Pavyzdžiui, jie turi tokias nuostabias funkcijas kaip prisitaikantis detalumas, praleidimo indeksai ir „DoubleDelta“ kodekas.
Pagal numatytuosius nustatymus diegimo metu registravimo lygis nustatomas į sekimą. Žurnalai pasukami ir archyvuojami, tačiau tuo pat metu išsiplečia iki gigabaito. Jei nereikia, galite nustatyti įspėjimo lygį, tada rąsto dydis smarkiai sumažėja. Registravimo nustatymas nustatytas faile config.xml:
<!-- Possible levels: https://github.com/pocoproject/poco/blob/develop/Foundation/include/Poco/Logger. h#L105 -->
<level>warning</level>
Keletas naudingų komandų
Поскольку оригинальные пакеты установки собираются по 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. Užregistruokite maršrutizatorių iš „FileBeat“ į „RabbitMQ“ eilę
Šis komponentas naudojamas iš FileBeat gaunamiems žurnalams nukreipti į RabbitMQ eilę. Čia yra du punktai:
- Deja, „FileBeat“ neturi išvesties papildinio, kad būtų galima rašyti tiesiai į „RabbitMQ“. Ir toks funkcionalumas, sprendžiant iš jų „github“ problemos, nėra planuojamas įdiegti. Yra Kafka įskiepis, bet kažkodėl negalime jo naudoti namuose.
- DMZ nustatyti žurnalų rinkimo reikalavimai. Remiantis jais, žurnalai pirmiausia turi būti įtraukti į eilę, o tada LogStash nuskaito įrašus iš eilės iš išorės.
Todėl tuo atveju, kai serveriai yra DMZ, reikia naudoti tokią šiek tiek sudėtingą schemą. Konfigūracijos pavyzdys atrodo taip:
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. pranešimų eilė
Šis komponentas naudojamas žurnalo įrašams DMZ buferizuoti. Įrašymas atliekamas per Filebeat → LogStash krūvą. Skaitymas atliekamas iš DMZ ribų per LogStash. Veikiant per RabboitMQ, per sekundę apdorojama apie 4 tūkst.
Pranešimų maršrutas sukonfigūruojamas pagal sistemos pavadinimą, t. y. remiantis „FileBeat“ konfigūracijos duomenimis. Visi pranešimai patenka į vieną eilę. Jei dėl kokių nors priežasčių eilės paslauga bus sustabdyta, tai nepraras pranešimų: „FileBeats“ gaus ryšio klaidas ir laikinai sustabdys siuntimą. O iš eilės nuskaitantis LogStash taip pat gaus tinklo klaidas ir lauks, kol bus atkurtas ryšys. Tokiu atveju duomenys, žinoma, nebebus įrašomi į duomenų bazę.
Šios instrukcijos naudojamos eilėms kurti ir konfigūruoti:
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. Prietaisų skydeliai
Šis komponentas naudojamas stebėjimo duomenims vizualizuoti. Tokiu atveju turite įdiegti „ClickHouse“ duomenų šaltinį, skirtą „Grafana 4.6+“ papildiniui. Turėjome jį šiek tiek pakoreguoti, kad pagerintume SQL filtrų apdorojimo prietaisų skydelyje efektyvumą.
Pavyzdžiui, naudojame kintamuosius, o jei jie nenustatyti filtro lauke, tai norėtume, kad formos WHERE negeneruotų sąlygos ( uriStem = » AND uriStem != » ). Tokiu atveju ClickHouse nuskaitys stulpelį uriStem. Apskritai išbandėme įvairias parinktis ir galiausiai pataisėme papildinį (makrokomandą $valueIfEmpty), kad tuščios reikšmės atveju būtų pateikta 1, neminint paties stulpelio.
Ir dabar galite naudoti šią užklausą diagramai
$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')
kuris reiškia šį SQL (atkreipkite dėmesį, kad tušti uriStem laukai buvo konvertuoti tik į 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
išvada
„ClickHouse“ duomenų bazės atsiradimas tapo svarbiu įvykiu rinkoje. Sunku buvo įsivaizduoti, kad visiškai nemokamai akimirksniu apsiginklavome galingu ir praktišku įrankiu dirbti su dideliais duomenimis. Žinoma, didėjant poreikiams (pavyzdžiui, dalijimasis ir replikavimas į kelis serverius), schema taps sudėtingesnė. Tačiau iš pirmo įspūdžio dirbti su šia duomenų baze yra labai malonu. Matyti, kad gaminys sukurtas „žmonėms“.
Palyginti su ElasticSearch, žurnalų saugojimo ir apdorojimo sąnaudos sumažės nuo penkių iki dešimties kartų. Kitaip tariant, jei esamam duomenų kiekiui tektų sukurti kelių mašinų klasterį, tai naudojant ClickHouse mums užtenka vieno mažos galios mašinos. Taip, žinoma, ElasticSearch taip pat turi diske esančius duomenų glaudinimo mechanizmus ir kitas funkcijas, kurios gali žymiai sumažinti resursų suvartojimą, tačiau lyginant su ClickHouse, tai bus brangiau.
Be jokių specialių optimizacijų iš mūsų pusės, pagal numatytuosius nustatymus, duomenų įkėlimas ir pasirinkimas iš duomenų bazės veikia nuostabiu greičiu. Dar neturime daug duomenų (apie 200 mln. įrašų), bet pats serveris silpnas. Ateityje šį įrankį galėsime naudoti kitiems tikslams, nesusijusiems su žurnalų saugojimu. Pavyzdžiui, visapusiškai analizei, saugumo, mašininio mokymosi srityje.
Pabaigoje šiek tiek apie privalumus ir trūkumus.
Trūkumai
- Įrašai didelėmis partijomis. Viena vertus, tai yra funkcija, tačiau vis tiek turite naudoti papildomus komponentus įrašams buferizuoti. Ši užduotis ne visada lengva, bet vis tiek išsprendžiama. Ir aš norėčiau supaprastinti schemą.
- Kai kurios egzotiškos funkcijos ar naujos funkcijos dažnai sugenda naujose versijose. Tai kelia susirūpinimą, sumažinant norą atnaujinti į naują versiją. Pavyzdžiui, Kafka lentelės variklis yra labai naudinga funkcija, leidžianti tiesiogiai skaityti įvykius iš Kafka, neįdiegiant vartotojų. Tačiau, sprendžiant iš „Github“ problemų skaičiaus, vis tiek stengiamės nenaudoti šio variklio gamyboje. Tačiau jei nedarote staigių gestų į šoną ir naudojatės pagrindine funkcija, tai veikia stabiliai.
Argumentai "už"
- Nelėtėja.
- Žemas įėjimo slenkstis.
- Atviro kodo.
- Laisvas.
- Gerai svarstyklės (išardymas / replikavimas iš dėžutės)
- Įtrauktas į Ryšių ministerijos rekomenduojamą Rusijos programinės įrangos registrą.
- Oficialios „Yandex“ paramos buvimas.
Šaltinis: www.habr.com