База данни на ClickHouse за хора или извънземни технологии

Алексей Лизунов, ръководител на Компетентен център за канали за отдалечено обслужване на дирекция „Информационни технологии“ на МКБ

База данни на ClickHouse за хора или извънземни технологии

Като алтернатива на стека ELK (ElasticSearch, Logstash, Kibana), ние правим проучване за използването на базата данни ClickHouse като хранилище на данни за регистрационни файлове.

В тази статия бихме искали да говорим за нашия опит от използването на базата данни ClickHouse и предварителните резултати от пилотната операция. Веднага трябва да се отбележи, че резултатите бяха впечатляващи.


База данни на ClickHouse за хора или извънземни технологии

След това ще опишем по-подробно как е конфигурирана нашата система и от какви компоненти се състои. Но сега бих искал да поговоря малко за тази база данни като цяло и защо си струва да й обърнем внимание. Базата данни ClickHouse е високопроизводителна аналитична колонна база данни от Yandex. Използва се в услугите на Yandex, първоначално е основното хранилище за данни за Yandex.Metrica. Система с отворен код, безплатна. От гледна точка на разработчици, винаги съм се чудил как са го внедрили, защото има фантастично големи данни. А самият потребителски интерфейс на Metrica е много гъвкав и бърз. При първото запознаване с тази база данни впечатлението е: „Е, най-накрая! Направено за хората! Започвайки от процеса на инсталиране и завършвайки с изпращане на заявки.

Тази база данни има много нисък праг за влизане. Дори средно квалифициран разработчик може да инсталира тази база данни за няколко минути и да започне да я използва. Всичко работи ясно. Дори хора, които са нови в Linux, могат бързо да се справят с инсталацията и да извършат най-простите операции. Ако по-рано, с думите Big Data, Hadoop, Google BigTable, HDFS, обикновен разработчик имаше идеи, че става въпрос за някакви терабайти, петабайти, че някакви свръхчовеци се занимават с настройки и разработка за тези системи, то с появата на ClickHouse база данни, имаме прост, разбираем инструмент, с който можете да решавате непостижим досега набор от задачи. Отнема само една доста средна машина и пет минути за инсталиране. Тоест имаме такава база данни като например MySql, но само за съхраняване на милиарди записи! Определен суперархиватор с езика SQL. Сякаш на хората бяха връчени оръжията на извънземни.

Относно нашата система за регистриране

За събиране на информация се използват IIS регистрационни файлове на уеб приложения със стандартен формат (в момента също анализираме регистрационни файлове на приложения, но основната цел на пилотния етап е събирането на IIS регистрационни файлове).

Поради различни причини не можахме напълно да изоставим стека ELK и продължаваме да използваме компонентите LogStash и Filebeat, които са се доказали добре и работят доста надеждно и предвидимо.

Общата схема на регистриране е показана на фигурата по-долу:

База данни на ClickHouse за хора или извънземни технологии

Характеристика на записване на данни в базата данни ClickHouse е рядко (веднъж в секунда) вмъкване на записи в големи партиди. Това очевидно е най-„проблемната“ част, която срещате, когато за първи път работите с базата данни ClickHouse: схемата става малко по-сложна.
Плъгинът за LogStash, който директно вмъква данни в ClickHouse, помогна много тук. Този компонент е разположен на същия сървър като самата база данни. Така че, общо казано, не е препоръчително да го правите, но от практическа гледна точка, за да не произвеждате отделни сървъри, докато е разположен на същия сървър. Не забелязахме повреди или конфликти на ресурси с базата данни. Освен това трябва да се отбележи, че плъгинът има механизъм за повторен опит в случай на грешки. И в случай на грешки, плъгинът записва на диска пакет от данни, които не могат да бъдат вмъкнати (файловият формат е удобен: след редактиране можете лесно да вмъкнете коригирания пакет с помощта на clickhouse-клиент).

Пълният списък на софтуера, използван в схемата, е представен в таблицата:

Списък на използвания софтуер

Име

описание

Връзка за разпространение

Nginx

Обратно прокси за ограничаване на достъпа по портове и организиране на оторизация

