ElasticSearch для ведения журнала

Мы используем ElasticSearch у меня на работе для фронтальных веб-запросов. Производительность критическая, и для наших целей, данные в основном статические. Мы обновляем поисковые индексы ежедневно, но не имеем проблем запуска на старых индексах в течение нескольких недель. Большинство трафика на этом кластере забирает поиск; это "тяжелый для чтения" ("read heavy") кластер. У нас были некоторые сбои производительности в начале, но мы работали в тесном сотрудничестве с Шейем Бэнноном из ElasticSearch для ликвидации этих проблем. Теперь наши фронт-энд кластеры являются очень надежными, устойчивыми и быстрыми.

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

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

Макеты указателей

Две популярные системы маршрутизации журнала с открытым исходным кодом это Graylog2 и LogStash. На момент написания статьи, стабильная версия Graylog2 поддерживала только написание / чтение из одного индекса. Как я уже указывал в предыдущей статье, это представляет огромные проблемы масштабирования для Graylog2. Релиз Graylog2 0.10.0 будет включать в себя способность к индексированию к нескольким индексам. Однако, мой опыт был с индексами LogStash, поскольку это были единственные масштабируемые опции в прошлом.

Для того, чтобы получить максимальную отдачу от ElasticSearch во время журналирования, вы должны использовать несколько индексов. Есть несколько способов справиться с этим при пролонгировании индекса, но автоматическое суточное вращение LogStash по умолчанию, получается, имеет больше смысла. Таким образом, у вас получится что-то вроде:

  • logstash-2012.12.19
  • logstash-2012.12.20
  • logstash-2012.12.21
  • logstash-THE_WORLD_HAS_ENDED

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

Давай серьезно или иди домой.

Оба LogStash и Graylog2 поставляются со встроенным ElasticSearch патчем. Это очень удобно для демонстрационных целей или разработок. НЕ ИСПОЛЬЗУЙТЕ ЭТОТ ВСТРОЕННЫЙ СЕРВЕР ДЛЯ РЕАЛЬНЫХ ЦЕЛЕЙ! Я удивлен количеством пользователей LogStash и Graylog2, заканчивающих на #elasticsearch или irc.freenode.org, которые используют встроенный движок хранилища ElasticSearch и удивляются, что все обвалилось!

Запустите автономный кластер ElasticSearch!

Вам понадобится отдельное оборудование для этого. Java приложения, такие как LogStash и ElasticSearch являются интенсивными для памяти и дискового кэша. Зафиксируйте оборудование на коробках переработки индексации журнала и отдельные коробки к кластеру ElasticSearch. Java имеет некоторые странные проблемы с памятью. Мы обнаружили, что Вы не хотите просматривать 32 ГБ оперативной памяти, посвященной ElasticSearch, и резерв по меньшей мере, 8 Гб, посвященный индексированию файловой системы ОС кэширования.

Мой кластер обрабатывает ~ 60 Гб данных журнала в день в моей среде разработки с 3 поисковыми узлами на 24 Гб оперативной памяти каждый и это восторг. Это вызывает следующий вопрос, сколько серверов для моего кластера? Начните с 3 серверов в кластере ElasticSearch. Это дает вам гибкость для отключения сервера и поддержку в полной мере для использования кластера. Вы всегда можете добавить больше оборудования!

Установка ElasticSearch

Я не стану полностью описывать установку ElasticSearch, вы можете прочитать об этом больше на сайте документации. Вы можете даже решить удалить .deb или, возможно, запустить rpm и создать «рецепт» управления ElasticSearch с помощью Puppet или Chef. Единственная вещь, которую я скажу об установке, это то, что не смотря на все трудности, лучше всего запускать ElasticSearch с помощью Sun JVM. Так разработчики ElasticSearch пользуются ElasticSearch и вы тоже можете!

Конфигурация ElasticSearch: OS и Java

Есть некоторые вещи, которые вам действительно нужно настроить на хост-системе. Я предполагаю, что вы используете Linux в качестве хост-системы. Вы должны запустить ElasticSearch как непривилегированный пользователь. Мой кластер работает как пользователь “elasticsearch", потому мы настраиваем пределы ядра на процессы и память в '/etc/security/limits.conf':

