Перейти к основному содержимому
Перейти к основному содержимому

Integrating Vector with ClickHouse

Partner Integration

Возможность анализировать логи в реальном времени критически важна для production-приложений. ClickHouse превосходно справляется с хранением и анализом логов благодаря отличному сжатию (до 170x для логов) и способности быстро агрегировать большие объемы данных.

Данное руководство показывает, как использовать популярный конвейер данных Vector для отслеживания файла логов Nginx и отправки данных в ClickHouse. Приведенные ниже шаги аналогичны для отслеживания файлов логов любого типа.

Предварительные требования:

  • У вас уже установлен и запущен ClickHouse
  • У вас установлен Vector

Создание базы данных и таблицы

Определите таблицу для хранения событий логов:

  1. Сначала создайте новую базу данных с именем nginxdb:
CREATE DATABASE IF NOT EXISTS nginxdb
  1. Вставьте всё событие лога как одну строку. Очевидно, что это не лучший формат для проведения аналитики по данным логов, но ниже мы разберёмся с этим, используя materialized views.
CREATE TABLE IF NOT EXISTS  nginxdb.access_logs (
  message String
)
ENGINE = MergeTree()
ORDER BY tuple()
Примечание

ORDER BY установлен в tuple() (пустой кортеж), так как первичный ключ пока не требуется.

Настройка Nginx

На этом шаге будет показано, как настроить логирование Nginx.

  1. Следующая директива access_log записывает логи в /var/log/nginx/my_access.log в формате combined. Это значение указывается в разделе http файла nginx.conf:
http {
  include       /etc/nginx/mime.types;
  default_type  application/octet-stream;
  access_log  /var/log/nginx/my_access.log combined;
  sendfile        on;
  keepalive_timeout  65;
  include /etc/nginx/conf.d/*.conf;
}
  1. Обязательно перезапустите Nginx, если вы изменяли файл nginx.conf.

  2. Сгенерируйте несколько событий в журнале доступа (access log), переходя по страницам вашего веб-сервера. Записи журнала в формате combined выглядят следующим образом:

192.168.208.1 - - [12/Oct/2021:03:31:44 +0000] "GET / HTTP/1.1" 200 615 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36"
192.168.208.1 - - [12/Oct/2021:03:31:44 +0000] "GET /favicon.ico HTTP/1.1" 404 555 "http://localhost/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36"
192.168.208.1 - - [12/Oct/2021:03:31:49 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36"

Настройка Vector

Vector собирает, преобразует и маршрутизирует логи, метрики и трейсы (далее — источники) в различные сервисы (далее — приёмники), включая встроенную «из коробки» совместимость с ClickHouse. Источники и приёмники определяются в конфигурационном файле vector.toml.

  1. Следующий файл vector.toml определяет source типа file, который непрерывно считывает новые записи из конца файла my_access.log, а также определяет sink, направляющий данные в таблицу access_logs, описанную выше:
[sources.nginx_logs]
type = "file"
include = [ "/var/log/nginx/my_access.log" ]
read_from = "end"

[sinks.clickhouse]
type = "clickhouse"
inputs = ["nginx_logs"]
endpoint = "http://clickhouse-server:8123"
database = "nginxdb"
table = "access_logs"
skip_unknown_fields = true
  1. Запустите Vector с приведённой выше конфигурацией. За дополнительной информацией об определении источников и приёмников обращайтесь к документации Vector.

  2. Убедитесь, что логи доступа записываются в ClickHouse, выполнив следующий запрос. В своей таблице вы должны увидеть эти логи доступа:

SELECT * FROM nginxdb.access_logs
Просмотр логов ClickHouse в табличном виде

Разбор логов

Хранить логи в ClickHouse полезно, но сохранение каждого события в виде одной строки не дает больших возможностей для анализа данных. Далее мы рассмотрим, как разбирать события логов с помощью материализованного представления.

Материализованное представление работает подобно триггеру на INSERT в SQL. Когда строки данных вставляются в исходную таблицу, материализованное представление выполняет над ними некоторые преобразования и вставляет результаты в целевую таблицу. The materialized view can be configured to configure a parsed representation of the log events in access_logs. An example of one such log event is shown below:

192.168.208.1 - - [12/Oct/2021:15:32:43 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36"

В ClickHouse есть различные функции для разбора приведённой выше строки. Функция splitByWhitespace разбирает строку по пробельным символам и возвращает каждый токен в виде элемента массива. Для демонстрации выполните следующую команду:

SELECT splitByWhitespace('192.168.208.1 - - [12/Oct/2021:15:32:43 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36"')
["192.168.208.1","-","-","[12/Oct/2021:15:32:43","+0000]","\"GET","/","HTTP/1.1\"","304","0","\"-\"","\"Mozilla/5.0","(Macintosh;","Intel","Mac","OS","X","10_15_7)","AppleWebKit/537.36","(KHTML,","like","Gecko)","Chrome/93.0.4577.63","Safari/537.36\""]

В некоторых строках есть лишние символы, а user agent (сведения о браузере) не требовалось парсить, но получившийся массив близок к нужному.

Аналогично функции splitByWhitespace, функция splitByRegexp разбивает строку на массив по регулярному выражению. Выполните следующую команду, которая вернёт две строки.

SELECT splitByRegexp('\S \d+ "([^"]*)"', '192.168.208.1 - - [12/Oct/2021:15:32:43 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36"')

Обратите внимание, что вторая возвращаемая строка — это user agent, успешно разобранный из лога:

["192.168.208.1 - - [12/Oct/2021:15:32:43 +0000] \"GET / HTTP/1.1\" 30"," \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36\""]

Прежде чем перейти к итоговой команде CREATE MATERIALIZED VIEW, давайте рассмотрим ещё пару функций, используемых для очистки данных. Например, поле RequestMethod имеет значение "GET, то есть содержит лишнюю двойную кавычку. Вы можете использовать функцию trimBoth (псевдоним trim), чтобы удалить двойную кавычку:

SELECT trim(LEADING '"' FROM '"GET')

Строка с датой начинается с квадратной скобки и при этом имеет формат, который ClickHouse не может разобрать как дату. Однако, если мы заменим разделитель с двоеточия (:) на запятую (,), разбор уже работает отлично:

SELECT parseDateTimeBestEffort(replaceOne(trim(LEADING '[' FROM '[12/Oct/2021:15:32:43'), ':', ' '))

Теперь мы готовы определить materialized view. В определение ниже включено POPULATE, что означает, что существующие строки в access_logs будут сразу обработаны и вставлены. Выполните следующий SQL-запрос:

CREATE MATERIALIZED VIEW nginxdb.access_logs_view
(
  RemoteAddr String,
  Client String,
  RemoteUser String,
  TimeLocal DateTime,
  RequestMethod String,
  Request String,
  HttpVersion String,
  Status Int32,
  BytesSent Int64,
  UserAgent String
)
ENGINE = MergeTree()
ORDER BY RemoteAddr
POPULATE AS
WITH
  splitByWhitespace(message) as split,
  splitByRegexp('\S \d+ "([^"]*)"', message) as referer
SELECT
  split[1] AS RemoteAddr,
  split[2] AS Client,
  split[3] AS RemoteUser,
  parseDateTimeBestEffort(replaceOne(trim(LEADING '[' FROM split[4]), ':', ' ')) AS TimeLocal,
  trim(LEADING '"' FROM split[6]) AS RequestMethod,
  split[7] AS Request,
  trim(TRAILING '"' FROM split[8]) AS HttpVersion,
  split[9] AS Status,
  split[10] AS BytesSent,
  trim(BOTH '"' from referer[2]) AS UserAgent
FROM
  (SELECT message FROM nginxdb.access_logs)

Теперь убедитесь, что всё работает. Вы должны увидеть, что логи доступа аккуратно разобраны по столбцам:

SELECT * FROM nginxdb.access_logs_view
Просматривайте разобранные логи ClickHouse в виде таблицы
Примечание

В приведённом выше примере данные сохранялись в двух таблицах, но вы можете изменить исходную таблицу nginxdb.access_logs, чтобы она использовала движок таблиц Null. Разобранные данные по-прежнему попадут в таблицу nginxdb.access_logs_view, но исходные данные не будут сохраняться в таблице.

Используя Vector, который требует лишь простой установки и быстрой настройки, вы можете отправлять журналы с сервера Nginx в таблицу ClickHouse. Используя materialized view, вы можете разобрать эти журналы по столбцам для упрощения аналитики.