В момента не се използва в схемата

https://nginx.org/ru/download.html

https://nginx.org/download/nginx-1.16.0.tar.gz

FileBeat

Прехвърляне на файлови дневници.

https://www.elastic.co/downloads/beats/filebeat (комплект за разпространение за Windows 64bit).

https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-7.3.0-windows-x86_64.zip

logstash

Събирач на трупи.

Използва се за събиране на регистрационни файлове от FileBeat, както и за събиране на регистрационни файлове от опашката RabbitMQ (за сървъри, които са в DMZ.)

https://www.elastic.co/products/logstash

https://artifacts.elastic.co/downloads/logstash/logstash-7.0.1.rpm

Logstash-изход-кликхаус

Loagstash плъгин за прехвърляне на регистрационни файлове към базата данни ClickHouse на партиди

https://github.com/mikechris/logstash-output-clickhouse

/usr/share/logstash/bin/logstash-plugin инсталирайте logstash-output-clickhouse

/usr/share/logstash/bin/logstash-plugin инсталиране на logstash-filter-prune

/usr/share/logstash/bin/logstash-plugin инсталиране на logstash-filter-multiline

Щракнете върху Къща

Съхранение на регистрационни файлове https://clickhouse.yandex/docs/ru/

https://packagecloud.io/Altinity/clickhouse/packages/el/7/clickhouse-server-19.5.3.8-1.el7.x86_64.rpm

https://packagecloud.io/Altinity/clickhouse/packages/el/7/clickhouse-client-19.5.3.8-1.el7.x86_64.rpm

Забележка. От август 2018 г. в хранилището на Yandex се появиха „нормални“ rpm компилации за RHEL, така че можете да опитате да ги използвате. По време на инсталацията използвахме пакети, създадени от Altinity.

Графана

Визуализация на дневника. Настройване на табла за управление

https://grafana.com/

https://grafana.com/grafana/download

Redhat & Centos (64 бита) - най-новата версия

Източник на данни ClickHouse за Grafana 4.6+

Плъгин за Grafana с източник на данни ClickHouse

https://grafana.com/plugins/vertamedia-clickhouse-datasource

https://grafana.com/api/plugins/vertamedia-clickhouse-datasource/versions/1.8.1/download

logstash

Регистрирайте маршрутизатор от FileBeat към RabbitMQ опашка.

Забележка. За съжаление FileBeat не извежда директно към RabbitMQ, така че е необходима междинна връзка под формата на Logstash

https://www.elastic.co/products/logstash

https://artifacts.elastic.co/downloads/logstash/logstash-7.0.1.rpm

RabbitMQ

опашка за съобщения. Това е регистрационният буфер в DMZ

https://www.rabbitmq.com/download.html

https://github.com/rabbitmq/rabbitmq-server/releases/download/v3.7.14/rabbitmq-server-3.7.14-1.el7.noarch.rpm

Erlang Runtime (необходим за RabbitMQ)

Време за изпълнение на Erlang. Изисква се, за да работи RabbitMQ

http://www.erlang.org/download.html

https://www.rabbitmq.com/install-rpm.html#install-erlang http://www.erlang.org/downloads/21.3

Конфигурацията на сървъра с базата данни ClickHouse е представена в следната таблица:

Име

Стойност

Внимание

Конфигурация

HDD: 40GB
RAM: 8GB
Процесор: Core 2 2 Ghz