# Ensure ElasticSearch can open files and lock memory!
elasticsearch   soft    nofile          65536
elasticsearch   hard    nofile          65536
elasticsearch   -       memlock         unlimited

Поэтому вы должны настроить минимальный и максимальный пул памяти ElasticSearch и установить в том же значении. Это берет на себя все распределения памяти при запуске, так что вам не придется ожидать, чтобы получить больше памяти из ядра. Я построил ElasticSearch в системе RedHat и он есть в моем '/etc/sysconfig/elasticsearch' которая устанавливает переменные среды для демона при запуске:

# Allocate 14 Gigs of RAM
ES_MIN_MEM=14g
ES_MAX_MEM="$ES_MIN_MEM"

Этот файл находится в ведении Puppet и устанавливает память, равную индексированию 50% от RAM + 2 гигабайта. Это не ракетостроение, и это рассматривается в каждом руководстве настройки ElasticSearch.

Конфигурация ElasticSearch: elasticsearch.yml

Есть некоторые вещи, которые мы можем настроить в файле ''elasticsearch.yml", которые значительно улучшат производительность тяжелых для записи узлов. Во-первых, установить bootstrap.mlockall на "да". Это заставляет JVM выделить все ES_MIN_MEM немедленно. Это означает, что у Java есть вся память, необходимая при запуске! Еще одна проблема тяжелого на запись кластера - это дисбаланс выделения памяти индексированию/объемному двигателю.

ElasticSearch предполагает, что вы собираетесь использовать его в основном для поиска, так что большинство вашего распределения памяти охраняется для поисков. Вопрос не в этом кластере, так, по настройке indices.memory.index_buffer_size до 50% мы можем восстановить баланс, необходимый для этого использования. В моей установке, я также поднимал интервал обновления и сделку рассчитывал на очистку журнала. В противном случае, ElasticSearch будет чистить транслогарифм почти каждую секунду.

Вторая вещь, которую мы должны настроить, чтобы избежать катастрофических неудач, это настройки пула потоков. ElasticSearch будет делать то, что по его мнению лучше всего для достижения самой высокой производительности. Мы выяснили, на производстве, что это может означать вылавливание тысяч и тысяч потоков для обработки входящих запросов. Это выведет весь кластер из строя довольно быстро под такой нагрузкой. Чтобы избежать этого, мы устанавливаем максимальное количество потоков в пул; поиск, индекс, и основной. Большинство наших операций будут громады, поэтому мы оставляем угрозам 60, и другим операциям 20. Мы также устанавливаем максимальное число запросов, которое может "стоять" в очереди на обработку 200 для громады и 100 для всего остального. Таким образом, если кластер становится перегруженным, он хочет отказаться от новых запросов, но он оставит вам достаточно файловых дескрипторов и идентификаторов PID, чтоб заглянуть в коробки и выяснить, что пошло не так.

Собрав все это вместе, вот мой конфигурационный файл:

 

 

 

  ##################################################################
  # /etc/elasticsearch/elasticsearch.yml
  #
  # Base configuration for a write heavy cluster
  #
   
  # Cluster / Node Basics
  cluster.name: logng
   
  # Node can have abritrary attributes we can use for routing
  node.name: logsearch-01
  node.datacenter: amsterdam
   
  # Force all memory to be locked, forcing the JVM to never swap
  bootstrap.mlockall: true
   
  ## Threadpool Settings ##
   
  # Search pool
  threadpool.search.type: fixed
  threadpool.search.size: 20
  threadpool.search.queue_size: 100
   
  # Bulk pool
  threadpool.bulk.type: fixed
  threadpool.bulk.size: 60
  threadpool.bulk.queue_size: 300
   
  # Index pool
  threadpool.index.type: fixed
  threadpool.index.size: 20
  threadpool.index.queue_size: 100
   
  # Indices settings
  indices.memory.index_buffer_size: 30%
  indices.memory.min_shard_index_buffer_size: 12mb
  indices.memory.min_index_buffer_size: 96mb
   
  # Cache Sizes
  indices.fielddata.cache.size: 15%
  indices.fielddata.cache.expire: 6h
  indices.cache.filter.size: 15%
  indices.cache.filter.expire: 6h
   
  # Indexing Settings for Writes
  index.refresh_interval: 30s
  index.translog.flush_threshold_ops: 50000
   
  # Minimum nodes alive to constitute an operational cluster
  discovery.zen.minimum_master_nodes: 2
   
  # Unicast Discovery (disable multicast)
  discovery.zen.ping.multicast.enabled: false
  discovery.zen.ping.unicast.hosts: [ "logsearch-01", "logsearch-02", "logsearch-03" ]
