Оптимальный размер шардов: баланс производительности и управления кластером

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

Оптимальный размер шардов: баланс производительности и управления кластером

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

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

Основы шардов Elasticsearch

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

  • Индекс: Коллекция документов. В Elasticsearch индекс делится на несколько шардов.
  • Шард: Единица распределения. Каждый шард — это самостоятельный индекс Lucene. Индекс может содержать несколько шардов, распределенных по разным узлам кластера.
  • Первичный шард: При создании индекса ему назначается количество первичных шардов. В эти шарды индексируются ваши данные. Нельзя просто изменить number_of_shards в существующем индексе, но Elasticsearch предоставляет операции split и shrink при определенных условиях. Многие команды по-прежнему считают количество первичных шардов решением на этапе проектирования, поскольку его изменение позже требует планирования.
  • Шард-реплика: Копии ваших первичных шардов. Они обеспечивают избыточность и увеличивают пропускную способность чтения. Если первичный шард выходит из строя, реплика может быть повышена до первичной. Количество шардов-реплик можно изменить в любое время.

Как шарды влияют на производительность

  • Производительность индексации: Каждый шард требует ресурсов для индексации. Больше шардов означает больше накладных расходов для координирующих узлов, управляющих запросами. Однако, если шарды становятся слишком большими, индексация в один шард может стать узким местом.
  • Производительность запросов: Поисковые запросы распределяются по всем соответствующим первичным шардам. Большее количество шардов может увеличить количество обрабатываемых запросов, потенциально увеличивая задержку. И наоборот, очень большие шарды могут привести к увеличению времени поиска, так как Lucene приходится обрабатывать больше данных в рамках этого шарда.
  • Управление кластером: Большое количество шардов увеличивает нагрузку на главный узел, отвечающий за управление состоянием кластера. Это также влияет на накладные расходы таких операций, как перемещение шардов, создание снимков и восстановление.
  • Использование ресурсов: Каждый шард потребляет память и дисковый ввод-вывод. Слишком много шардов может исчерпать ресурсы узла, что приведет к снижению производительности или нестабильности узла.

Ключевые соображения по размеру шардов

«Идеальный» размер шарда — не фиксированное число; он зависит от вашей конкретной рабочей нагрузки, характеристик данных и оборудования. Тем не менее, несколько факторов должны направлять ваши решения:

1. Объем данных и скорость роста

  • Текущий размер данных: Сколько данных у вас сейчас в индексе?
  • Скорость роста: Как быстро растут ваши данные? Это помогает прогнозировать будущие размеры шардов.
  • Политика хранения данных: Будете ли вы удалять старые данные? Это влияет на эффективный размер активных данных.

2. Нагрузка на индексацию

  • Скорость индексации: Сколько документов в секунду вы индексируете?
  • Размер документа: Каков средний размер отдельных документов?
  • Пропускная способность индексации: Могут ли ваши узлы справиться с нагрузкой индексации при текущей конфигурации шардов?

3. Шаблоны запросов

  • Сложность запросов: Ваши запросы — это простые поиски по ключевым словам или сложные агрегации?
  • Частота запросов: Как часто выполняются запросы к вашим данным?
  • Требования к задержке запросов: Каковы приемлемые времена отклика?

4. Топология кластера и ресурсы

  • Количество узлов: Сколько узлов в вашем кластере?
  • Аппаратное обеспечение узлов: ЦП, ОЗУ и диск (для Elasticsearch настоятельно рекомендуется SSD).
  • Лимиты шардов: Elasticsearch включает ограничения безопасности, которые предотвращают хранение узлом чрезмерного количества открытых шардов. В последних версиях обычно используется cluster.max_shards_per_node в качестве обще кластерного ограничения для обычных открытых индексов. cluster.routing.allocation.total_shards_per_node отличается: он ограничивает количество шардов из одного индекса или соответствующей области распределения, которые могут быть выделены одному узлу. Проверьте версию Elasticsearch перед изменением любого из этих параметров.

Лучшие практики распределения шардов

1. Стремитесь к целевому размеру шарда

Хотя магического числа не существует, многие производственные кластеры стремятся к размеру шардов около 10–50 ГБ для типичных рабочих нагрузок с логами и поиском. Этот диапазон — отправная точка, а не правило. Системы с очень высокой пропускной способностью или длительным хранением могут выбрать более крупные шарды после тестирования; индексы поиска для малого бизнеса могут лучше всего работать с одним маленьким шардом.

  • Слишком маленький (< 10 ГБ): Может привести к чрезмерным накладным расходам. Каждый шард имеет объем памяти и увеличивает нагрузку на главный узел. Управление тысячами крошечных шардов становится значительным эксплуатационным бременем.
  • Слишком большой (> 50 ГБ): Может вызвать проблемы с производительностью. Слияние сегментов, восстановление и операции ребалансировки занимают больше времени. Если большой шард выходит из строя, его восстановление может занять значительное время.

2. Рассмотрите временные индексы

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

  • Пример: Вместо одного массивного индекса у вас могут быть logs-2023.10.26, logs-2023.10.27 и т.д.
  • Преимущества: Более простое управление данными (удаление старых индексов через Index Lifecycle Management - ILM), лучшая производительность, так как запросы часто нацелены на недавние данные, и контролируемые размеры шардов.

3. Внедрите управление жизненным циклом индексов (ILM)