Необходимо е да се обърне внимание на съветите за работа с базата данни ClickHouse (https://clickhouse.yandex/docs/ru/operations/tips/)

Общ системен софтуер

ОС: Red Hat Enterprise Linux Server (Maipo)

JRE (Java 8)

 

Както можете да видите, това е обикновена работна станция.

Структурата на таблицата за съхранение на регистрационни файлове е както следва:

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;

Използваме разделяне по подразбиране (по месеци) и детайлност на индекса. Всички полета на практика съответстват на записи в журнала на IIS за регистриране на http заявки. Отделно отбелязваме, че има отделни полета за съхраняване на utm-тагове (те се анализират на етапа на вмъкване в таблицата от полето за низ на заявката).

Също така към таблицата са добавени няколко системни полета за съхраняване на информация за системи, компоненти, сървъри. Вижте таблицата по-долу за описание на тези полета. В една таблица съхраняваме логове за няколко системи.

Име

описание

Пример

име_на_приложение

Име на приложение/система
Валидни стойности:

  • site1.domain.com Външен сайт 1
  • site2.domain.com Външен сайт 2
  • internal-site1.domain.local Вътрешен сайт 1

site1.domain.com

fld_app_module

Системен модул
Валидни стойности:

  • web - Уеб сайт
  • svc - услуга за уеб сайт
  • intgr - Интеграционна уеб услуга
  • bo - Администратор (BackOffice)

мрежа

fld_име_на_уебсайт

Име на сайта в IIS

Няколко системи могат да бъдат разположени на един сървър или дори няколко екземпляра на един системен модул

уеб основен

име_на_флд_сървър

Име на сървъра

web1.domain.com

fld_log_file_name

Път до лог файла на сървъра

C:inetpublogsLogFiles
W3SVC1u_ex190711.log

Това ви позволява ефективно да изграждате графики в Grafana. Например, прегледайте заявки от интерфейса на определена система. Това е подобно на брояча на сайтове в Yandex.Metrica.

Ето малко статистика за използването на базата данни за два месеца.

Брой записи, разбити по системи и техните компоненти

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.)

Количеството данни на диска

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.

Степен на компресиране на данните в колони

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.

Описание на използваните компоненти

FileBeat. Прехвърляне на файлови регистрационни файлове

Този компонент проследява промените в регистрационните файлове на диска и предава информацията на LogStash. Инсталиран на всички сървъри, където се записват лог файлове (обикновено IIS). Работи в опашен режим (т.е. прехвърля само добавените записи към файла). Но отделно може да се конфигурира да прехвърля цели файлове. Това е полезно, когато трябва да изтеглите данни от предишни месеци. Просто поставете лог файла в папка и той ще го прочете целия.

Когато услугата бъде спряна, данните вече не се прехвърлят в хранилището.

Примерна конфигурация изглежда така:

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. Събирач на регистрационни файлове

Този компонент е проектиран да получава записи в журнала от FileBeat (или чрез опашката RabbitMQ), анализирайки и вмъквайки партиди в базата данни на ClickHouse.

За вмъкване в ClickHouse се използва плъгинът Logstash-output-clickhouse. Приставката Logstash има механизъм за повторен опит на заявка, но при редовно изключване е по-добре да спрете самата услуга. При спиране съобщенията ще се натрупват в опашката на RabbitMQ, така че ако спирането е за дълго време, тогава е по-добре да спрете Filebeats на сървърите. В схема, в която RabbitMQ не се използва (в локалната мрежа Filebeat директно изпраща логове към Logstash), Filebeats работят доста приемливо и сигурно, така че за тях липсата на изход минава без последствия.

Примерна конфигурация изглежда така:

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"
        }
    }
 
}

тръбопроводи.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. Съхранение на регистрационни файлове

Дневниците за всички системи се съхраняват в една таблица (вижте в началото на статията). Предназначен е да съхранява информация за заявки: всички параметри са подобни за различни формати, като например IIS регистрационни файлове, apache и nginx регистрационни файлове. За регистрационните файлове на приложенията, в които например се записват грешки, информационни съобщения, предупреждения, ще бъде предоставена отделна таблица със съответната структура (в момента на етап проектиране).

Когато проектирате таблица, е много важно да вземете решение за първичния ключ (по който данните ще бъдат сортирани по време на съхранение). Степента на компресиране на данните и скоростта на заявките зависят от това. В нашия пример ключът е
ПОРЪЧАЙ ПО (fld_app_name, fld_app_module, logdatetime)
Тоест по името на системата, името на системния компонент и датата на събитието. Първоначално на първо място беше датата на събитието. След като го преместихте на последното място, заявките започнаха да работят около два пъти по-бързо. Промяната на първичния ключ ще изисква повторно създаване на таблицата и презареждане на данните, така че ClickHouse да пресортира данните на диска. Това е тежка операция, така че е добра идея да помислите много какво трябва да бъде включено в ключа за сортиране.