view raw elasticsearch.yml hosted with ❤ by GitHub

Конфигурация ElasticSearch: Шаблоны индексов

Как я уже говорил, я разработал этот кластер на основе LogStash из-за недостатков в реализации Graylog2 в то время. Данный раздел будет содержать понятие "журнальная нычка", но вы можете легко адаптировать это к Graylog2 или домашнему отображению индекса.

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

Настройки моего шаблона:

  {
  "template": "logstash-*",
  "settings" : {
  "index.number_of_shards" : 3,
  "index.number_of_replicas" : 1,
  "index.query.default_field" : "@message",
  "index.routing.allocation.total_shards_per_node" : 2,
  "index.auto_expand_replicas": false
  },
  "mappings": {
  "_default_": {
  "_all": { "enabled": false },
  "_source": { "compress": false },
  "dynamic_templates": [
  {
  "fields_template" : {
  "mapping": { "type": "string", "index": "not_analyzed" },
  "path_match": "@fields.*"
  }
  },
  {
  "tags_template" : {
  "mapping": { "type": "string", "index": "not_analyzed" },
  "path_match": "@tags.*"
  }
  }
  ],
  "properties" : {
  "@fields": { "type": "object", "dynamic": true, "path": "full" },
  "@source" : { "type" : "string", "index" : "not_analyzed" },
  "@source_host" : { "type" : "string", "index" : "not_analyzed" },
  "@source_path" : { "type" : "string", "index" : "not_analyzed" },
  "@timestamp" : { "type" : "date", "index" : "not_analyzed" },
  "@type" : { "type" : "string", "index" : "not_analyzed" },
  "@message" : { "type" : "string", "analyzer" : "whitespace" }
   
  }
  }
  }
  }

 

Чтоб применить настройки к кластеру, мы создаем или обновляем шаблон с помощью PUT:

curl -XPUT 'http://localhost:9200/_template/template_logstash/' -d @logstash-template.json

Установка шаблона logstash-* означает все новые индексы, созданные и начинающиеся с "logstash-" будут обладать этими параметрами. Я переопределил поведение поиска по умолчанию, отключив поиск полях _all и установив атрибут @message по умолчанию. Это поле будет сырым syslog-сообщением. Это, следовательно, единственное поле, в котором анализатор отключен. Не волнуйтесь. Это экономия пространства и времени индексирования. Поиск других полей в документе будет соответствовать помощи в поиске точных совпадений, а не нечетких запросов, но это нормально. Мы можем спокойно получить это нестабильное теплое чувство, ища поле @message! Это позволит резко уменьшить размер хранилища.

В предыдущих рецензиях, до ElasticSearch 0.19, вы, возможно, видели 6набор атрибутов"_source": { "compress": true }. Не рекомендуется для регистрации данных. Этот атрибут детерминирует каждый ли документ (читай: входящее сообщение) хранится с использованием сжатия. Так как эти документы, как правило, очень маленькие, сжатие не сэкономит реально много места. Это стоит дополнительной обработки во время индексации и поиска. Лучше действительно отключить сжатие для регистрации кластера. Установка, которая позволяет хранение сжатия в нашей elasticsearch.yml использует сжатие на уровне блоков и является гораздо более эффективной.

Установки индекса

Настройки индекса настроены на 3 узла кластера. Мы можем все изменить, но index.number_of_shards спохватится на лету, если нам нужно увеличить или уменьшить кластер. Данная установка не точно идеальна, как мы иногда имеем дело с "осиротевшими" (нераспределенными) шардами. Это достаточно легко исправить путем перемещения шардов к ElasticSearch API.

Вместо репликации всего индекса во весь кластер, мы добавляем емкость, поскольку мы добавляем узлы. Таким образом у нас есть схожая с "RAID" установка для локализации шардов. У меня есть 3-узловой кластер и я создаю 3 шарда на индекс. Это означает, что мастер или "пишущий" шард могут быть сбалансированы в один на каждом узле. Для резервирования, я поставил ряд реплик на один. Это означает, что есть 6 шардов для каждого индекса. Каждый узел может иметь только 2 шарда на индекс.