Политики ILM позволяют автоматизировать управление индексами на основе возраста, размера или количества документов. Вы можете определить фазы для индекса (горячая, теплая, холодная, удаление) и указать действия для каждой фазы, включая изменение количества реплик, сжатие индексов или их удаление.

  • Горячая фаза: Индекс активно записывается и запрашивается. Максимальная производительность.
  • Теплая фаза: Индекс больше не записывается, но все еще запрашивается. Может быть перемещен на менее производительное оборудование, возможно, с меньшим количеством реплик или сжат.
  • Холодная фаза: Редко запрашивается. Данные могут быть перемещены на более дешевое хранилище или узлы с более низкой производительностью, в зависимости от вашей лицензии Elasticsearch, версии и архитектуры.
  • Фаза удаления: Данные больше не нужны и удаляются.

4. Избегайте избыточного шардирования

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

  • Симптомы: Высокая загрузка ЦП на главных узлах, медленные обновления состояния кластера, длительное время восстановления и общая вялость.
  • Смягчение: Планируйте количество первичных шардов с самого начала. Для временных индексов начните с разумного количества первичных шардов на индекс (например, 1 или 3). Вы всегда можете добавить реплики позже.

5. Не создавайте избыточное количество индексов

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

6. Учитывайте параметр number_of_shards

При создании индекса параметр number_of_shards определяет количество первичных шардов. Этот параметр неизменяем после создания индекса.

PUT my-index
{
  "settings": {
    "index": {
      "number_of_shards": 3,  // Пример: 3 первичных шарда
      "number_of_replicas": 1   // Пример: 1 шард-реплика
    }
  }
}
  • Совет: Для небольших индексов или индексов с очень низкой нагрузкой на индексацию/запросы может быть достаточно одного первичного шарда. Для более крупных и активных индексов 3 или 5 первичных шардов могут обеспечить лучшее распределение и отказоустойчивость, особенно если вы планируете разделить индекс позже (хотя разделение сложно).

7. Ребалансировка и перемещение

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

8. Настройка производительности запросов

Если производительность ваших запросов страдает, оцените свою стратегию шардирования. Учитывайте:

  • Количество шардов: Слишком много шардов может увеличить накладные расходы на координацию.
  • Размер шарда: Очень большие шарды могут замедлить слияние сегментов и поиск внутри шарда.
  • Дизайн индекса: Используете ли вы соответствующие маппинги и анализаторы?

Расчет оптимального количества шардов

Не существует единой формулы, но вот распространенный подход:

  1. Оцените общий объем данных на индекс в течение его жизненного цикла.
  2. Определите целевой размер шарда (например, 30 ГБ).
  3. Рассчитайте необходимое количество первичных шардов: Общий объем данных / Целевой размер шарда.
  4. Округлите вверх до ближайшего целого числа. Это даст вам number_of_shards для индекса.
    • Пример: Если вы ожидаете 90 ГБ данных и стремитесь к шардам по 30 ГБ, вам понадобится 90 ГБ / 30 ГБ = 3 первичных шарда.
  5. Учитывайте отказоустойчивость и распределение: Для критически важных индексов рассмотрите использование 3 или 5 первичных шардов, чтобы обеспечить лучшее распределение и возможности восстановления, даже если ваш начальный объем данных этого строго не требует. Компромисс — увеличенные накладные расходы.
  6. Начинайте консервативно: Обычно проще добавить реплики, чем изменить количество первичных шардов (что обычно требует переиндексации или сложных обходных путей). Если сомневаетесь, начните с меньшего количества первичных шардов и отслеживайте производительность.

Пример сценария: Анализ логов

Допустим, вы индексируете логи приложений:

  • Объем данных: Вы ожидаете 1 ТБ логов в месяц.

  • Хранение данных: Вы храните логи 30 дней.

  • Целевой размер шарда: Вы стремитесь к 20 ГБ.

  • Ежедневные индексы: Вы создаете ежедневные индексы (logstash-YYYY.MM.DD). Каждый ежедневный индекс будет содержать примерно 1 ТБ / 30 дней ≈ 33 ГБ данных.

  • Первичные шарды на индекс: Учитывая целевой размер 20 ГБ и ежедневный объем 33 ГБ, вы можете выбрать 2 первичных шарда на индекс (33 ГБ / 20 ГБ ≈ 1,65, округлено до 2). Это гарантирует, что отдельные шарды останутся в пределах целевого размера.

  • Реплики: Вы решаете использовать 1 реплику для высокой доступности.

  • Всего шардов: За 30-дневный период хранения у вас будет 30 индексов, каждый с 2 первичными и 2 шардами-репликами, всего 60 первичных и 60 шардов-реплик, активных в любой момент времени.

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

Что обычно идет не так

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

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

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

Лучший шаблон переключения

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

PUT _ilm/policy/logs-policy
{
  "policy": {
    "phases": {
      "hot": {
        "actions": {
          "rollover": {
            "max_primary_shard_size": "30gb",
            "max_age": "1d"
          }
        }
      },
      "delete": {
        "min_age": "30d",
        "actions": {
          "delete": {}
        }
      }
    }
  }
}

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

Как проверить текущие шарды

Прежде чем что-либо менять, посмотрите на свой кластер:

GET _cat/shards?v&h=index,shard,prirep,state,docs,store,node&s=store:desc
GET _cat/indices?v&h=index,pri,rep,docs.count,store.size,pri.store.size&s=pri.store.size:desc
GET _cluster/health

Вы ищете закономерности: много крошечных шардов, несколько огромных шардов, неназначенные шарды, неравномерное размещение узлов или индексы, размер первичного хранилища которых далек от вашего целевого. Если в одном индексе 100 ГБ первичных данных и пять первичных шардов, каждый первичный шард составляет примерно 20 ГБ до реплик. Если в том же индексе 100 ГБ и 50 первичных шардов, вы, вероятно, создали ненужные накладные расходы.

Заключительные замечания

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