Трябва също да се отбележи, че типът данни LowCardinality се появи относително в последните версии. Когато го използвате, размерът на компресираните данни се намалява драстично за тези полета, които имат ниска кардиналност (малко опции).

В момента се използва версия 19.6 и планираме да опитаме да актуализираме до най-новата версия. Те имат такива прекрасни функции като Adaptive Granularity, Skipping индекси и кодека DoubleDelta, например.

По подразбиране по време на инсталацията нивото на регистриране е зададено на проследяване. Дневниците се ротират и архивират, но в същото време се разширяват до гигабайт. Ако няма нужда, тогава можете да зададете нивото на предупреждение, тогава размерът на дневника се намалява драстично. Настройката за регистриране е зададена във файла config.xml:

<!-- Possible levels: https://github.com/pocoproject/poco/blob/develop/Foundation/include/Poco/Logger. h#L105 -->
<level>warning</level>

Някои полезни команди

Поскольку оригинальные пакеты установки собираются по Debian, то для других версий Linux необходимо использовать пакеты собранные компанией Altinity.
 
Вот по этой ссылке есть инструкции с ссылками на их репозиторий: https://www.altinity.com/blog/2017/12/18/logstash-with-clickhouse
sudo yum search clickhouse-server
sudo yum install clickhouse-server.noarch
  
1. проверка статуса
sudo systemctl status clickhouse-server
 
2. остановка сервера
sudo systemctl stop clickhouse-server
 
3. запуск сервера
sudo systemctl start clickhouse-server
 
Запуск для выполнения запросов в многострочном режиме (выполнение после знака ";")
clickhouse-client --multiline
clickhouse-client --multiline --host 127.0.0.1 --password pa55w0rd
clickhouse-client --multiline --host 127.0.0.1 --port 9440 --secure --user default --password pa55w0rd
 
Плагин кликлауза для логстеш в случае ошибки в одной строке сохраняет всю пачку в файл /tmp/log_web_failed.json
Можно вручную исправить этот файл и попробовать залить его в БД вручную:
clickhouse-client --host 127.0.0.1 --password password --query="INSERT INTO log_web FORMAT JSONEachRow" < /tmp/log_web_failed__fixed.json
 
sudo mv /etc/logstash/tmp/log_web_failed.json /etc/logstash/tmp/log_web_failed__fixed.json
sudo chown user_dev /etc/logstash/tmp/log_web_failed__fixed.json
sudo clickhouse-client --host 127.0.0.1 --password password --query="INSERT INTO log_web FORMAT JSONEachRow" < /etc/logstash/tmp/log_web_failed__fixed.json
sudo mv /etc/logstash/tmp/log_web_failed__fixed.json /etc/logstash/tmp/log_web_failed__fixed_.json
 
выход из командной строки
quit;
## Настройка TLS
https://www.altinity.com/blog/2019/3/5/clickhouse-networking-part-2
 
openssl s_client -connect log.domain.com:9440 < /dev/null

logstash. Регистрирайте маршрутизатор от FileBeat към RabbitMQ опашка

Този компонент се използва за насочване на регистрационни файлове, идващи от FileBeat към опашката RabbitMQ. Тук има две точки:

  1. За съжаление, FileBeat няма плъгин за изход, който да пише директно в RabbitMQ. И такава функционалност, съдейки по проблема в техния github, не е планирана за внедряване. Има плъгин за Kafka, но по някаква причина не можем да го използваме у дома.
  2. Има изисквания за събиране на трупи в DMZ. Въз основа на тях логовете първо трябва да се добавят към опашката и след това LogStash чете записите от опашката отвън.

Следователно в случай, че сървърите са разположени в DMZ, трябва да се използва такава малко сложна схема. Примерна конфигурация изглежда така:

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. опашка за съобщения

Този компонент се използва за буфериране на записи в дневника в DMZ. Записът се извършва чрез набор от Filebeat → LogStash. Четенето се извършва извън DMZ чрез LogStash. При работа през RabboitMQ се обработват около 4 хиляди съобщения в секунда.

