Автор: Беляев Данила, инженер по ОТ Юсетех.

Введение

Всем привет! Меня зовут Беляев Данила, я работаю инженером SR в Usetech. Цель этой статьи — изучить четыре метода, которые могут помочь уменьшить объем дискового пространства, используемого Elasticsearch.

Во-первых, эта статья будет полезна начинающим администраторам стека ELK, системным администраторам мониторинга, разработчикам, использующим стек ELK в своих проектах.

Работая над мониторингом в одном из наших проектов, мы столкнулись с проблемой, что период времени, за который мы можем хранить данные, нам недостаточен, потому что мы хотели иметь возможность сравнить производительность системы за более длительный период времени.

Мы увидели два пути решения проблемы:

  1. Увеличьте объем дискового пространства.
  2. Уменьшите объем дискового пространства, занимаемого индексами.

Долгое время мы шли по первому пути, но достигли предела ресурсов. Поэтому пришло время оптимизации.

Цели

Цель этой статьи — рассказать о четырех простых способах, которые помогли нам сократить использование диска Elasticsearch:

  1. Настройка динамического отображения в шаблоне индекса.
  2. Использование агрессивного алгоритма сжатия.
  3. Отключение индексации и doc_value для полей, которые не участвуют в поиске, сортировке и агрегации.
  4. Использование политики жизненного цикла.

Эти методы можно применять по отдельности или настраивать вместе для достижения наибольшей оптимизации использования диска. Хотя эти методы довольно просты, они помогли увеличить срок хранения индексов в среднем в шесть раз.

Отказ от ответственности. Примеры в этой статье были протестированы на Elasticsearch версии 7.7.1.

Настройка динамического отображения в шаблоне индекса

Динамическое сопоставление — это процесс автоматического создания и ввода полей. Чтобы хранить данные, Elasticsearch необходимо понимать, какой тип данных использовать для обнаруженного поля. Тип данных определяется на основе правил, показанных в следующей таблице:

Подробнее о динамическом отображении:

  • «Динамическое отображение | Руководство по Elasticsearch [8.6] | Эластичный"
  • «динамический | Руководство по Elasticsearch [8.6] | Эластичный"

Мы видим, что строковый тип преобразуется в два типа данных. Это означает, что значение строкового поля в Elasticsearch будет сохранено как в виде текста, так и в виде ключевого слова.

Текст – это тип данных, позволяющий выполнять полнотекстовый поиск. Однако текст нельзя использовать для сортировки и агрегирования.

Ключевое слово – это тип данных, который позволяет индексировать строку как есть. Он используется для сортировки, агрегирования и в запросах на уровне терминов.

Есть хорошая статья, объясняющая все различия между этими двумя типами.

В нашем проекте мы решили использовать только тип ключевых слов, чтобы уменьшить объем и время индексации, так как мы не используем полнотекстовый поиск.

Давайте рассмотрим, как настроить динамическое сопоставление полей в шаблоне индекса на практическом примере. Этот пример позволяет вам преобразовать только строку в ключевое слово, но вы также можете настроить преобразование в текст.

Во-первых, вам необходимо:

  1. Перейдите в раздел: Управление -> Управление стеком -> Управление индексами.
  2. Откройте раздел шаблонов индексов.
  3. Создайте новый шаблон или перейдите к существующему
  4. В разделе Mapping -> dynamic_template добавьте:
{
"strings": {
"mapping": {
"ignore_above": 256,
"type": "keyword"
},
"match_mapping_type": "string"
}
}

Теперь при появлении нового строкового поля оно будет преобразовано в ключевое слово. Параметр ignore_above отвечает за максимальный размер ключевого слова, которое будет проиндексировано. В нашем примере, если длина поля больше 256 символов, оно не будет проиндексировано.

Vital Point Если вы отключите индексирование для поля, вы не сможете выполнять поиск по нему. Тем не менее, вы все равно можете сортировать и агрегировать по нему. Подробнее по ссылке.

