Aleksey Lizunov, Jefe del Centro de Competencia para Canales de Servicio Remoto de la Dirección de Tecnologías de la Información del MKB
Como alternativa a la pila ELK (ElasticSearch, Logstash, Kibana), estamos investigando el uso de la base de datos ClickHouse como almacén de datos para registros.
En este artículo, nos gustaría hablar sobre nuestra experiencia en el uso de la base de datos ClickHouse y los resultados preliminares de la operación piloto. Cabe señalar de inmediato que los resultados fueron impresionantes.
A continuación, describiremos con más detalle cómo está configurado nuestro sistema y de qué componentes consta. Pero ahora me gustaría hablar un poco sobre esta base de datos en su conjunto y por qué vale la pena prestarle atención. La base de datos ClickHouse es una base de datos columnar analítica de alto rendimiento de Yandex. Se utiliza en los servicios de Yandex, inicialmente es el principal almacenamiento de datos para Yandex.Metrica. Sistema de código abierto, gratuito. Desde el punto de vista de un desarrollador, siempre me he preguntado cómo lo implementaron, porque hay un gran volumen de datos fantástico. Y la propia interfaz de usuario de Metrica es muy flexible y rápida. Al conocer por primera vez esta base de datos, la impresión es: “¡Bueno, finalmente! ¡Hecho para la gente! Comenzando desde el proceso de instalación y terminando con el envío de solicitudes.
Esta base de datos tiene un umbral de entrada muy bajo. Incluso un desarrollador con habilidades promedio puede instalar esta base de datos en unos minutos y comenzar a usarla. Todo funciona con claridad. Incluso las personas que son nuevas en Linux pueden manejar rápidamente la instalación y realizar las operaciones más simples. Si antes, con las palabras Big Data, Hadoop, Google BigTable, HDFS, un desarrollador ordinario tenía ideas de que se trataba de algunos terabytes, petabytes, que algunos superhumanos se dedican a la configuración y el desarrollo de estos sistemas, entonces con el advenimiento de ClickHouse base de datos, obtuvimos una herramienta simple y comprensible con la que puede resolver una gama de tareas previamente inalcanzable. Solo se necesita una máquina bastante promedio y cinco minutos para instalar. Es decir, obtuvimos una base de datos como, por ejemplo, MySql, ¡pero solo para almacenar miles de millones de registros! Cierto súper-archivador con el lenguaje SQL. Es como si a la gente se le entregaran las armas de los extraterrestres.
Acerca de nuestro sistema de registro
Para recopilar información, se utilizan archivos de registro de IIS de aplicaciones web de formato estándar (actualmente también estamos analizando registros de aplicaciones, pero el objetivo principal en la etapa piloto es recopilar registros de IIS).
Por varias razones, no pudimos abandonar por completo la pila ELK y continuamos usando los componentes LogStash y Filebeat, que han demostrado su eficacia y funcionan de manera bastante confiable y predecible.
El esquema general de registro se muestra en la siguiente figura:
Una característica de la escritura de datos en la base de datos de ClickHouse es la inserción poco frecuente (una vez por segundo) de registros en grandes lotes. Aparentemente, esta es la parte más “problemática” con la que te encuentras cuando trabajas por primera vez con la base de datos de ClickHouse: el esquema se vuelve un poco más complicado.
El complemento para LogStash, que inserta datos directamente en ClickHouse, ayudó mucho aquí. Este componente se implementa en el mismo servidor que la propia base de datos. Entonces, en términos generales, no se recomienda hacerlo, pero desde un punto de vista práctico, para no producir servidores separados mientras se implementa en el mismo servidor. No observamos ninguna falla o conflicto de recursos con la base de datos. Además, cabe señalar que el complemento tiene un mecanismo de reintento en caso de errores. Y en caso de errores, el complemento escribe en el disco un lote de datos que no se pudo insertar (el formato de archivo es conveniente: después de editar, puede insertar fácilmente el lote corregido usando clickhouse-client).
En la tabla se presenta una lista completa del software utilizado en el esquema:
Lista de programas utilizados
nombre
Descripción
Enlace de distribución
Nginx
Proxy inverso para restringir el acceso por puertos y organizar la autorización
Actualmente no se utiliza en el esquema
ArchivoBeat
Transferencia de registros de archivos.
Log Stash
Recolector de troncos.
Se utiliza para recopilar registros de FileBeat, así como para recopilar registros de la cola de RabbitMQ (para servidores que se encuentran en la DMZ).
Logstash-salida-clickhouse
Complemento de Loagstash para transferir registros a la base de datos de ClickHouse en lotes
/usr/share/logstash/bin/logstash-plugin instalar logstash-salida-clickhouse
/usr/share/logstash/bin/logstash-plugin instalar logstash-filter-prune
/usr/share/logstash/bin/logstash-plugin instalar logstash-filter-multiline
casa de clics
Almacenamiento de registros
Nota. A partir de agosto de 2018, aparecieron compilaciones de rpm "normales" para RHEL en el repositorio de Yandex, por lo que puede intentar usarlas. En el momento de la instalación, estábamos usando paquetes creados por Altinity.
Grafana
Visualización de registros. Configuración de paneles
Redhat y Centos (64 bits) - última versión
Fuente de datos ClickHouse para Grafana 4.6+
Complemento para Grafana con fuente de datos ClickHouse
Log Stash
Inicie sesión en el enrutador de FileBeat a la cola de RabbitMQ.
Nota. Desafortunadamente, FileBeat no tiene una salida directa a RabbitMQ, por lo que se requiere un enlace intermedio en forma de Logstash.
RabbitMQ
cola de mensajes. Este es el búfer de registro en la DMZ
Tiempo de ejecución de Erlang (requerido para RabbitMQ)
Tiempo de ejecución de Erlang. Requerido para que RabbitMQ funcione
La configuración del servidor con la base de datos de ClickHouse se presenta en la siguiente tabla:
nombre
Valor
Nota
Configuración
HDD: 40GB
RAM: 8GB
Procesador: Núcleo 2 2Ghz
Es necesario prestar atención a los consejos para operar la base de datos de ClickHouse (
Software general del sistema
SO: Servidor Red Hat Enterprise Linux (Maipo)
JRE (Java 8)
Como puede ver, esta es una estación de trabajo ordinaria.
La estructura de la tabla para almacenar registros es la siguiente:
registro_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;
Utilizamos partición predeterminada (por mes) y granularidad de índice. Todos los campos corresponden prácticamente a las entradas de registro de IIS para registrar solicitudes http. Por separado, observamos que hay campos separados para almacenar etiquetas utm (se analizan en la etapa de inserción en la tabla desde el campo de cadena de consulta).
Además, se han agregado varios campos del sistema a la tabla para almacenar información sobre sistemas, componentes y servidores. Consulte la siguiente tabla para obtener una descripción de estos campos. En una tabla, almacenamos registros para varios sistemas.
nombre
Descripción
ejemplo
fld_app_name
Nombre de aplicación/sistema
Valores válidos:
- sitio1.dominio.com Sitio externo 1
- sitio2.dominio.com Sitio externo 2
- internal-site1.domain.local Sitio interno 1
sitio1.dominio.com
fld_app_module
Módulo del sistema
Valores válidos:
- web - sitio web
- svc - Servicio de sitio web
- intgr - Servicio web de integración
- bo - Administrador (BackOffice)
web
fld_sitio_web_nombre
Nombre del sitio en IIS
Se pueden implementar varios sistemas en un servidor, o incluso varias instancias de un módulo de sistema
web principal
fld_nombre_servidor
Nombre del servidor
web1.dominio.com
fld_log_nombre_archivo
Ruta al archivo de registro en el servidor
C:inetpublogsArchivos de registro
W3SVC1u_ex190711.log
Esto le permite construir gráficos de manera eficiente en Grafana. Por ejemplo, ver solicitudes desde la interfaz de un sistema en particular. Esto es similar al contador del sitio en Yandex.Metrica.
Aquí hay algunas estadísticas sobre el uso de la base de datos durante dos meses.
Número de registros desglosados por sistemas y sus componentes
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.)
La cantidad de datos en el 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 rows in set. Elapsed: 0.035 sec.
Grado de compresión de datos en columnas
SELECT
name,
formatReadableSize(data_uncompressed_bytes) AS uncompressed,
formatReadableSize(data_compressed_bytes) AS compressed,
data_uncompressed_bytes / data_compressed_bytes AS compress_ratio
FROM system.columns
WHERE table = 'log_web'
┌─name───────────────────┬─uncompressed─┬─compressed─┬─────compress_ratio─┐
│ logdate │ 401.53 MiB │ 1.80 MiB │ 223.16665968777315 │
│ logdatetime │ 803.06 MiB │ 35.91 MiB │ 22.363966401202305 │
│ fld_log_file_name │ 220.66 MiB │ 2.60 MiB │ 84.99905736932571 │
│ fld_server_name │ 201.54 MiB │ 50.63 MiB │ 3.980924816977078 │
│ fld_app_name │ 201.17 MiB │ 969.17 KiB │ 212.55518183686877 │
│ fld_app_module │ 201.17 MiB │ 968.60 KiB │ 212.67805817411906 │
│ fld_website_name │ 201.54 MiB │ 1.24 MiB │ 162.7204926761546 │
│ serverIP │ 201.54 MiB │ 50.25 MiB │ 4.010824061219731 │
│ method │ 201.53 MiB │ 43.64 MiB │ 4.617721053304486 │
│ uriStem │ 5.13 GiB │ 832.51 MiB │ 6.311522291936919 │
│ uriQuery │ 2.58 GiB │ 501.06 MiB │ 5.269731450124478 │
│ port │ 803.06 MiB │ 3.98 MiB │ 201.91673864241824 │
│ username │ 318.08 MiB │ 26.93 MiB │ 11.812513794583598 │
│ clientIP │ 2.35 GiB │ 82.59 MiB │ 29.132328640073343 │
│ clientRealIP │ 2.49 GiB │ 465.05 MiB │ 5.478382297052563 │
│ userAgent │ 18.34 GiB │ 764.08 MiB │ 24.57905114484208 │
│ referer │ 14.71 GiB │ 1.37 GiB │ 10.736792723669906 │
│ response │ 803.06 MiB │ 83.81 MiB │ 9.582334090987247 │
│ subresponse │ 399.87 MiB │ 1.83 MiB │ 218.4831068635027 │
│ win32response │ 407.86 MiB │ 7.41 MiB │ 55.050315514606815 │
│ timetaken │ 1.57 GiB │ 402.06 MiB │ 3.9947395692010637 │
│ uriQuery__utm_medium │ 208.17 MiB │ 12.29 MiB │ 16.936148912472955 │
│ uriQuery__utm_source │ 215.18 MiB │ 13.00 MiB │ 16.548367623199912 │
│ uriQuery__utm_campaign │ 381.46 MiB │ 37.94 MiB │ 10.055156353418509 │
│ uriQuery__utm_term │ 231.82 MiB │ 10.78 MiB │ 21.502540454070672 │
│ uriQuery__utm_content │ 441.34 MiB │ 87.60 MiB │ 5.038260760449327 │
│ uriQuery__yclid │ 216.88 MiB │ 16.58 MiB │ 13.07721335008116 │
│ uriQuery__region │ 204.35 MiB │ 9.49 MiB │ 21.52661903446796 │
└────────────────────────┴──────────────┴────────────┴────────────────────┘
28 rows in set. Elapsed: 0.005 sec.
Descripción de los componentes usados
FileBeat. Transferir registros de archivos
Este componente rastrea los cambios en los archivos de registro en el disco y pasa la información a LogStash. Instalado en todos los servidores donde se escriben los archivos de registro (generalmente IIS). Funciona en modo cola (es decir, transfiere solo los registros agregados al archivo). Pero por separado se puede configurar para transferir archivos completos. Esto es útil cuando necesita descargar datos de meses anteriores. Simplemente coloque el archivo de registro en una carpeta y lo leerá en su totalidad.
Cuando se detiene el servicio, los datos ya no se transfieren más al almacenamiento.
Una configuración de ejemplo se ve así:
archivobeat.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: ~
almacenamiento de registros Recolector de registros
Este componente está diseñado para recibir entradas de registro de FileBeat (oa través de la cola de RabbitMQ), analizando e insertando lotes en la base de datos de ClickHouse.
Para la inserción en ClickHouse, se utiliza el complemento Logstash-output-clickhouse. El complemento Logstash tiene un mecanismo de reintento de solicitud, pero con un apagado regular, es mejor detener el servicio en sí. Cuando se detenga, los mensajes se acumularán en la cola de RabbitMQ, por lo que si la detención es prolongada, es mejor detener Filebeats en los servidores. En un esquema en el que no se utiliza RabbitMQ (en la red local, Filebeat envía directamente los registros a Logstash), Filebeats funciona de manera bastante aceptable y segura, por lo que para ellos la falta de disponibilidad de la salida pasa sin consecuencias.
Una configuración de ejemplo se ve así:
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"
}
}
}
tuberías.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"
casa de clics. Almacenamiento de registros
Los registros de todos los sistemas se almacenan en una tabla (ver al principio del artículo). Está destinado a almacenar información sobre solicitudes: todos los parámetros son similares para diferentes formatos, como registros de IIS, registros de apache y nginx. Para los logs de la aplicación, en los que se registran, por ejemplo, errores, mensajes de información, advertencias, se proporcionará una tabla separada con la estructura adecuada (actualmente en la etapa de diseño).
Al diseñar una tabla, es muy importante decidir la clave principal (según la cual se ordenarán los datos durante el almacenamiento). El grado de compresión de datos y la velocidad de consulta dependen de esto. En nuestro ejemplo, la clave es
ORDENAR POR (fld_app_name, fld_app_module, logdatetime)
Es decir, por el nombre del sistema, el nombre del componente del sistema y la fecha del evento. Inicialmente, la fecha del evento fue lo primero. Después de moverlo al último lugar, las consultas comenzaron a funcionar aproximadamente el doble de rápido. Cambiar la clave principal requerirá volver a crear la tabla y recargar los datos para que ClickHouse vuelva a ordenar los datos en el disco. Esta es una operación pesada, por lo que es una buena idea pensar mucho sobre lo que debe incluirse en la clave de ordenación.
También se debe tener en cuenta que el tipo de datos LowCardinality ha aparecido relativamente en versiones recientes. Al usarlo, el tamaño de los datos comprimidos se reduce drásticamente para aquellos campos que tienen baja cardinalidad (pocas opciones).
La versión 19.6 está actualmente en uso y planeamos intentar actualizar a la última versión. Tienen características tan maravillosas como la granularidad adaptativa, los índices de omisión y el códec DoubleDelta, por ejemplo.
De forma predeterminada, durante la instalación, el nivel de registro se establece en seguimiento. Los registros se rotan y archivan, pero al mismo tiempo se expanden hasta un gigabyte. Si no es necesario, puede establecer el nivel de advertencia, luego el tamaño del registro se reduce drásticamente. La configuración de registro se establece en el archivo config.xml:
<!-- Possible levels: https://github.com/pocoproject/poco/blob/develop/Foundation/include/Poco/Logger. h#L105 -->
<level>warning</level>
Algunos comandos útiles
Поскольку оригинальные пакеты установки собираются по Debian, то для других версий Linux необходимо использовать пакеты собранные компанией Altinity.
Вот по этой ссылке есть инструкции с ссылками на их репозиторий: https://www.altinity.com/blog/2017/12/18/logstash-with-clickhouse
sudo yum search clickhouse-server
sudo yum install clickhouse-server.noarch
1. проверка статуса
sudo systemctl status clickhouse-server
2. остановка сервера
sudo systemctl stop clickhouse-server
3. запуск сервера
sudo systemctl start clickhouse-server
Запуск для выполнения запросов в многострочном режиме (выполнение после знака ";")
clickhouse-client --multiline
clickhouse-client --multiline --host 127.0.0.1 --password pa55w0rd
clickhouse-client --multiline --host 127.0.0.1 --port 9440 --secure --user default --password pa55w0rd
Плагин кликлауза для логстеш в случае ошибки в одной строке сохраняет всю пачку в файл /tmp/log_web_failed.json
Можно вручную исправить этот файл и попробовать залить его в БД вручную:
clickhouse-client --host 127.0.0.1 --password password --query="INSERT INTO log_web FORMAT JSONEachRow" < /tmp/log_web_failed__fixed.json
sudo mv /etc/logstash/tmp/log_web_failed.json /etc/logstash/tmp/log_web_failed__fixed.json
sudo chown user_dev /etc/logstash/tmp/log_web_failed__fixed.json
sudo clickhouse-client --host 127.0.0.1 --password password --query="INSERT INTO log_web FORMAT JSONEachRow" < /etc/logstash/tmp/log_web_failed__fixed.json
sudo mv /etc/logstash/tmp/log_web_failed__fixed.json /etc/logstash/tmp/log_web_failed__fixed_.json
выход из командной строки
quit;
## Настройка TLS
https://www.altinity.com/blog/2019/3/5/clickhouse-networking-part-2
openssl s_client -connect log.domain.com:9440 < /dev/null
almacenamiento de registros Registrar el enrutador de FileBeat a la cola de RabbitMQ
Este componente se usa para enrutar registros provenientes de FileBeat a la cola de RabbitMQ. Hay dos puntos aquí:
- Desafortunadamente, FileBeat no tiene un complemento de salida para escribir directamente en RabbitMQ. Y dicha funcionalidad, a juzgar por el problema en su github, no está planificada para su implementación. Hay un complemento para Kafka, pero por alguna razón no podemos usarlo en casa.
- Existen requisitos para recopilar registros en la DMZ. Según ellos, los registros primero deben agregarse a la cola y luego LogStash lee las entradas de la cola desde el exterior.
Por lo tanto, es en el caso de que los servidores estén ubicados en la DMZ que uno tiene que usar un esquema un poco complicado. Una configuración de ejemplo se ve así:
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
}
}
ConejoMQ. cola de mensajes
Este componente se utiliza para almacenar en búfer las entradas de registro en la DMZ. La grabación se realiza a través de un montón de Filebeat → LogStash. La lectura se realiza desde fuera de la DMZ a través de LogStash. Al operar a través de RabboitMQ, se procesan alrededor de 4 mil mensajes por segundo.
El enrutamiento de mensajes se configura por nombre del sistema, es decir, en función de los datos de configuración de FileBeat. Todos los mensajes van a una cola. Si por algún motivo se detiene el servicio de cola, esto no provocará la pérdida de mensajes: FileBeats recibirá errores de conexión y suspenderá temporalmente el envío. Y LogStash que lee de la cola también recibirá errores de red y esperará a que se restablezca la conexión. En este caso, los datos, por supuesto, ya no se escribirán en la base de datos.
Las siguientes instrucciones se utilizan para crear y configurar colas:
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. Tableros
Este componente se utiliza para visualizar los datos de seguimiento. En este caso, debe instalar la fuente de datos ClickHouse para el complemento Grafana 4.6+. Tuvimos que modificarlo un poco para mejorar la eficiencia del procesamiento de filtros SQL en el tablero.
Por ejemplo, usamos variables, y si no están configuradas en el campo de filtro, nos gustaría que no generara una condición en el WHERE del formulario ( uriStem = » AND uriStem != » ). En este caso, ClickHouse leerá la columna uriStem. En general, probamos diferentes opciones y finalmente corregimos el complemento (la macro $valueIfEmpty) para que, en el caso de un valor vacío, devuelva 1, sin mencionar la columna en sí.
Y ahora puedes usar esta consulta para el gráfico.
$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')
que se traduce a este SQL (tenga en cuenta que los campos vacíos de uriStem se han convertido en solo 1)
SELECT
t,
groupArray((response, c)) AS groupArr
FROM (
SELECT
(intDiv(toUInt32(logdatetime), 60) * 60) * 1000 AS t, response,
count(*) AS c FROM default.log_web
WHERE (logdate >= toDate(1565061982)) AND (logdatetime >= toDateTime(1565061982)) AND 1 AND (fld_app_name = 'site1.domain.ru') AND (fld_app_module = 'web') AND 1 AND 1 AND 1
GROUP BY
t, response
ORDER BY
t ASC,
response ASC
)
GROUP BY t ORDER BY t ASC
Conclusión
La aparición de la base de datos ClickHouse se ha convertido en un hito en el mercado. Era difícil imaginar que, de forma totalmente gratuita, en un instante dispusiéramos de una potente y práctica herramienta para trabajar con big data. Por supuesto, con el aumento de las necesidades (por ejemplo, fragmentación y replicación en varios servidores), el esquema se volverá más complicado. Pero a primera vista, trabajar con esta base de datos es muy agradable. Se puede ver que el producto está hecho "para personas".
En comparación con ElasticSearch, se estima que el costo de almacenamiento y procesamiento de registros se reduce entre cinco y diez veces. En otras palabras, si para la cantidad actual de datos tuviéramos que configurar un clúster de varias máquinas, entonces al usar ClickHouse, una máquina de bajo consumo es suficiente para nosotros. Sí, por supuesto, ElasticSearch también tiene mecanismos de compresión de datos en disco y otras funciones que pueden reducir significativamente el consumo de recursos, pero en comparación con ClickHouse, esto será más costoso.
Sin optimizaciones especiales de nuestra parte, en la configuración predeterminada, la carga de datos y la selección de la base de datos funciona a una velocidad asombrosa. Todavía no tenemos muchos datos (alrededor de 200 millones de registros), pero el servidor en sí es débil. Podemos utilizar esta herramienta en el futuro para otros fines no relacionados con el almacenamiento de registros. Por ejemplo, para análisis de extremo a extremo, en el campo de la seguridad, aprendizaje automático.
Al final, un poco sobre los pros y los contras.
Contras
- Cargar registros en grandes lotes. Por un lado, esta es una característica, pero aún debe usar componentes adicionales para almacenar registros en búfer. Esta tarea no siempre es fácil, pero aún tiene solución. Y me gustaría simplificar el esquema.
- Algunas funcionalidades exóticas o nuevas características a menudo se rompen en las nuevas versiones. Esto causa preocupación, reduciendo el deseo de actualizar a una nueva versión. Por ejemplo, el motor de tablas de Kafka es una función muy útil que le permite leer directamente eventos de Kafka, sin implementar consumidores. Pero a juzgar por la cantidad de problemas en github, todavía tenemos cuidado de no usar este motor en producción. Sin embargo, si no hace gestos bruscos hacia un lado y usa la funcionalidad principal, entonces funciona de manera estable.
Pros
- No se ralentiza.
- Umbral de entrada bajo.
- Fuente abierta.
- Gratis.
- Escala bien (fragmentación/replicación lista para usar)
- Incluido en el registro de software ruso recomendado por el Ministerio de Comunicaciones.
- La presencia de apoyo oficial de Yandex.
Fuente: habr.com