Маршрутизирането на съобщения се конфигурира от името на системата, т.е. въз основа на данните за конфигурацията на FileBeat. Всички съобщения отиват в една опашка. Ако по някаква причина услугата за опашка бъде спряна, това няма да доведе до загуба на съобщения: FileBeats ще получи грешки при свързване и временно ще спре изпращането. И LogStash, който чете от опашката, също ще получава мрежови грешки и ще чака връзката да бъде възстановена. В този случай данните, разбира се, вече няма да се записват в базата данни.

Следните инструкции се използват за създаване и конфигуриране на опашки:

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"

Графана. Табла за управление

Този компонент се използва за визуализиране на данните от мониторинга. В този случай трябва да инсталирате източника на данни ClickHouse за плъгина Grafana 4.6+. Трябваше да го променим малко, за да подобрим ефективността на обработката на SQL филтрите на таблото за управление.

Например, ние използваме променливи и ако те не са зададени в полето за филтър, тогава бихме искали то да не генерира условие в WHERE на формата ( uriStem = » И uriStem != » ). В този случай ClickHouse ще прочете колоната uriStem. Като цяло опитахме различни опции и в крайна сметка коригирахме плъгина (макроса $valueIfEmpty), така че в случай на празна стойност да връща 1, без да споменава самата колона.

И сега можете да използвате тази заявка за графиката

$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')

което се превежда в този SQL (обърнете внимание, че празните полета uriStem са преобразувани само в 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

Заключение

Появата на базата данни ClickHouse се превърна в забележително събитие на пазара. Трудно ни беше да си представим, че напълно безплатно, за миг бяхме въоръжени с мощен и практичен инструмент за работа с големи данни. Разбира се, с увеличаване на нуждите (например шардинг и репликация към множество сървъри), схемата ще стане по-сложна. Но на първо впечатление работата с тази база данни е много приятна. Вижда се, че продуктът е направен "за хората".

В сравнение с ElasticSearch разходите за съхранение и обработка на регистрационни файлове се оценяват като намалени от пет до десет пъти. С други думи, ако за текущото количество данни ще трябва да настроим клъстер от няколко машини, тогава при използване на ClickHouse ни е достатъчна една машина с ниска мощност. Да, разбира се, ElasticSearch също има механизми за компресиране на данни на диска и други функции, които могат значително да намалят потреблението на ресурси, но в сравнение с ClickHouse това ще бъде по-скъпо.

Без специални оптимизации от наша страна, при настройки по подразбиране, зареждането на данни и избирането от базата данни работи с невероятна скорост. Все още нямаме много данни (около 200 милиона записа), но самият сървър е слаб. Можем да използваме този инструмент в бъдеще за други цели, които не са свързани със съхраняването на регистрационни файлове. Например за анализи от край до край, в областта на сигурността, машинно обучение.

Накрая малко за плюсовете и минусите.

Против

  1. Зареждане на записи в големи партиди. От една страна, това е функция, но все пак трябва да използвате допълнителни компоненти за буфериране на записи. Тази задача не винаги е лесна, но все пак разрешима. И бих искал да опростя схемата.
  2. Някои екзотични функции или нови функции често се повреждат в новите версии. Това предизвиква безпокойство, намалявайки желанието за надграждане до нова версия. Например, Kafka table engine е много полезна функция, която ви позволява директно да четете събития от Kafka, без да внедрявате потребители. Но съдейки по броя на проблемите в github, ние все още внимаваме да не използваме този двигател в производството. Въпреки това, ако не правите внезапни жестове встрани и използвате основната функционалност, тогава тя работи стабилно.

Професионалисти

  1. Не забавя.
  2. Нисък праг на влизане.
  3. Отворен код.
  4. Безплатно.
  5. Мащабира добре (шардинг/репликация извън кутията)
  6. Включен в регистъра на руския софтуер, препоръчан от Министерството на съобщенията.
  7. Наличието на официална поддръжка от Yandex.

Източник: www.habr.com

Добавяне на нов коментар