Таким образом, мы можем настроить динамическое сопоставление и для других типов, а с помощью интерфейса или API в шаблоне индекса указать дополнительные настройки для полей. Например, мы можем использовать регулярные выражения для преобразования полей с определенными именами в указанный тип данных и отключения индексации для этих полей.

{ "labels": {
"path_match": "labels.*",
"mapping": {
"type": "keyword",
"index": false
},
"match_mapping_type": "string"
}

В этом примере поля, начинающиеся с меток, будут преобразованы в тип ключевого слова, и для этих полей будет отключена индексация.

Даты и числа

Преобразование дат и чисел в тип данных date и long вместо keyword поможет уменьшить размер индексов.

Чтобы включить динамическое сопоставление дат и чисел, сделайте следующее:

  1. Перейдите в раздел Управление > Управление стеком > Управление индексами.
  2. Откройте раздел Шаблоны индексов.
  3. Создайте новый шаблон или перейдите к существующему
  4. В разделе Mapping -> Advanced Options включите следующее:

Если вы могли использовать запросы с подстановочными знаками перед преобразованием данных в дату и long, например код_ответа:5*, и получить все документы в формате response_code, которые содержат 5xx коды ответов HTTP, после преобразования необходимо использовать операторы сравнения, т.е. response_code: ›= 500

Заключение

Мы уже определили динамическое сопоставление в шаблоне индекса и указали преобразование дат и чисел в date и long соответственно, но насколько эффективными были эти методы для уменьшения размера индекса? индекс?

Чтобы получить некоторые сравнительные результаты:

  1. Сначала запустим сбор логов без наших настроек:

2. Затем добавляем наши улучшения:

Результат:

  1. Для 1 миллиона документов ~= 5,7 ГБ
  2. Для 1 миллиона документов ~= 4,8 ГБ

Таким образом, в нашем проекте использование диска после изменения настроек динамического отображения в шаблоне индекса сократилось примерно на 16%. Более подробную информацию о динамических шаблонах можно найти в документации.

Использование алгоритма сжатия DEFLATE

По умолчанию Elasticsearch использует алгоритм сжатия LZ4. LZ4 — это алгоритм сжатия данных без потерь, ориентированный на быстрое сжатие данных. Чаще всего используется в приложениях с высокими нагрузками, где требуется дешевое и быстрое сжатие данных без дополнительной нагрузки на ЦП.

Вместо LZ4 вы можете настроить Elasticsearch на использование алгоритма сжатия DEFLATE. DEFLATE — это алгоритм сжатия данных без потерь, в котором используется комбинация LZ77 и кодирования Хаффмана. Алгоритм ориентирован на более эффективное сжатие повторяющихся данных. Это требует больше времени для сжатия/распаковки и больше ресурсов процессора.

Недавний пример: одна из наших служб начала отправлять ошибки 5xx чаще, чем ожидалось. Пиковая нагрузка составляла около 50 RPS, и каждая ошибка генерировала одинаковые логи, не считая нормальной работы приложения с другими сервисами. На тот момент мы уже настроили алгоритм сжатия DEFLATE. Посмотрите на индексы 13 и 14 на изображении ниже. Мы видим, что разница в объеме 13-го и 14-го индекса составляет ~3 ГБ, а в документах разница более чем в 2 раза.

Чтобы использовать алгоритм DEFLATE вместо LZ4, необходимо указать его использование в шаблоне индекса.

Для этого вам необходимо:

  1. Откройте раздел шаблонов индексов.
  2. Выберите шаблон, в котором вы хотите использовать алгоритм сжатия DEFLATE.
  3. В разделе настроек индекса добавьте:
{
"index": {
"code": "best_compression"
}

Если ваш «индекс» уже содержит некоторые поля, просто добавьте «код»: «best_compression».

Vital Point Как упоминалось ранее, агрессивный алгоритм сжатия DEFLATE требует больше ресурсов, чем LZ4. Поэтому попробуйте протестировать его, прежде чем использовать по умолчанию в своих шаблонах индексов.

Заключение

Нас как инженеров и математиков интересуют только цифры и факты (ну и котята). Давайте сравним размеры индексов, используя:

  1. LZ4
  2. СДУВАТЬ
  3. Динамическое отображение + DEFLATE

Размер первого индекса с LZ4:

Размер второго индекса с DEFLATE:

Размер индекса при динамическом отображении + DEFLATE:

Получаем следующие числа для трех индексов:

  1. 1 миллион документов ~= 5,7 ГБ
  2. 1 миллион документов ~= 3,7 ГБ
  3. 1 миллион документов ~= 1,5 ГБ

Таким образом, мы видим, что индекс с DEFLATE потерял в размере около 35%*, а индекс с динамическим отображением + DEFLATE потерял в размере около 74%* по сравнению с индексом с LZ4.

** относительно индекса LZ4*

Отключение индексации и doc_value для полей, которые не используются при поиске, сортировке и агрегации

Иногда в логах есть поля, которые нельзя использовать для поиска, сортировки или агрегации, но они используются при чтении логов. Например, в нашем проекте есть поле с именем Exception, которое отображает сообщение об ошибке в коде Python. Использование поля для поиска, сортировки или агрегирования не рекомендуется из-за чрезмерного количества символов, которые оно содержит.

Возможно, у вас есть другие полезные поля, которые не используются, кроме как при чтении логов. Поэтому, чтобы уменьшить их влияние на использование диска, выполните следующие действия:

Отключение индексации

Неиспользуемые поля с индексацией опасны тем, что при многих из них они значительно увеличивают использование диска. Особенно, если такие поля содержат много символов (длинные поля).

Поэтому рассмотрим, что нужно настроить для отключения индексации:

Если у вас много полей

Вы можете попробовать использовать регулярное выражение для динамического сопоставления в шаблоне индекса. Вы можете сделать это следующим образом:

  1. Перейдите в раздел: Управление > Управление стеком > Управление индексом.
  2. Откройте раздел шаблонов индексов.
  3. Создайте новый шаблон или перейдите к существующему
  4. В разделе dynamic_template добавьте:
{
"longfield": {
"path_match": "longfield.*",
"mapping": {
"type": "keyword",
"index": false
},
"match_mapping_type": "string"
}

В поле path_match вы можете подставить собственное регулярное выражение вместо longfield.*, а index: false отключает индексирование.

Если у вас есть несколько полей

Вы можете добавить каждое поле вручную. Вы можете сделать это следующим образом:

  1. Перейдите в раздел: Управление > Управление стеком > Управление индексом.
  2. Откройте раздел шаблоны индекса.
  3. Создайте новый шаблон или перейдите к существующему
  4. В разделе mappings -> mapped fields добавьте имя поля и отключите параметр Searchable, как показано на изображении ниже.

Может быть случай, когда вы собираете какие-то поля, но в данный момент не используете их для поиска. Затем подумайте о том, чтобы не хранить их в _source, чтобы оптимизировать использование диска.

_source – это поле, в котором хранится исходный текст документа в формате JSON, который был передан во время индексирования.

Чтобы не сохранять поле в _source, сделайте следующее:

  1. Перейдите в раздел шаблоны индекса > сопоставления > дополнительный параметр".
  2. Прокрутите вниз до раздела _source:

3. В разделе исключить поля добавьте имена полей, которые вы не хотите сохранять в _source.

Если вы хотите добавить поле в _source, просто добавьте его во включаемые поля.

Отключение doc_value

Хотя инвертированный индекс быстр для поиска, он не самый лучший для сортировки и агрегирования. Для этих задач структуры хранения столбцов более эффективны. В Elasticsearch такая структура называется doc_value.

doc_value — это структура, которая создается во время индексации документа, поэтому отключение индексации может привести к отключению сортировки и агрегирования. Однако такие типы данных, как число, дата, логическое значение, ключевое слово и т. д., по-прежнему можно использовать для сортировки и агрегирования, даже если для них отключено индексирование.

Чтобы отключить doc_value для поля, выполните следующие действия:

  1. Перейдите в раздел: Управление -> Управление стеком -> Управление индексами.
  2. Откройте раздел index templates.
  3. Создайте новый шаблон или введите существующий
  4. В разделе dynamic_template добавьте:
{
"longfield": {
"path_match": "longfield.*",
"mapping": {
"type": "keyword",
"doc_value": false
},
"match_mapping_type": "string"
}

В этом примере все поля, начинающиеся с longfield. и имеющие тип string, будут сопоставлены с ключевым словом, а doc_value будет отключено, что сделает их непригодными для сортировки и агрегирования.

Заключение

Попробуйте уменьшить количество полей с включенным индексированием и doc_value, особенно если это длинные поля. Если какие-то поля сейчас не используются, но сохранены, постарайтесь не добавлять их в _source.

Мы уже достаточно поговорили об отключении индексации, теперь давайте посмотрим на некоторые цифры.

Сравним размер индексов:

  1. Без методов оптимизации
  2. С отключением индексации для некоторых полей
  3. С использованием индексации для некоторых полей и предыдущих методов оптимизации

Размер индекса без учета политик

Размер индекса с отключенной индексацией для некоторых полей

Размер индекса с использованием индексации некоторых полей и предыдущих методов оптимизации

Мы получаем:

  1. 1 миллион документов ~= 5,7 ГБ
  2. 1 миллион документов ~= 3,7 ГБ
  3. 1 миллион документов ~= 1,3 ГБ

Результат сокращения длинных полей с настройками составляет около 35%*, а результат сокращения тремя методами оптимизации — около 77%.* На результат влияет количество полей, для которых мы отключили индексирование.

** относительно индекса без использования методов оптимизации*

Использование политики жизненного цикла

Многоуровневая архитектура в Elasticsearch

Для эффективного распределения ресурсов и хранения данных в Elasticsearch реализована архитектура «горячий-теплый-холодный», состоящая из 4 фаз:

  1. горячий
  2. теплый
  3. холодный
  4. заморозить

Благодаря этой архитектуре узлы могут быть организованы таким образом, что имеется пул узлов с высокопроизводительным аппаратным профилем для вновь создаваемых индексов, данные которых активно запрашиваются и представляют наибольшую ценность, и другие пулы узлов с менее производительным профилем. аппаратный профиль, где поиск по индексам происходит реже.

Политика жизненного цикла позволяет определять фазы и переходы между фазами, что оптимизирует процессы хранения и удаления индексов.

Политика жизненного цикла не применяется к ранее созданным индексам. Он должен быть указан при создании индекса и будет управлять им с момента создания до удаления.

Фазы

Для каждой фазы можно настроить ее продолжительность. Это означает, что индекс будет переходить от фазы к фазе через указанное время. Единственное отличие — для горячей фазы, где помимо времени можно указать размер индекса или количество документов. Если эти значения превышены, индекс перейдет к следующей настроенной фазе.

Кроме того, у нас есть возможность вообще пропустить определенные этапы. Например, индекс, который в настоящее время находится в горячей фазе, может перейти непосредственно в холодную фазу или из теплой фазы в фазу удаления.

Вновь созданный индекс находится в горячей фазе, что означает, что индекс доступен для чтения и записи. Он заполняется новыми журналами, а это означает, что информация часто запрашивается и представляет наивысшую ценность. Данные активно индексируются и дополнительно не сжимаются (используются только настройки шаблона индекса). Поэтому индекс в горячей фазе занимает больше всего места на диске и требует больше ресурсов ЦП и SSD для работы.

Теплая фаза — индекс этой фазы доступен для чтения. Он используется для устаревших данных, которые все еще имеют ценность. Поиск происходит медленнее, чем в горячей фазе. Таким образом, для работы с индексами в теплой фазе требуется меньше ресурсов ЦП и SSD.

Холодная фаза — индекс этой фазы доступен для чтения. Он используется для данных, которые редко запрашиваются. Поиск может занять даже больше времени, чем в теплой фазе. Он требует наименьшего количества ресурсов ЦП и SSD.

Этап замораживания — индекс на этом этапе недоступен для чтения или записи. Он используется для хранения данных до лучших времен, если это необходимо. Использование диска может быть значительно уменьшено. Он требует дисковых ресурсов, но почти не требует ресурсов процессора.

Концом любой политики жизненного цикла является этап удаления. Индексы удаляются на этапе удаления.

После настройки ILM (управление жизненным циклом индексов) вам больше не нужно беспокоиться о добавлении, удалении и сжатии индексов. ILM делает все автоматически. Главное — правильно указать триггеры перехода, чтобы ваше дисковое пространство не заполнилось до того, как будет удален первый индекс с настроенной политикой жизненного цикла.

Индекс переходит из фазы в фазу, когда время жизни индекса в текущей фазе подходит к концу. За исключением горячей фазы, где есть возможность настроить сразу несколько триггеров:

  1. Размер индекса
  2. Количество документов в индексе
  3. Время жизни индекса

В настройках политики жизненного цикла мы указываем эти три значения. Например, переход к следующему этапу, как только размер индекса превысит 50 гигабайт, или количество документов превысит 20 миллионов, или он будет создан 2 дня назад.

Как только одно из условий будет выполнено, наш индекс перейдет к следующему этапу. И ILM создаст новый индекс на горячем этапе — этот процесс называется rollover.

Как это работает?

Для этого Elasticsearch использует псевдонимы, необходимые для создания нового индекса и понимания, где хранить входящие журналы.

Вот в чем проблема: чтобы создать новый индекс после того, как предыдущий уже выполнил ролловер, политика жизненного цикла должна понимать, какое имя дать новому индексу. К сожалению, просто указать псевдоним не получится. У вас получится ситуация двух одинаковых индексов, и система не сможет их уследить и выдаст ошибку.

Подробнее о ролловере можно прочитать здесь.

Давайте рассмотрим самый простой способ использования ILM:

Во-первых, мы рассмотрим наиболее популярный вариант использования ILM в индексах. Настроим горячие и удаляемые фазы без ролловера. Таким образом, наши индексы останутся в горячей фазе, пока не будут удалены. Это самый простой способ автоматизировать вещи. Дополнительные настройки и возможности ILM можно найти в других статьях и документации.

Чтобы использовать политику жизненного цикла, ее необходимо настроить. Сделать это:

  1. Перейдите в раздел политики жизненного цикла индекса.
  2. Создайте новую политику.

Это пример интерфейса, у вас может быть что-то вроде этого:

В горячей фазе нам нужно отключить параметр Enable rollover, чтобы наш индекс оставался в горячей фазе до удаления и не создавал дополнительных псевдонимов во время своего существования.

На этом этапе мы назовем политику main-policy. Затем мы прокручиваем вниз и включаем фазу удаления. Например, через неделю после создания наш индекс должен быть удален.

Теперь настроим использование созданной политики жизненного цикла в шаблоне индекса. Сделать это:

  1. Перейдите в раздел Управление > Управление стеком > Управление индексами.
  2. Откройте раздел шаблоны индекса.
  3. Создайте новый шаблон или отредактируйте существующий.
  4. В разделе Mapping -> Index settings добавьте блок жизненного цикла:
{
"index": {
"lifecycle": {
"name": "main-policy"
}
}

В параметре name нужно указать имя только что созданной политики жизненного цикла.

Теперь индекс, который будет использовать этот шаблон индекса, также будет управлять созданной политикой жизненного цикла. Таким образом, через неделю после создания ILM удалит его и освободит место для нового индекса.

Заключение

Мы рассмотрели 4 способа оптимизации использования диска. Последний метод больше связан с полезной автоматизацией, которая может сэкономить много рабочих часов и обеспечить более крепкий и продолжительный сон.

Мы также получили результаты, которые показывают, что объем индексов действительно уменьшается. А использование комбинации всех способов существенно продлевает срок службы индексов. Теперь мы можем хранить старые данные и использовать их для анализа и статистики.

Буду рад советам и комментариям!