Вы должны будете поэкспериментировать с этими настройками для ваших нужд. Примите во внимание, сколько узлов вы можете позволить себе потерять, прежде чем потерять функциональность. Вы должны будете регулировать количество реплик на основе этого. Я пошел по простому пути и просто создал 1 реплику шарда. Данное значит, я могу только сохранить только единственный узел от кластера. Пока, я понял, что, number_of_replicas равные (2/3 * Количество узлов) - 1 это хороший номер.

Автоматически разворачивающиеся реплики

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

  • Все хорошо, число реплик = 1.
  • Узел A закрывается
  • Кластер это замечает и становится желтым
    • реплик = 0, ожидается 1
    • количество узлов сейчас = 1
    • кол-во реплик, ожидающихся = 0 сейчас
  • Состояние кластера улучшено до зеленого, все обновлено
  • Узел возвращается в онлайн
  • Кластер посылает количество ожидаемых реплик, актуальных для всех индексов
  • Узел понимает, что это шарды не нужны, и удаляет данные
  • Кластер увеличивает количество узлов, реплики ожидаются = 1, текущая = 0
  • Узел осведомлен, что количество реплик еще не соответсвует
  • Узел повторяет каждый шард обратно в его индекс, по сети

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

  • Все хорошо.
  • Узел выключается
  • Кластер это замечает, статус кластера желтый
  • Состояние кластера не улучшается, ожидаемые реплики! = фактическим репликам
  • Узел А возвращается
  • Кластер посылает количество ожидаемых реплик и актуальных для всех индексов
  • Узел А уведомляет кластер, что у него есть копии шардов
  • Ожидаемый кластер и фактические реплики в настоящее время равны, состояние "зеленое"
  • Кластер вычисляет контрольные шарды и повторяет любые устаревшие шарды к узлу А

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

Техническое обслуживание и мониторинг

Я написал несколько скриптов для работы с ElasticSearch в среде разработки. Они включают экспорт метрик в Graphite и Cacti. Существует, следовательно, проверка мониторинга Nagios, которая очень конфигурируемая. Мы используем эти утилиты для отслеживания производительности и состояния наших различных кластеров, включая журналоведческий кластер. Я буду обновлять это в ближайшие несколько дней, чтобы включить мой скрипт управления индексом logstash.

В процессе того, как вы пишете ваши данные в журнал кластера, ElasticSearch создает индекс Lucene  логовых сообщений в фоновом режиме. Существует буфер входящих документов и на основе ваших настроек, эти данные записываются на индекс Lucene. Индексы Lucene дорогие для создания / обновления, но быстрые для поиска. Это означает, что один шард может содержать сотни индексов Lucene, которые часто называют сегментами. Эти сегменты могут быть быстро найдены, но только один на поток может быть обработан. Это может начать оказывать негативное влияние на производительность. Мы видели, ухудшение скорости поиска на 10% с индексами с 20+ сегментов.

К счастью, ElasticSearch предоставляет API для оптимизации сегментов Lucene. Вы не должны оптимизировать индекс, в настоящее время индексирующий данные. Новые данные будут просто создавать больше сегментов на тех шардах. Так как мы можем знать, что мы закончили записи на индекс? Ну, если вы помните, я рекомендовал использовать ежедневный индекс. Это означает, что вы можете запустить задание ежедневно (или каждый час), чтобы проверить наличие индексов с вчерашнего дня и старше и убедиться, что они 'повторно оптимизированы (или max_num_segments = 1). Если вы выбрали какую-то другую схему для создания имен индексов, вы только что создали больше работы для себя.

Будущие изыскания

Этот пост оказался больше, чем я ожидал. Я показываю только поверхностный взгляд на разработку и реализацию кластера ElasticSearch для логгируемых данных. Мой кластер будет двигаться от разработки к производству в ближайшее время (хотя он и в настоящее время обеспечивает производственные функции). Когда я что-то делаю, я готов столкнуться с некоторыми дополнительными трудностями и у меня есть ноутбук, полный идей о том, как структурировать индексы и кластеры и справиться с нагрузкой и некоторыми из частных проблем, которые возникают, когда вы вдруг предоставляете простой, быстрый доступ к огромным объемам данных.

Перевод статьи с английского