Aleksej Lizunov, responsabile del centro competenze per i canali di servizio a distanza della direzione tecnologie informative MKB

Come alternativa allo stack ELK (ElasticSearch, Logstash, Kibana), stiamo conducendo studi sull'uso del database ClickHouse come archivio dati per i log.
In questo articolo vorremmo condividere la nostra esperienza nell'utilizzo del database ClickHouse e i risultati preliminari dopo la sperimentazione pilota. È opportuno notare subito che i risultati sono stati impressionanti.

In seguito descriveremo più nel dettaglio come abbiamo impostato il sistema e quali componenti lo compongono. Ma ora vorremmo raccontare un po' di questo database in generale e perché merita attenzione. Il database ClickHouse è un database colonnare analitico ad alte prestazioni sviluppato da Yandex. È utilizzato nei servizi di Yandex, essendo originariamente l'archivio di dati principale per Yandex.Metrica. È un sistema open-source, gratuito. Dal punto di vista di un sviluppatore, mi è sempre interessato sapere come abbiano realizzato questo sistema, dato che gestiscono dati fantastici in dimensioni. E l'interfaccia utente di Metrica è molto flessibile e veloce. Alla prima conoscenza di questo database, l'impressione è stata: “Finalmente! È stato fatto 'per le persone'! A partire dal processo di installazione fino all'invio delle query.”
Questo database ha una soglia di ingresso molto bassa. Anche uno sviluppatore di media competenza può installare questo database in pochi minuti e iniziare ad utilizzarlo. Tutto funziona in modo preciso. Anche le persone che hanno poca familiarità con Linux riescono rapidamente a gestire l'installazione e a compiere operazioni semplici. Se in passato, alla parola Big Data, Hadoop, Google BigTable, HDFS, un normale sviluppatore si immaginava un discorso su terabyte, petabyte, e che le configurazioni e lo sviluppo per questi sistemi fossero compiti per superuomini, con l'arrivo del database ClickHouse abbiamo ottenuto uno strumento semplice e chiaro per risolvere un insieme di compiti fino a quel momento inaccessibile. È sufficiente una macchina relativamente media e cinque minuti per l'installazione. Quindi abbiamo ottenuto un database come, ad esempio, MySql, ma specificamente per la memorizzazione di miliardi di record! Una sorta di super archiviatore con linguaggio SQL. È come se fosse stato dato alle persone l'arma di extraterrestri.
Sul nostro sistema di raccolta dei log
Per la raccolta delle informazioni vengono utilizzati file di log IIS delle applicazioni web in formato standard (attualmente stiamo anche lavorando al parsing dei log delle applicazioni, ma l'obiettivo principale in questa fase pilot è la raccolta dei log IIS).
Non siamo riusciti, per vari motivi, a rinunciare completamente al stack ELK, e continuiamo a utilizzare i componenti LogStash e Filebeat, che hanno dimostrato di funzionare bene e sono piuttosto affidabili e prevedibili.
Lo schema generale di logging è illustrato nell'immagine sottostante:

Una caratteristica della registrazione dei dati nel database ClickHouse è l'inserimento sporadico (una volta al secondo) di record in grandi blocchi. Questa sembra essere la parte più "problemativa" che si incontra durante la prima esperienza con il database ClickHouse: lo schema diventa leggermente più complesso.
Qui ci ha molto aiutato un plugin per LogStash, che inserisce direttamente i dati in ClickHouse. Questo componente viene implementato sullo stesso server del database. In generale, ciò non è raccomandato, ma dal punto di vista pratico, per non dover gestire server separati, ora è distribuito sullo stesso server. Non abbiamo riscontrato né crash né conflitti di risorse con il database. Inoltre, va notato che il plugin prevede un meccanismo di retry in caso di errori. In caso di errori, il plugin scrive su disco un blocco di dati che non è riuscito a inserire (il formato del file è comodo: dopo la correzione, si può facilmente reinserire il blocco corretto tramite clickhouse-client).
L'elenco completo del software utilizzato nello schema è presentato nella tabella:
Elenco del software utilizzato
Nome
Descrizione
Link al pacchetto
NGINX
Reverse-proxy per limitare l'accesso alle porte e organizzare l'autenticazione
Attualmente non utilizzato nello schema
FileBeat
Trasmissione di file di log.
(pacchetto per Windows 64bit).
LogStash
Raccoglitore di log.
Utilizzato per raccogliere log da FileBeat e anche per raccogliere log dalla coda RabbitMQ (per i server che si trovano in DMZ).
Logstash-output-clickhouse
Plugin Logstash per l'invio di log al database ClickHouse in blocchi
/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
Archiviazione dei log
Nota. A partire da agosto 2018, nel repository di Yandex sono apparse build "normali" rpm per RHEL, quindi è possibile provare a utilizzare queste. Al momento dell'installazione, stavamo utilizzando pacchetti costruiti da Altinity.
Grafana
Visualizzazione dei log. Configurazione dei dashboard
Redhat & Centos(64 Bit) – ultima versione
ClickHouse datasource per Grafana 4.6+
Plugin per Grafana con sorgente dati ClickHouse
LogStash
Router dei log da FileBeat alla coda RabbitMQ.
Nota. Sfortunatamente, FileBeat non ha un output diretto per RabbitMQ, quindi è necessario un anello intermedio sotto forma di Logstash.
RabbitMQ
Coda messaggi. Questo è un buffer di registrazioni dei log nella DMZ.
Erlang Runtime (Necessario per RabbitMQ)
Ambiente di esecuzione Erlang. Necessario per il funzionamento di RabbitMQ.
La configurazione del server con il database ClickHouse è presentata nella seguente tabella:
Nome
Valore
Nota
Configurazione
HDD: 40GB
RAM: 8GB
Processore: Core 2 2Ghz
È necessario prestare attenzione ai consigli per l'uso del database ClickHouse ()
Software di sistema comune
OS: Red Hat Enterprise Linux Server (Maipo)
JRE (Java 8)
Come si vede, è una normale workstation.
La struttura della tabella per la registrazione dei log appare come segue:
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;Utilizziamo i valori predefiniti per il partizionamento (per mesi) e la granularità dell'indice. Tutti i campi corrispondono praticamente alle registrazioni del log IIS per la registrazione delle richieste http. Si noti separatamente i campi per la memorizzazione delle etichette utm (queste vengono analizzate durante l'inserimento nella tabella dal campo della stringa di query).
Sono stati inoltre aggiunti diversi campi di sistema per memorizzare informazioni sui sistemi, componenti, server. La descrizione di questi campi è riportata di seguito nella tabella. In una tabella memorizziamo i log di diversi sistemi.
Nome
Descrizione
Esempio
fld_app_name
Nome dell'applicazione/sistema
Valori consentiti:
- site1.domain.com Sito esterno 1
- site2.domain.com Sito esterno 2
- internal-site1.domain.local Sito interno 1
site1.domain.com
fld_app_module
Modulo di sistema
Valori consentiti:
- web — Sito web
- svc — Servizio web del sito
- intgr — Servizio web di integrazione
- bo — Admin (BackOffice)
web
fld_website_name
Nome del sito in IIS
Su un server possono essere distribuiti diversi sistemi, o anche più istanze di un modulo di sistema.
web-main
fld_server_name
Nome del server
web1.domain.com
fld_log_file_name
Percorso al file di log sul server
C:\inetpub\logs\LogFiles
W3SVC1u_ex190711.log
Questo consente di costruire grafici in modo efficace in Grafana. Ad esempio, visualizzare le query dal frontend di un sistema specifico. È simile a un contatore di siti in Yandex.Metrica.
Ecco alcune statistiche sull'utilizzo del database negli ultimi due mesi.
Numero di record suddivisi per sistemi e relativi componenti
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 │
└──────────────────┴────────────────┴────────────┘
Totali:
┌─fld_app_name─┬─fld_app_module─┬─rows_count─┐
│ │ │ 210522593 │
└──────────────┴────────────────┴────────────┘
11 righe nel set. Tempo trascorso: 4.874 sec. Elaborate 210,52 milioni di righe, 421,67 MB (43,19 milioni di righe/s, 86,51 MB/s).Volume dei dati su disco
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 riga nel set. Tempo trascorso: 0.035 sec.Grado di compressione dei dati nelle colonne
SELEZIONA
nome,
formatReadableSize(data_uncompressed_bytes) COME uncompressed,
formatReadableSize(data_compressed_bytes) COME compresso,
data_uncompressed_bytes / data_compressed_bytes COME compress_ratio
DA system.columns
DOVE table = 'log_web'
┌─nome────────────────────┬─uncompressed─┬─compresso───┬─────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 righe nel set. Trascorso: 0.005 sec.Descrizione dei componenti utilizzati
FileBeat. Trasmissione dei log dei file
Questo componente monitora le modifiche nei file di log sul disco e invia le informazioni a LogStash. Si installa su tutti i server dove vengono scritti file di log (di solito, IIS). Funziona in modalità tail (cioè, invia solo le registrazioni aggiunte al file). Tuttavia, può essere impostato per inviare file interi. Questo è comodo quando è necessario caricare dati dei mesi precedenti. Basta mettere il file di log nella cartella e lo leggerà interamente.
Quando il servizio viene fermato, i dati smettono di essere trasmessi ulteriormente nel deposito.
Un esempio di configurazione appare come segue:
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. Raccolta log
Questo componente è progettato per ricevere registri dai log di FileBeat (o tramite la coda RabbitMQ), eseguire il parsing e inserire i dati a blocchi nel database ClickHouse.
Per l'inserimento in ClickHouse, si utilizza il plugin Logstash-output-clickhouse. Il plugin Logstash ha un meccanismo di retry per le richieste, ma durante una fermata programmata, è comunque meglio fermare il servizio stesso. Durante l'arresto, i messaggi si accumuleranno nella coda RabbitMQ, quindi se l'arresto è prolungato, è meglio fermare i Filebeat sui server. Nello schema in cui non si utilizza RabbitMQ (nella rete locale Filebeat invia direttamente i log a Logstash), i Filebeat funzionano in modo accettabile e sicuro, quindi per loro l'indisponibilità dell'output avviene senza conseguenze.
Un esempio di configurazione appare come segue:
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. Archivio log
I log di tutti i sistemi vengono salvati in un'unica tabella (vedi all'inizio dell'articolo). È destinata a memorizzare informazioni sulle richieste: tutti i parametri sono simili per diversi formati, ad esempio i log IIS, i log di apache e nginx. Per i log delle applicazioni, in cui vengono registrati, ad esempio, errori, messaggi informativi, avvisi, sarà prevista una tabella separata, con la struttura corrispondente (attualmente in fase di progettazione).
Nella progettazione della tabella è molto importante definire la chiave primaria (sulla quale i dati saranno ordinati durante la memorizzazione). Questo influisce sul grado di compressione dei dati e sulla velocità delle query. Nel nostro esempio, la chiave è
ORDER BY (fld_app_name, fld_app_module, logdatetime)
Cioè, in base al nome del sistema, al nome del componente del sistema e alla data dell'evento. Inizialmente, la data dell'evento era al primo posto. Dopo averla spostata all'ultimo posto, le query sono diventate circa il doppio più veloci. Modificare la chiave primaria richiederà di ricreare la tabella e ricaricare i dati, in modo che ClickHouse riordini i dati su disco. Questa è un'operazione pesante, quindi è consigliabile pianificare con largo anticipo quali dovrebbero essere inclusi nella chiave di ordinamento.
È inoltre importante notare che nelle ultime versioni è apparso il tipo di dati LowCardinality. Usandolo, si riduce drasticamente la dimensione dei dati compressi per quei campi che hanno una bassa cardinalità (poche opzioni).
Attualmente è in uso la versione 19.6 e prevediamo di provare ad aggiornare alla versione più recente. In queste versioni sono state introdotte funzionalità interessanti come la Granularità Adattiva, indici di Skipping e il codec DoubleDelta, per esempio.
Per impostazione predefinita, durante l'installazione, a livello di configurazione, è impostato il livello di registrazione trace. I log vengono ruotati e archiviati, ma si espandono fino a un gigabyte. Se non è necessario, si può impostare il livello warning, in tal caso la dimensione del log si riduce drasticamente. La configurazione della registrazione è definita nel file config.xml:
warningAlcuni comandi utili
Poiché i pacchetti di installazione originali vengono assemblati per Debian, per altre versioni di Linux è necessario utilizzare pacchetti assemblati da Altinity.
Qui puoi trovare istruzioni con collegamenti al loro repository: https://www.altinity.com/blog/2017/12/18/logstash-with-clickhouse
sudo yum search clickhouse-server
sudo yum install clickhouse-server.noarch
1. verifica dello stato
sudo systemctl status clickhouse-server
2. arresto del server
sudo systemctl stop clickhouse-server
3. avvio del server
sudo systemctl start clickhouse-server
Avvio per eseguire query in modalità multilinea (esecuzione dopo il punto e virgola ";")
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
Il plugin ClickHouse per LogStash in caso di errore su una linea salva l'intero pacchetto in un file /tmp/log_web_failed.json
Puoi correggere manualmente questo file e provare a caricarlo nel DB manualmente:
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
uscita dalla riga di comando
quit;
## Configurazione TLS
https://www.altinity.com/blog/2019/3/5/clickhouse-networking-part-2
openssl s_client -connect log.domain.com:9440 < /dev/nullLogStash. Il router dei log da FileBeat alla coda RabbitMQ
Questo componente viene utilizzato per instradare i log provenienti da FileBeat alla coda RabbitMQ. Ci sono due aspetti qui:
- Sfortunatamente, FileBeat non ha un plugin di output per scrivere direttamente in RabbitMQ. E questa funzionalità, a giudicare dai problemi sul loro GitHub, non è prevista per il futuro. Esiste un plugin per Kafka, ma per motivi specifici non possiamo usarlo.
- Ci sono requisiti per la raccolta dei log nella DMZ. In base a questi, i log devono prima essere inseriti in una coda e poi LogStash legga esternamente dalle registrazioni della coda.
Pertanto, nel caso in cui i server si trovino nella DMZ, è necessario utilizzare uno schema leggermente più complesso. Un esempio di configurazione potrebbe apparire come segue:
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. Coda di messaggi
Questo componente viene utilizzato per il buffering delle registrazioni dei log nella DMZ. La registrazione avviene attraverso la combinazione Filebeat → LogStash. La lettura avviene dall'esterno della DMZ tramite LogStash. Quando si utilizza RabbitMQ, vengono elaborate circa 4.000 messaggi al secondo.
Il routing dei messaggi è impostato in base al nome del sistema, cioè sulla base dei dati di configurazione di FileBeat. Tutti i messaggi vanno a finire in un'unica coda. Se per qualche motivo il servizio delle code viene fermato, questo non comporterà la perdita di messaggi: i FileBeat riceveranno errori di connessione e interromperanno temporaneamente l'invio. Anche LogStash, che legge dalla coda, riceverà errori di rete e attenderà il ripristino della connessione. I dati in questo caso cesseranno ovviamente di essere scritti nel database.
Le seguenti istruzioni vengono utilizzate per creare e configurare le code:
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. Dashboard
Questo componente è utilizzato per la visualizzazione dei dati di monitoraggio. È necessario installare il plugin ClickHouse datasource per Grafana 4.6+. Abbiamo dovuto modificarlo un po' per migliorare l'efficienza dell'elaborazione dei filtri SQL nel dashboard.
Ad esempio, utilizziamo variabili e se non sono impostate nel campo filtro, vorremmo che non generasse una condizione nel WHERE di tipo (uriStem = » AND uriStem != »). In tal caso, ClickHouse leggerà la colonna uriStem. In generale, abbiamo provato diverse opzioni e alla fine abbiamo modificato il plugin (macro $valueIfEmpty), in modo che nel caso di un valore vuoto restituisca 1, senza menzionare la colonna stessa.
E ora puoi utilizzare una query del genere per il grafico
$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')che si trasforma in questa SQL (si noti che i campi vuoti uriStem sono stati trasformati in semplicemente 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 ASCConclusione
L'arrivo del database ClickHouse è stato un evento significativo nel mercato. Era difficile immaginare che, del tutto gratuitamente, ci siamo dotati di uno strumento potente e pratico per lavorare con grandi volumi di dati. Certamente, con l'aumentare delle esigenze (ad esempio, sharding e replica su più server), lo schema diventerà più complesso. Ma dalle prime impressioni, lavorare con questo database è molto piacevole. È evidente che il prodotto è stato realizzato 'per le persone'.
Rispetto a ElasticSearch, i costi per la memorizzazione e l'elaborazione dei log, secondo le stime preliminari, si riducono da cinque a dieci volte. In altre parole, se per l'attuale volume di dati avremmo dovuto configurare un cluster di più macchine, utilizzando ClickHouse ci basta una sola macchina di modeste dimensioni. Sì, è ovvio che in ElasticSearch ci sono anche meccanismi di compressione dei dati su disco e altre funzionalità che consentono di ridurre significativamente il consumo di risorse, ma a confronto con ClickHouse, ciò richiederà costi maggiori.
Senza alcuna ottimizzazione speciale da parte nostra, con le impostazioni predefinite, il caricamento dei dati e le query dal database funzionano con un'incredibile rapidità. Attualmente, abbiamo pochi dati (circa 200 milioni di record), ma il server è debole. Questo strumento possiamo in futuro utilizzarlo anche per altri scopi, non legati alla memorizzazione dei log. Ad esempio, per analisi trasversali, nel campo della sicurezza, dell'apprendimento automatico.
Alla fine, un po' sui lati negativi e positivi.
Contro
- Caricamento dei record in grandi batch. Questo, da un lato, è una funzionalità, ma si devono comunque utilizzare componenti aggiuntivi per la memorizzazione temporanea dei record. Questo compito non è sempre semplice, ma è comunque risolvibile. E ci piacerebbe semplificare lo schema.
- Alcune funzionalità esotiche o nuove caratteristiche spesso si rompono nelle nuove versioni. Questo suscita preoccupazioni, riducendo la voglia di aggiornarsi all'ultima versione. Ad esempio, il motore delle tabelle Kafka è una funzionalità molto utile che consente di leggere direttamente eventi da Kafka, senza implementare consumatori. Tuttavia, a giudicare dal numero di issue su GitHub, ci asteniamo dall'usare questo motore in produzione. D'altra parte, se non si fanno movimenti bruschi e si utilizza la funzionalità principale, allora funziona in modo stabile.
Pro
- Non rallenta.
- Basso rischio di ingresso.
- Open-source.
- Gratuito.
- Si scala bene (sharding/rettifica 'out of the box')
- È presente nel registro del software russo raccomandato dal Ministero della Comunicazione.
- Presenza di supporto ufficiale da Yandex.
Fonte: habr.com
