Alexey Lizunov, Leiter der Abteilung fĂŒr die Kompetenzzentren im Bereich der Fernbetreuungsdienste der IT-Direktion der MKB

Als Alternative zum ELK-Stack (ElasticSearch, Logstash, Kibana) fĂŒhren wir Forschungsarbeiten zur Nutzung von ClickHouse als Datenspeicher fĂŒr Logs durch.
In diesem Artikel möchten wir ĂŒber unsere Erfahrungen mit der Datenbank ClickHouse und die ersten Ergebnisse aus der Pilotphase berichten. Es ist sofort zu erwĂ€hnen, dass die Ergebnisse beeindruckend sind.

Im Folgenden werden wir nĂ€her beschreiben, wie unser System eingerichtet ist und aus welchen Komponenten es besteht. ZunĂ€chst möchten wir jedoch kurz etwas ĂŒber diese Datenbank im Allgemeinen erzĂ€hlen und warum sie Beachtung verdient. Die ClickHouse-Datenbank ist eine leistungsstarke analytische Spalten-Datenbank von Yandex. Sie wird in den Yandex-Diensten verwendet und war ursprĂŒnglich das Hauptdatenspeicher fĂŒr Yandex.Metrica. Es handelt sich um ein Open-Source-System, das kostenlos ist. Aus der Sicht eines Entwicklers war es fĂŒr mich immer interessant, wie sie das umsetzen, denn dort werden fantastisch groĂe Datenmengen verarbeitet. Auch die BenutzeroberflĂ€che von Metrica ist sehr flexibel und arbeitet schnell. Bei der ersten Begegnung mit dieser Datenbank hatte ich den Eindruck: âEndlich! Das ist 'fĂŒr die Menschen' gemacht! Vom Installationsprozess bis hin zu den Abfragen."
Diese Datenbank hat eine sehr geringe EinstiegshĂŒrde. Selbst ein Entwickler mit durchschnittlicher Qualifikation kann diese Datenbank in wenigen Minuten installieren und sofort nutzen. Alles funktioniert reibungslos. Sogar Personen, die mit Linux nicht gut vertraut sind, können die Installation relativ schnell bewĂ€ltigen und grundlegende Operationen durchfĂŒhren. FrĂŒher, wenn man Big Data, Hadoop, Google BigTable oder HDFS hörte, dachte ein gewöhnlicher Entwickler an Terabytes, Petabytes und dass die Konfiguration und Entwicklung fĂŒr diese Systeme etwas fĂŒr Ăbermenschen sei. Mit der EinfĂŒhrung der ClickHouse-Datenbank haben wir jedoch ein einfaches, verstĂ€ndliches Werkzeug erhalten, mit dem wir zuvor unlösbare Aufgaben angehen können. Man benötigt lediglich einen ziemlich einfachen Rechner und fĂŒnf Minuten fĂŒr die Installation. Das bedeutet, wir haben eine Datenbank wie beispielsweise MySQL, aber nur fĂŒr die Speicherung von Milliarden von DatensĂ€tzen! Ein gewisser Super-Archivierer mit SQL-Syntax. Es ist, als ob den Menschen die Waffen von AuĂerirdischen ĂŒbergeben wurden.
Ăber unser Log-Management-System
Zur Informationssammlung verwenden wir standardisierte IIS-Logdateien von Webanwendungen (derzeit arbeiten wir auch an der Analyse von Anwendungsprotokollen, jedoch liegt unser Hauptaugenmerk in der Pilotphase auf der Sammlung von IIS-Logs).
Aus verschiedenen GrĂŒnden konnten wir nicht vollstĂ€ndig auf das ELK-Stack verzichten, und wir setzen weiterhin die Komponenten LogStash und Filebeat ein, die sich als zuverlĂ€ssig und vorhersehbar erwiesen haben.
Das allgemeine Schema der Protokollierung ist im folgenden Bild dargestellt:

Ein besonderes Merkmal des Datenbankeintrags in ClickHouse ist die seltene (einmal pro Sekunde) EinfĂŒgung von DatensĂ€tzen in gröĂeren Paketen. Dies scheint die bisher âproblematischsteâ Herausforderung zu sein, die man bei den ersten Erfahrungen mit ClickHouse antrifft: Das Schema wird dadurch etwas komplizierter.
Hier kam das LogStash-Plugin stark zum Einsatz, das Daten direkt in ClickHouse einfĂŒgt. Dieses Modul lĂ€uft auf demselben Server wie die Datenbank selbst. Allgemein wird das nicht empfohlen, aber aus praktischer Sicht, um keine separaten Server zu schaffen, wĂ€hrend er auf demselben Server lĂ€uft, ist das vertretbar. Wir haben keine AusfĂ€lle oder Ressourcenkonflikte mit der Datenbank beobachtet. DarĂŒber hinaus ist es wichtig zu erwĂ€hnen, dass das Plugin einen Retry-Mechanismus fĂŒr Fehler implementiert hat. Im Fehlerfall schreibt das Plugin eine Datenmenge auf die Festplatte, die nicht eingefĂŒgt werden konnte (das Dateiformat ist praktisch: nach der Korrektur kann die angepasste Menge einfach mit dem clickhouse-client eingefĂŒgt werden).
Die vollstĂ€ndige Liste der verwendeten Software in der Architektur ist in der Tabelle aufgefĂŒhrt:
Liste der verwendeten Software
Titel
Beschreibung
Link zum Distributionspaket
NGINX
Reverse-Proxy zur EinschrĂ€nkung des Zugriffs ĂŒber Ports und zur Organisation der Autorisierung
Derzeit nicht in der Architektur verwendet
FileBeat
Ăbertragung von Datei-Logs.
(Distributionspaket fĂŒr Windows 64bit).
LogStash
Log-Sammler.
Wird zum Sammeln von Logs von FileBeat sowie zum Sammeln von Logs aus der RabbitMQ-Warteschlange verwendet (fĂŒr Server, die sich in der DMZ befinden).
Logstash-output-clickhouse
Logstash-Plugin zur Ăbertragung von Logs in die ClickHouse-Datenbank in Batch-Prozessen
/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
Log-Speicher
Hinweis. Seit August 2018 gibt es im Yandex-Repository "normale" RPM-Builds fĂŒr RHEL, sodass Sie diese ausprobieren können. Zum Zeitpunkt der Installation haben wir Pakete von Altinity verwendet.
Grafana
Visualisierung von Logs. Dashboard-Konfiguration
Redhat & Centos (64 Bit) â die neueste Version
ClickHouse-Datenquelle fĂŒr Grafana 4.6+
Plugin fĂŒr Grafana mit ClickHouse-Datenquelle
LogStash
Log Router von FileBeat in die RabbitMQ-Warteschlange.
Hinweis. Leider unterstĂŒtzt FileBeat keinen direkten Output in RabbitMQ, weshalb ein Zwischenschritt in Form von Logstash erforderlich ist.
RabbitMQ
Nachrichtenschlange. Dies ist ein Puffer fĂŒr Log-EintrĂ€ge in der DMZ.
Erlang-Laufzeit (Erforderlich fĂŒr RabbitMQ)
Erlang-Laufzeitumgebung. Wird fĂŒr den Betrieb von RabbitMQ benötigt.
Die Konfiguration des Servers mit der ClickHouse-Datenbank ist in der folgenden Tabelle dargestellt:
Titel
Bedeutung
Hinweis
Konfiguration
HDD: 40 GB
RAM: 8 GB
Prozessor: Core 2 2 GHz
Es ist wichtig, die Betriebshinweise fĂŒr die ClickHouse-Datenbank zu beachten ()
Allgemeine Systemsoftware
Betriebssystem: Red Hat Enterprise Linux Server (Maipo)
JRE (Java 8)
Â
Wie zu sehen ist, handelt es sich um einen normalen Arbeitsplatz.
Die Struktur der Tabelle zur Speicherung von Logs sieht folgendermaĂen aus:
log_web.sql
ERSTELLEN SIE DIE TABELLE 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)
EINSTELLUNGEN index_granularity = 8192;Wir verwenden Standardwerte fĂŒr die Partitionierung (nach Monaten) und die GranularitĂ€t des Index. Alle Felder entsprechen nahezu den IIS-Logs fĂŒr die Registrierung von HTTP-Anfragen. Besonders hervorzuheben sind die separaten Felder zur Speicherung von UTM-Markierungen (diese werden beim EinfĂŒgen in die Tabelle aus dem Abfragefeld geparst).
Die Tabelle enthĂ€lt auĂerdem mehrere Systemfelder zur Speicherung von Informationen ĂŒber Systeme, Komponenten und Server. Eine Beschreibung dieser Felder finden Sie unten in der Tabelle. In einer Tabelle speichern wir die Protokolle fĂŒr mehrere Systeme.
Titel
Beschreibung
Beispiel
fld_app_name
Name der Anwendung/des Systems
Erlaubte Werte:
- site1.domain.com Externe Website 1
- site2.domain.com Externe Website 2
- internal-site1.domain.local Interne Website 1
site1.domain.com
fld_app_module
Systemmodul
Erlaubte Werte:
- web â Webseite
- svc â Webdienst der Webseite
- intgr â Integrations-Webdienst
- bo â Adminbereich (BackOffice)
web
fld_website_name
Webseitenname in IIS
Auf einem Server können mehrere Systeme oder sogar mehrere Instanzen eines Moduls bereitgestellt werden.
web-main
fld_server_name
Servername
web1.domain.com
fld_log_file_name
Pfad zur Protokolldatei auf dem Server
C:inetpublogsLogFiles
W3SVC1u_ex190711.log
Dies ermöglicht eine effiziente Grafikerstellung in Grafana, zum Beispiel zur Ansicht von Anfragen vom Frontend eines bestimmten Systems. Es Àhnelt dem Website-ZÀhler in Yandex.Metrica.
Hier sind einige Statistiken zur Nutzung der Datenbank ĂŒber zwei Monate.
Anzahl der DatensÀtze unterteilt nach Systemen und deren Komponenten
WĂHLEN
fld_app_name,
fld_app_module,
COUNT(fld_app_name) AS rows_count
VON log_web
GRUPPIEREN NACH
fld_app_name,
fld_app_module
MIT TOTALEN
SORTIEREN NACH
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 â
ââââââââââââââââââââŽâââââââââââââââââŽâââââââââââââ
Gesamt:
ââfld_app_nameââŹâfld_app_moduleââŹârows_countââ
â â â 210522593 â
ââââââââââââââââŽâââââââââââââââââŽâââââââââââââ
11 Zeilen im Satz. Verstrichene Zeit: 4,874 Sek. Verarbeitet 210,52 Millionen Zeilen, 421,67 MB (43,19 Millionen Zeilen/s, 86,51 MB/s).Datenspeicherplatz auf der Festplatte
WĂHLEN
formatReadableSize(sum(data_uncompressed_bytes)) AS unkomprimiert,
formatReadableSize(sum(data_compressed_bytes)) AS komprimiert,
sum(rows) AS gesamtzeilen
FROM system.parts
WHERE table = 'log_web'
ââunkomprimiertââŹâkomprimiertââŹâgesamtzeilenââ
â 54,50 GiB â 4,86 GiB â 211427094 â
ââââââââââââââââŽâââââââââââââŽâââââââââââââ
1 Zeile im Set. Verstrichene Zeit: 0,035 Sek.Kompression der Daten in den Spalten
WĂHLEN
name,
formatReadableSize(data_uncompressed_bytes) AS uncompressed,
formatReadableSize(data_compressed_bytes) AS compressed,
data_uncompressed_bytes / data_compressed_bytes AS compress_ratio
VON system.columns
WO 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 Zeilen im Set. Verstrichene Zeit: 0.005 Sek.Beschreibung der verwendeten Komponenten
FileBeat. Ăbertragung von Logdateien
Dieses Modul ĂŒberwacht Ănderungen in Logdateien auf der Festplatte und ĂŒbertrĂ€gt die Informationen an LogStash. Es wird auf allen Servern installiert, wo Logdateien erzeugt werden (meistens IIS). Es arbeitet im Tail-Modus (d. h. es ĂŒbertrĂ€gt nur die hinzugefĂŒgten EintrĂ€ge in die Datei). Aber es kann auch so eingestellt werden, dass komplette Dateien ĂŒbertragen werden. Das ist praktisch, wenn Daten aus den vorherigen Monaten geladen werden mĂŒssen. Einfach die Logdatei in den Ordner legen und sie wird vollstĂ€ndig gelesen.
Beim Stoppen des Dienstes werden die Daten nicht mehr weiter an den Speicher ĂŒbertragen.
Ein Beispiel fĂŒr die Konfiguration sieht folgendermaĂen aus:
filebeat.yml
filebeat.inputs:
- typ: log
aktiviert: true
pfade:
- C:/inetpub/logs/LogFiles/W3SVC1/*.log
exclude_files: ['.gz$','.zip$']
tail_files: true
ignore_older: 24h
felder:
fld_server_name: "site1.domain.de"
fld_app_name: "site1.domain.de"
fld_app_module: "web"
fld_website_name: "web-main"
- typ: log
aktiviert: true
pfade:
- C:/inetpub/logs/LogFiles/__Import/access_log-*
exclude_files: ['.gz$','.zip$']
tail_files: false
felder:
fld_server_name: "site2.domain.de"
fld_app_name: "site2.domain.de"
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.de.cer"
ssl.key: "C:/filebeat/certs/site1.domain.de.key"
#================================ Prozessoren =====================================
processors:
- add_host_metadata: ~
- add_cloud_metadata: ~LogStash. Log-Sammler
Dieses Modul dient dazu, LogeintrĂ€ge von FileBeat (entweder ĂŒber eine RabbitMQ-Warteschlange) zu empfangen, sie zu parsen und gebĂŒndelt in die ClickHouse-Datenbank einzufĂŒgen.
FĂŒr die Integration in ClickHouse wird das Plugin Logstash-output-clickhouse verwendet. Das Logstash-Plugin verfĂŒgt ĂŒber einen Mechanismus zur Wiederholung von Anfragen, jedoch ist es besser, den Dienst bei einer regulĂ€ren Stilllegung vollstĂ€ndig anzuhalten. Bei einer Stilllegung sammeln sich Nachrichten in der RabbitMQ-Warteschlange, daher ist es ratsam, die Filebeats auf den Servern ebenfalls anzuhalten, wenn die Stilllegung lĂ€ngere Zeit in Anspruch nimmt. In einem Schema, in dem RabbitMQ nicht verwendet wird (Filebeat sendet die Protokolle direkt an Logstash im lokalen Netzwerk), funktionieren die Filebeats recht gut und sicher, sodass ein Ausfall des Outputs fĂŒr sie ohne Folgen bleibt.
Ein Beispiel fĂŒr die Konfiguration sieht folgendermaĂen aus:
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. Log-Speicher
Logs aus allen Systemen werden in einer einzigen Tabelle gespeichert (siehe zu Beginn des Artikels). Diese dient der Speicherung von Informationen ĂŒber Anfragen: Alle Parameter sind fĂŒr verschiedene Formate Ă€hnlich, zum Beispiel IIS-Logs, Apache- und Nginx-Logs. FĂŒr Anwendungslogs, in denen beispielsweise Fehler, Informationsmeldungen und Warnungen registriert werden, wird eine separate Tabelle mit der entsprechenden Struktur vorgesehen (derzeit in der Planungsphase).
Bei der Planung der Tabelle ist es sehr wichtig, sich fĂŒr den PrimĂ€rschlĂŒssel zu entscheiden (nach dem die Daten bei der Speicherung sortiert werden). Dies beeinflusst die Kompressionsrate der Daten und die Geschwindigkeit der Abfragen. In unserem Beispiel ist der SchlĂŒssel
ORDER BY (fld_app_name, fld_app_module, logdatetime)
Das bedeutet, dass es sich um den Systemnamen, den Namen der Systemkomponente und das Ereignisdatum handelt. UrsprĂŒnglich stand das Ereignisdatum an erster Stelle. Nachdem es an die letzte Stelle verschoben wurde, arbeiten die Abfragen etwa doppelt so schnell. Eine Ănderung des PrimĂ€rschlĂŒssels erfordert das erneute Erstellen der Tabelle und das Hochladen der Daten, damit ClickHouse die Daten auf der Festplatte neu sortiert. Dies ist ein aufwendiger Prozess, daher ist es ratsam, im Voraus gut zu ĂŒberlegen, was in den SortierschlĂŒssel aufgenommen werden soll.
Es ist auch wichtig zu erwĂ€hnen, dass in den letzten Versionen der Datentyp LowCardinality hinzugekommen ist. Bei Verwendung dieses Typs wird die GröĂe der komprimierten Daten fĂŒr Felder mit geringer KardinalitĂ€t (wenig Varianten) erheblich reduziert.
Derzeit verwenden wir Version 19.6 und planen, ein Upgrade auf die neueste Version zu versuchen. Diese Versionen bieten groĂartige Funktionen wie Adaptive Granularity, Skipping Indices und den DoubleDelta-Codec.
Bei der Installation ist standardmĂ€Ăig der Logging-Level auf Trace eingestellt. Logs werden rotiert und archiviert, können jedoch bis zu einem Gigabyte anwachsen. Wenn dies nicht notwendig ist, kann der Level auf Warning gesetzt werden, wodurch die Log-GröĂe erheblich reduziert wird. Die Logging-Konfiguration wird in der Datei config.xml festgelegt:
warningEinige nĂŒtzliche Befehle
Da die Original-Installationspakete fĂŒr Debian zusammengestellt werden, mĂŒssen fĂŒr andere Linux-Versionen die von Altinity erstellten Pakete verwendet werden.
Hier sind die Anleitungen mit Links zu ihrem Repository: https://www.altinity.com/blog/2017/12/18/logstash-with-clickhouse
sudo yum search clickhouse-server
sudo yum install clickhouse-server.noarch
1. ĂberprĂŒfung des Status
sudo systemctl status clickhouse-server
2. Server stoppen
sudo systemctl stop clickhouse-server
3. Server starten
sudo systemctl start clickhouse-server
Start fĂŒr die AusfĂŒhrung von Abfragen im Mehrzeilenmodus (auszufĂŒhren nach dem Zeichen ";")
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
Der ClickHouse-Plugin fĂŒr Logstash speichert im Falle eines Fehlers in einer Zeile die gesamte Batch in der Datei /tmp/log_web_failed.json.
Diese Datei kann manuell korrigiert und dann manuell in die Datenbank hochgeladen werden:
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
Verlassen der Eingabeaufforderung
quit;
## TLS-Konfiguration
https://www.altinity.com/blog/2019/3/5/clickhouse-networking-part-2
openssl s_client -connect log.domain.com:9440 < /dev/nullLogStash. Logrouter von FileBeat zur RabbitMQ-Warteschlange
Dieses Komponent wird zur Routen von Logs verwendet, die von FileBeat in die RabbitMQ-Warteschlange eingehen. Hier sind zwei Aspekte:
- Leider hat FileBeat kein Output-Plugin, um direkt in RabbitMQ zu schreiben. Laut einem Issue auf ihrem GitHub ist eine solche FunktionalitĂ€t nicht in Planung. Es gibt ein Plugin fĂŒr Kafka, aber aus bestimmten GrĂŒnden können wir dies bei uns nicht verwenden.
- Es gibt Anforderungen zum Sammeln von Logs in der DMZ. Dementsprechend mĂŒssen die Logs zuerst in eine Warteschlange gelegt werden, aus der LogStash dann extern die EintrĂ€ge ausliest.
FĂŒr den Fall, dass Server in der DMZ platziert sind, mĂŒssen wir daher ein etwas komplizierteres Schema verwenden. Ein Beispiel fĂŒr die Konfiguration sieht folgendermaĂen aus:
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. Nachrichtenwarteschlange
Diese Komponente wird zur Pufferung von ProtokolleintrĂ€gen in der DMZ verwendet. Die Aufzeichnung erfolgt ĂŒber die Verbindung Filebeat â LogStash. Das Lesen erfolgt von auĂerhalb der DMZ ĂŒber LogStash. Bei der Nutzung ĂŒber RabbitMQ werden etwa 4.000 Nachrichten pro Sekunde verarbeitet.
Das Routing der Nachrichten ist anhand des Systems konfiguriert, d. h. basierend auf den Daten der FileBeat-Konfiguration. Alle Nachrichten gelangen in eine Warteschlange. Sollte aus irgendeinem Grund der Warteschdienst gestoppt werden, fĂŒhrt das nicht zum Verlust von Nachrichten: FileBeat wird Verbindungsfehler erhalten und die Ăbermittlung vorĂŒbergehend aussetzen. Auch LogStash, das aus der Warteschlange liest, wird Netzwerkfehler erhalten und warten, bis die Verbindung wiederhergestellt ist. Zu diesem Zeitpunkt wird jedoch nicht mehr in die Datenbank geschrieben.
Die folgenden Anweisungen werden zur Erstellung und Konfiguration der Warteschlangen verwendet:
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. Dashboards
Dieses Modul wird zur Visualisierung von Ăberwachungsdaten verwendet. Dazu ist es erforderlich, das Plugin ClickHouse-Datenquelle fĂŒr Grafana 4.6+ zu installieren. Wir mussten es ein wenig anpassen, um die Effizienz der Verarbeitung von SQL-Filtern im Dashboard zu erhöhen.
Zum Beispiel verwenden wir Variablen, und wenn sie nicht im Filterfeld festgelegt sind, möchten wir, dass keine Bedingung in der WHERE-Klausel generiert wird, die wie ( uriStem = '' AND uriStem != '' ) aussieht. In diesem Fall wird ClickHouse die Spalte uriStem lesen. Insgesamt haben wir verschiedene AnsĂ€tze ausprobiert und schlieĂlich das Plugin (Makro $valueIfEmpty) so angepasst, dass bei einem leeren Wert 1 zurĂŒckgegeben wird, ohne die Spalte selbst zu erwĂ€hnen.
Und jetzt kann die folgende Abfrage fĂŒr das Diagramm verwendet werden
$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')die sich in folgendes SQL umwandelt (beachten Sie, dass leere felder uriStem zu einfach 1 umgewandelt wurden)
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 ASCFazit
Die EinfĂŒhrung von ClickHouse war ein Meilenstein auf dem Markt. Es war kaum vorstellbar, dass wir im Handumdrehen mit einem leistungsstarken und praktischen Werkzeug fĂŒr die Arbeit mit groĂen Daten ausgestattet wĂ€ren â und das völlig kostenlos. NatĂŒrlich wird die Struktur komplizierter, wenn die Anforderungen steigen (zum Beispiel Sharding und Replikation auf mehrere Server). Aber schon beim ersten Eindruck macht die Arbeit mit dieser Datenbank wirklich Freude. Man merkt, dass das Produkt "fĂŒr die Menschen" entwickelt wurde.
Im Vergleich zu ElasticSearch werden die Kosten fĂŒr die Speicherung und Verarbeitung von Logs SchĂ€tzungen zufolge um das FĂŒnf- bis Zehnfache gesenkt. Mit anderen Worten, wĂ€hrend wir fĂŒr das aktuelle Datenvolumen einen Cluster aus mehreren Maschinen einrichten mĂŒssten, genĂŒgt bei der Verwendung von ClickHouse eine einzelne, leistungsschwache Maschine. Ja, in ElasticSearch gibt es auch Datenkomprimierungsmechanismen und andere Funktionen, die den Ressourcenverbrauch merklich reduzieren können, aber im Vergleich zu ClickHouse sind die Kosten dafĂŒr erheblich höher.
Ohne spezielle Optimierungen von unserer Seite und mit den Standard-Einstellungen funktionieren Datenladungen und Abfragen aus der Datenbank mit beeindruckender Geschwindigkeit. Aktuell haben wir nur wenige Daten (etwa 200 Millionen DatensĂ€tze), aber der Server ist schwach. Dieses Werkzeug können wir in Zukunft auch fĂŒr andere Zwecke verwenden, die nicht mit der Speicherung von Protokollen zusammenhĂ€ngen. Zum Beispiel fĂŒr durchgehende Analysen, Sicherheitsanwendungen oder maschinelles Lernen.
Am Ende ein wenig ĂŒber Vor- und Nachteile.
Nachteile
- Das Laden von DatensĂ€tzen in groĂen Paketen. Das ist einerseits eine Funktion, doch man muss zusĂ€tzliche Komponenten zur Pufferung der DatensĂ€tze nutzen. Diese Aufgabe ist nicht immer einfach, aber dennoch lösbar. Ich wĂŒrde mir wĂŒnschen, die Struktur zu vereinfachen.
- Einige exotische Funktionen oder neue Features brechen in neuen Versionen oft. Dies fĂŒhrt zu Bedenken und verringert die Bereitschaft, auf eine neue Version zu aktualisieren. Zum Beispiel ist die Kafka-Tabellen-Engine ein sehr nĂŒtzliches Feature, das ermöglicht, Ereignisse direkt aus Kafka zu lesen, ohne Consumer implementieren zu mĂŒssen. Aber angesichts der Anzahl der Issues auf GitHub sind wir vorsichtig, diese Engine in der Produktion zu verwenden. Allerdings, solange man keine drastischen Ănderungen vornimmt und die Hauptfunktionen nutzt, funktioniert sie stabil.
Vorteile
- Stört nicht.
- Geringe EinstiegshĂŒrde.
- Open-Source.
- Kostenlos.
- Gut skalierbar (Sharding/Replikation âout of the boxâ).
- Ist im Register der von MinComSvyaz empfohlenen russischen Software aufgefĂŒhrt.
- Offizielle UnterstĂŒtzung von Yandex verfĂŒgbar.
Quelle: habr.com
