Aleksey Lizunov, Leiter des Bereichs fĂŒr das Kompetenzzentrum der FernbedienungskanĂ€le der IT-Direktion von MKB

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

Im Folgenden werden wir detailliert beschreiben, wie unser System eingerichtet ist und aus welchen Komponenten es besteht. ZunĂ€chst möchten wir jedoch ein wenig ĂŒber diese Datenbank im Allgemeinen sprechen und warum es sich lohnt, ihr Aufmerksamkeit zu schenken. Die Datenbank ClickHouse ist eine hochleistungsfĂ€hige analytische Spalten-Datenbank von Yandex. Sie wird in den Diensten von Yandex verwendet und war ursprĂŒnglich der Hauptdatenspeicher fĂŒr Yandex.Metrik. Es handelt sich um ein Open-Source-System, das kostenlos ist. Aus der Sicht eines Entwicklers war ich immer neugierig, wie sie das umgesetzt haben, denn dort gibt es fantastisch groĂe Daten. Auch die BenutzeroberflĂ€che von Metrik ist sehr flexibel und arbeitet schnell. Bei der ersten Begegnung mit dieser Datenbank ist der Eindruck: âEndlich! Es ist âfĂŒr die Menschenâ gemacht! Vom Installationsprozess bis zur Ăbermittlung von Anfragenâ.
Diese Datenbank hat eine sehr niedrige Eintrittsbarriere. Selbst ein Entwickler mit durchschnittlichem Know-how kann diese Datenbank in wenigen Minuten installieren und nutzen. Alles funktioniert reibungslos. Selbst Personen, die mit Linux wenig vertraut sind, können die Installation ziemlich schnell bewĂ€ltigen und einfachste Operationen durchfĂŒhren. FrĂŒher hatten gewöhnliche Entwickler beim Wort Big Data, Hadoop, Google BigTable, HDFS, Vorstellungen, dass es dabei um Terabytes oder Petabytes ging und dass die Einrichtung und Entwicklung fĂŒr diese Systeme von ĂŒbermenschlichen Wesen durchgefĂŒhrt wird. Mit dem Aufkommen der Datenbank ClickHouse haben wir ein einfaches, verstĂ€ndliches Werkzeug erhalten, mit dem wir einen zuvor unerreichbaren Aufgabenbereich bewĂ€ltigen können. Es genĂŒgt eine recht bescheidene Maschine und fĂŒnf Minuten fĂŒr die Installation. Wir haben also eine Datenbank, wie z. B. MySql, aber nur fĂŒr die Speicherung von Milliarden von DatensĂ€tzen! Eine Art Superarchivator mit SQL-Sprache. Es ist, als hĂ€tten die Menschen eine Waffe von AuĂerirdischen erhalten.
Ăber unser System zur Protokollsammlung
Zur Informationssammlung werden Standardformat-Logdateien von IIS-Webanwendungen verwendet (auĂerdem beschĂ€ftigen wir uns derzeit auch mit dem Parsen von Anwendungslogs, aber unser Hauptziel in der Pilotphase ist die Sammlung von IIS-Logs).
VollstĂ€ndig auf den ELK-Stack konnten wir aus verschiedenen GrĂŒnden nicht verzichten, und wir nutzen weiterhin die Komponenten LogStash und Filebeat, die sich gut bewĂ€hrt haben und zuverlĂ€ssig sowie vorhersehbar arbeiten.
Das allgemeine Logging-Schema ist im folgenden Bild dargestellt:

Ein besonderes Merkmal der Datenspeicherung in der ClickHouse-Datenbank ist die seltene (einmal pro Sekunde) EinfĂŒgung von DatensĂ€tzen in groĂen Paketen. Dies scheint die âproblematischsteâ Komponente zu sein, mit der man beim ersten Arbeiten mit ClickHouse konfrontiert wird: das Schema wird ein wenig komplizierter.
Hier half das LogStash-Plugin sehr, das Daten direkt in ClickHouse einfĂŒgt. Dieses Modul wird auf demselben Server bereitgestellt wie die Datenbank selbst. Das sollte man eigentlich nicht machen, aber aus praktischer Sicht, um separate Server zu vermeiden, bleibt es auf demselben Server. Wir haben keine AusfĂ€lle oder Ressourcenkonflikte mit der Datenbank beobachtet. AuĂerdem ist zu erwĂ€hnen, dass das Plugin einen Retry-Mechanismus im Fehlerfall hat. Im Fehlerfall schreibt das Plugin eine Gruppe von Daten, die nicht eingefĂŒgt werden konnten, auf die Festplatte (das Dateiformat ist praktisch: nach der Korrektur kann das korrigierte Paket leicht mit dem clickhouse-client eingefĂŒgt werden).
Die vollstÀndige Liste der in dem Schema verwendeten Software ist in der Tabelle dargestellt:
Liste der verwendeten Software
Bezeichnung
Beschreibung
Link zum Distribution
NGINX
Reverse-Proxy zur ZugriffsbeschrĂ€nkung ĂŒber Ports und zur Organisation der Authentifizierung
Derzeit nicht im Schema verwendet
FileBeat
Ăbertragung von Logdateien.
(Distribution fĂŒr Windows 64bit).
LogStash
Logsammler.
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 Paketen
/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
Logspeicher
Hinweis. Seit August 2018 sind im Yandex-Repository ânormaleâ RPM-Builds fĂŒr RHEL erhĂ€ltlich, daher können diese ausprobiert werden. Zum Zeitpunkt der Installation verwendeten wir Pakete, die von Altinity erstellt wurden.
Grafana
Logvisualisierung. Dashboard-Einstellungen
Redhat & Centos(64 Bit) â die neueste Version
ClickHouse-Datenquelle fĂŒr Grafana 4.6+
Plugin fĂŒr Grafana mit der ClickHouse-Datenquelle
LogStash
Der Log-Router von FileBeat in die RabbitMQ-Warteschlange.
Hinweis. Leider gibt es bei FileBeat keinen direkten Output in RabbitMQ, daher ist ein Zwischenschritt in Form von Logstash erforderlich.
RabbitMQ
Nachrichtenwarteschlange. Dies ist ein Puffer fĂŒr LogeintrĂ€ge in der DMZ.
Erlang Runtime (Notwendig fĂŒr RabbitMQ)
Erlang-Laufzeitumgebung. Erforderlich fĂŒr die Funktion von RabbitMQ.
Die Serverkonfiguration mit der ClickHouse-Datenbank ist in der folgenden Tabelle dargestellt:
Bezeichnung
Wert
Hinweis
Konfiguration
HDD: 40GB
RAM: 8GB
Prozessor: Core 2 2Ghz
Es ist wichtig, die Hinweise zur Nutzung der 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 ganz gewöhnlichen Arbeitsplatz.
Die Tabellenstruktur zur Speicherung von Logs sieht folgendermaĂen aus:
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;Wir verwenden die Standardwerte fĂŒr die Partitionierung (monatlich) und die IndexgranularitĂ€t. Alle Felder entsprechen praktisch den LogeintrĂ€gen des IIS fĂŒr die Registrierung von HTTP-Anfragen. Besonders hervorzuheben sind die separaten Felder zur Speicherung von UTM-Parametern (diese werden beim EinfĂŒgen in die Tabelle aus dem Query-String-Feld geparst).
In der Tabelle wurden auch mehrere Systemfelder zur Speicherung von Informationen ĂŒber Systeme, Komponenten und Server hinzugefĂŒgt. Die Beschreibung dieser Felder finden Sie in der Tabelle unten. In einer Tabelle speichern wir Logs von mehreren Systemen.
Bezeichnung
Beschreibung
Beispiel
fld_app_name
Name der Anwendung/System
ZulÀssige Werte:
- site1.domain.com Externer Standort 1
- site2.domain.com Externer Standort 2
- internal-site1.domain.local Interner Standort 1
site1.domain.com
fld_app_module
Modul des Systems
ZulÀssige Werte:
- web â Webseite
- svc â Webdienst der Seite
- intgr â Integrations-Webdienst
- bo â Admin-Bereich (BackOffice)
web
fld_website_name
Name der Website im IIS
Auf einem Server können mehrere Systeme oder sogar mehrere Instanzen eines Moduls installiert sein.
web-main
fld_server_name
Servername
web1.domain.com
fld_log_file_name
Pfad zur Logdatei auf dem Server
C:\inetpub\logs\LogFiles
W3SVC1u_ex190711.log
Dies ermöglicht eine effiziente Erstellung von Grafiken in Grafana. Zum Beispiel das Betrachten von Anfragen vom Frontend eines bestimmten Systems. Es Àhnelt dem ZÀhler einer Website in Yandex.Metrica.
Hier sind einige Statistiken zur Nutzung der Datenbank ĂŒber zwei Monate.
Anzahl der EintrÀge nach Systemen und deren Komponenten
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.)Datenvolumen auf der Festplatte
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.Kompressionsrate der Daten in den Spalten
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 Zeilen im Set. Verstrichene Zeit: 0,005 Sek.Beschreibung der verwendeten Komponenten
FileBeat. Ăbertragung von Dateilogs
Diese Komponente ĂŒberwacht Ănderungen in Logdateien auf der Festplatte und ĂŒbertrĂ€gt Informationen an LogStash. Sie wird auf allen Servern installiert, auf denen Logdateien geschrieben werden (in der Regel IIS). Sie arbeitet im Tail-Modus (d. h. sie ĂŒbertrĂ€gt nur die hinzugefĂŒgten EintrĂ€ge in die Datei). Separat kann sie auch so konfiguriert werden, dass ganze Dateien ĂŒbertragen werden. Das ist praktisch, wenn Daten der vorhergehenden Monate hochgeladen werden mĂŒssen. Einfach die Logdatei in den Ordner legen und sie wird diese vollstĂ€ndig lesen.
Bei der Deaktivierung des Dienstes werden die Daten nicht mehr ins Speicher weitergeleitet.
Ein Beispiel fĂŒr die Konfiguration sieht folgendermaĂen aus:
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. Protokollsammler
Dieses Modul dient dazu, ProtokolleintrĂ€ge von FileBeat (entweder ĂŒber eine RabbitMQ-Warteschlange) zu empfangen, zu parsen und gebĂŒndelt in die ClickHouse-Datenbank einzufĂŒgen.
FĂŒr die EinfĂŒgung in ClickHouse wird das Logstash-output-clickhouse-Plugin verwendet. Logstash hat einen Mechanismus fĂŒr die Wiederholung von Anfragen, aber bei einer regulĂ€ren Deaktivierung ist es besser, den Dienst selbst zu stoppen. Bei der Deaktivierung sammeln sich Nachrichten in der RabbitMQ-Warteschlange, daher ist es besser, die Filebeats auf den Servern zu stoppen, wenn der Halt lĂ€nger dauert. In einem Setup, das RabbitMQ nicht verwendet (Filebeat sendet Protokolle direkt an Logstash innerhalb des lokalen Netzwerks), funktionieren Filebeats völlig akzeptabel und sicher, sodass ein Ausfall des Outputs keine Folgen hat.
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. Protokolldatenbank
Die Protokolle aller Systeme werden in einer Tabelle gespeichert (siehe am Anfang des Artikels). Sie dient der Speicherung von Informationen ĂŒber Anfragen: Alle Parameter sind fĂŒr verschiedene Formate Ă€hnlich, beispielsweise IIS-Protokolle, Apache- und Nginx-Protokolle. FĂŒr Anwendungsprotokolle, in denen beispielsweise Fehler, Informationen und Warnungen registriert werden, wird eine separate Tabelle mit einer entsprechenden Struktur vorgesehen (momentan in der Planungsphase).
Bei der Planung der Tabelle ist es sehr wichtig, sich auf den PrimĂ€rschlĂŒssel festzulegen (nach dem die Daten beim Speichern sortiert werden). Dies beeinflusst das MaĂ der Datenkompression und die Geschwindigkeit der Abfragen. In unserem Beispiel ist der SchlĂŒssel
ORDER BY (fld_app_name, fld_app_module, logdatetime)
d. h. nach dem Systemnamen, dem Namen der Systemkomponente und dem Datum des Ereignisses. UrsprĂŒnglich stand das Datum des Ereignisses an erster Stelle. Nachdem es an die letzte Stelle verschoben wurde, arbeiteten die Abfragen etwa doppelt so schnell. Eine Ănderung des PrimĂ€rschlĂŒssels erfordert die Neuerstellung der Tabelle und das erneute Hochladen der Daten, damit ClickHouse die Daten auf der Festplatte neu sortiert. Dies ist ein aufwendiger Vorgang, daher ist es ratsam, im Voraus genau zu ĂŒberlegen, was in den SortierschlĂŒssel aufgenommen werden soll.
Es sollte auch erwĂ€hnt werden, dass in den letzten Versionen der Datentyp LowCardinality eingefĂŒhrt wurde. Bei dessen Verwendung wird die GröĂe der komprimierten Daten fĂŒr Felder mit niedriger KardinalitĂ€t (wenig Varianten) erheblich reduziert.
Derzeit wird Version 19.6 verwendet, und wir planen, die Version auf die neueste zu aktualisieren. Darin sind groĂartige Funktionen wie Adaptive Granularity, Skipping Indices und der DoubleDelta-Codec enthalten.
Bei der Installation ist standardmĂ€Ăig das Protokollierungsniveau 'trace' in der Konfiguration festgelegt. Die Protokolle werden rotiert und archiviert, wobei sie auf bis zu einem Gigabyte erweitert werden. Wenn dies nicht notwendig ist, kann das Protokollierungsniveau auf 'warning' gesetzt werden, wodurch die GröĂe des Protokolls stark reduziert wird. Die Protokollierungseinstellungen werden in der Datei config.xml festgelegt:
warningEinige nĂŒtzliche Befehle
Da die ursprĂŒnglichen Installationspakete fĂŒr Debian zusammengestellt werden, mĂŒssen fĂŒr andere Linux-Versionen die Pakete verwendet werden, die von Altinity erstellt wurden.
Hier ist der Link zu den 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ĂŒfen des Status
sudo systemctl status clickhouse-server
2. Stoppen des Servers
sudo systemctl stop clickhouse-server
3. Starten des Servers
sudo systemctl start clickhouse-server
Starten zur AusfĂŒhrung von Abfragen im mehrzeiligen Modus (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
Das ClickHouse-Plugin fĂŒr LogStash speichert im Fall eines Fehlers in einer Zeile das gesamte Paket in der Datei /tmp/log_web_failed.json
Man kann diese Datei manuell bearbeiten und versuchen, sie manuell in die Datenbank hochzuladen:
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
Beenden 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. Der Protokollrouter von FileBeat zur RabbitMQ-Warteschlange
Diese Komponente wird zur Weiterleitung von Protokollen verwendet, die von FileBeat an die RabbitMQ-Warteschlange gesendet werden. Hier gibt es zwei Punkte:
- Leider verfĂŒgt FileBeat nicht ĂŒber ein Ausgabemodul, um direkt in RabbitMQ zu schreiben. Laut einer Anfrage auf ihrem GitHub wird eine solche FunktionalitĂ€t nicht umgesetzt. Es gibt ein Plugin fĂŒr Kafka, aber aus bestimmten GrĂŒnden können wir es bei uns nicht verwenden.
- Es gibt Anforderungen fĂŒr das Sammeln von Protokollen in der DMZ. GemÀà diesen Anforderungen mĂŒssen die Protokolle zunĂ€chst in der Warteschlange abgelegt werden, und dann liest LogStash die EintrĂ€ge von auĂen aus der Warteschlange.
Daher mĂŒssen wir fĂŒr den Fall, dass die Server in der DMZ stehen, 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 ProtokolldatensĂ€tzen in der DMZ verwendet. Das Schreiben erfolgt ĂŒber die Verbindung Filebeat â LogStash. Das Lesen erfolgt von auĂerhalb der DMZ ĂŒber LogStash. Bei der Verwendung von RabbitMQ werden etwa 4000 Nachrichten pro Sekunde verarbeitet.
Das Routing der Nachrichten erfolgt nach dem Systemnamen, d. h. basierend auf den Daten der FileBeat-Konfiguration. Alle Nachrichten landen in einer Warteschlange. Wenn der Warteschendienst aus irgendeinem Grund gestoppt wird, kommt es nicht zu einem Verlust von Nachrichten: FileBeats erhalten Verbindungsfehler und unterbrechen vorĂŒbergehend das Senden. Auch LogStash, das aus der Warteschlange liest, erhĂ€lt Netzwerkfehler und wartet, bis die Verbindung wiederhergestellt ist. Dabei werden natĂŒrlich keine Daten mehr in die Datenbank geschrieben.
Die folgenden Anweisungen werden zur Erstellung und Konfiguration von 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
Diese Komponente wird zur Visualisierung von Ăberwachungsdaten verwendet. Dazu muss das Plugin ClickHouse-Datenquelle fĂŒr Grafana 4.6+ installiert werden. 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 diese im Filterfeld nicht gesetzt sind, möchten wir, dass keine Bedingung in WHERE in der Form (uriStem = » AND uriStem != ») generiert wird. In diesem Fall wird ClickHouse die Spalte uriStem lesen. Insgesamt haben wir verschiedene Varianten ausprobiert und schlieĂlich das Plugin (Makro $valueIfEmpty) so angepasst, dass es im Falle eines leeren Wertes 1 zurĂŒckgibt, ohne die Spalte selbst zu erwĂ€hnen.
Und jetzt kann dieser 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')das sich in folgendes SQL umwandelt (bitte beachten Sie, dass leere uriStem-Felder einfach in 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
Das Erscheinen der ClickHouse-Datenbank war ein bedeutendes Ereignis auf dem Markt. Es war schwer vorstellbar, dass wir in einem Moment völlig kostenlos mit einem leistungsstarken und praktischen Werkzeug fĂŒr die Verarbeitung groĂer Daten ausgestattet wurden. SelbstverstĂ€ndlich wird das Schema mit steigenden Anforderungen (zum Beispiel Sharding und Replikation auf mehreren Servern) komplexer. Aber nach den ersten EindrĂŒcken ist die Arbeit mit dieser Datenbank sehr angenehm. Man erkennt, dass das Produkt "fĂŒr die Menschen" gemacht wurde.
Im Vergleich zu ElasticSearch werden die Kosten fĂŒr die Speicherung und Verarbeitung von Protokollen vorlĂ€ufigen SchĂ€tzungen zufolge um das FĂŒnf- bis Zehnfache reduziert. Mit anderen Worten, wenn wir fĂŒr das aktuelle Datenvolumen einen Cluster aus mehreren Maschinen einrichten mĂŒssten, ist fĂŒr die Nutzung von ClickHouse eine schwache Maschine ausreichend. Ja, natĂŒrlich gibt es auch in ElasticSearch Mechanismen zur Datenkompression auf der Festplatte und andere Funktionen, die den Ressourcenverbrauch deutlich senken, aber im Vergleich zu ClickHouse erfordern diese einen höheren Aufwand.
Ohne besondere Optimierungen von unserer Seite und mit den Standard Einstellungen arbeiten der Datenupload und die Abfragen aus der Datenbank mit erstaunlicher Geschwindigkeit. Wir haben bisher nur wenig Daten (etwa 200 Millionen DatensĂ€tze), aber der Server ist schwach. Dieses Werkzeug können wir in Zukunft auch fĂŒr andere Zwecke nutzen, die nicht mit der Speicherung von Protokollen verbunden sind, zum Beispiel fĂŒr Durchanalyse, im Sicherheitsbereich, maschinelles Lernen.
Zum Schluss ein wenig ĂŒber die Vor- und Nachteile.
Nachteile
- Das Hochladen von DatensĂ€tzen in groĂen Chargen. Dies ist einerseits ein Feature, aber es mĂŒssen trotzdem zusĂ€tzliche Komponenten zur Pufferung der DatensĂ€tze verwendet werden. Diese Aufgabe ist nicht immer einfach, aber dennoch lösbar. Und wir möchten die Struktur vereinfachen.
- Einige exotische Funktionen oder neue Features brechen oft in neuen Versionen. Das fĂŒhrt zu Bedenken und verringert den Wunsch, auf die neue Version zu aktualisieren. Zum Beispiel ist die Kafka-Tabellen-Engine ein sehr nĂŒtzliches Feature, das es ermöglicht, Ereignisse direkt aus Kafka zu lesen, ohne Konsumenten zu implementieren. Aber judging by the number of issues on GitHub, scheuen wir uns bisher, diese Engine in der Produktion zu verwenden. Wenn man jedoch keine drastischen Schritte unternimmt und nur die Grundfunktionen nutzt, funktioniert sie stabil.
Vorteile
- Bremst nicht.
- Niedriger Einstieg.
- Open Source.
- Kostenlos.
- Gut skalierbar (Sharding/Replication âout of the boxâ)
- Ist im Register der empfohlenen russischen Software des MinKomSvyaz enthalten.
- Offizielle UnterstĂŒtzung von Yandex.
Quelle: habr.com
