Статьи

Воспроизведение Slowlogs Elasticsearch с Logstash и JMeter

Иногда нам просто нужно воспроизвести производственные запросы — будь то из-за того, что мы хотим реалистичного нагрузочного теста для новой версии продукта или из-за того, что мы хотим воспроизвести в тестовой среде ошибку, которая возникает только в рабочей среде (разве это не мило? когда это происходит? Все хорошо в тестах, но когда вы внедряете, тонны исключений в ваших журналах , тонны предупреждений от системы мониторинга …).

С Elasticsearch вы можете включить медленные журналы, чтобы они регистрировали запросы, занимающие больше времени (на шард), чем определенный порог. Вы можете изменить настройки по требованию. Например, следующий запрос запишет все запросы для test-index:

curl -XPUT localhost:9200/test-index/_settings -d '{
  "index.search.slowlog.threshold.query.warn" : "1ms"
}'

Вы можете запускать эти запросы из медленного журнала в тестовой среде с помощью такого инструмента, как JMeter . В этой статье мы рассмотрим, как анализировать медленные журналы с помощью Logstash для записи только запросов в файл, и как настроить JMeter для выполнения запросов из этого файла в кластере Elasticsearch.

Разбор Slowlogs с Logstash

Первый шаг — получить фактический запрос JSON из медленных журналов и поместить его в файл, по одному запросу на строку. Это позволит JMeter собирать запросы и воспроизводить их. Ниже вы можете найти конфигурацию Logstash, полученную из конфигурации, описанной в предыдущем посте о разборе журналов Elasticsearch с Logstash . Интересующее нас поле — это source_body , которое содержит каждый запрос. Мы поместим его в файл запросов ( / var / tmp / just_queries ) по одному на строку через кодек json_lines .

input {
  file {
    path => "/var/log/elasticsearch/elasticsearch-test_index_search_slowlog.log"
    start_position => "beginning"
  }
}

filter {
  grok {  # parses the common bits
    match => [ "message", "\[%{TIMESTAMP_ISO8601}\]\[%{DATA}%{SPACE}\]\[%{DATA}%{SPACE}\]%{SPACE}\[%{DATA}\]%{SPACE}\[%{DATA}\]\[%{DATA}\] took\[%{DATA}\], took_millis\[%{DATA}\], types\[%{DATA}\], stats\[%{DATA}\], search_type\[%{DATA}\], total_shards\[%{DATA}\], source\[(?(.|\r|\n)*\], extra_source\[)%{DATA}" ]
  }

  mutate {
    gsub => [
      "source_body", "\], extra_source\[$", ""
    ]
  }
}

output {
  file {
    path => "/var/tmp/just_queries"
    codec => "json_lines"
    message_format => "%{source_body}"
  }
}

Создание плана испытаний JMeter

Далее нам нужен план тестирования JMeter, чтобы запустить его. Для этого вы должны загрузить и запустить JMeter, который откроет новый план тестирования. Щелкните правой кнопкой мыши значок «План тестирования» слева и выберите «Добавить» -> «Темы (пользователи)» -> « Группа нитей» . Там вы можете указать, сколько потоков (как если бы они были параллельными пользователями) будут выполнять запросы и сколько запросов запускать для каждого потока.

В этой группе потоков мы создадим элемент config, который читает запросы, и сэмплер, который будет выполнять эти запросы через HTTP.

Чтение запросов в переменную

Для чтения запросов вы можете использовать CSV Data Set Config . Вы щелкнете правой кнопкой мыши по группе потоков, перейдите в «Добавить» -> «Элемент конфигурации» -> «Конфигурация набора данных CSV». Вам нужно добавить имя файла, содержащего ваши запросы ( / var / tmp / just_queries в этом примере), имя переменной, которая получает запрос ( BODY в этом примере) и указать, что запросы разделяются символом новой строки ( \ n ).

jmeter_csv

Использование переменной в HTTP-запросах

С запросами в переменной BODY последним шагом является создание сэмплера HTTP-запроса, который будет выполнять эти запросы. Щелкните правой кнопкой мыши группу потоков, выберите «Добавить» -> «Сэмплер» -> «HTTP-запрос». Затем необходимо внести следующие изменения:
— указать хост и порт для выполнения запросов. Если вы запустите их удаленно, вероятно, это будет localhost: 9200
— измените Method на POST . Это важно, потому что GET игнорирует тело сообщения, где будет находиться ваш запрос
— путь URL. Обычно INDEX-NAME / _search
— укажите, что $ {BODY} будет телом сообщения

jmeter_http

Запускайте запросы удаленно с помощью JMeter

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

bin/jmeter -n -t /path/to/test-plan.jmx -l /path/to/output-file.jtl

Затем вы можете скопировать файл результатов обратно на свой компьютер и проанализировать его с помощью графического интерфейса JMeter.

Проверка результатов

Чтобы проверить результаты, JMeter предлагает довольно много агрегатов. Часто мне просто нужны сводные числа, и для этого я использую сводный отчет (щелкните правой кнопкой мыши План тестирования -> Добавить -> Слушатель -> Сводный отчет). Там я могу найти файл JTL и открыть его, чтобы увидеть среднее время запросов, пропускную способность и так далее:

jmeter_summary

Проверка отдельных результатов запроса

Если вам что-то не так с результатами (например, слишком малое время запроса), вы можете проверить, что Elasticsearch отвечает на каждый запрос, используя представление дерева результатов . Возможно, вы захотите использовать для этого пользовательский интерфейс JMeter, а для пересылки запросов с вашего компьютера вы можете перенаправить порт удаленного сервера через SSH:

ssh -L 9200:localhost:9200 user@elasticsearch01

И тогда вы будете выполнять запросы от вашего локального JMeter против localhost: 9200 .

Чтобы просмотреть результаты во время выполнения теста, щелкните правой кнопкой мыши группу потоков и выберите «Добавить» -> «Слушатель» -> «Просмотреть дерево результатов». Там вы можете выбрать любой запрос и просмотреть запрос, который был отправлен в Elasticsearch, и получить ответ, чтобы убедиться, что он соответствует вашим ожиданиям.

jmeter_results_tree

Заключительные слова

У этой процедуры есть некоторые ограничения — вот два основных, о которых я знаю:
— мы выполняем запросы к жестко закодированному индексу. В идеале мы извлекаем имя индекса из slowlog и используем его как переменную в JMeter
— slowlogs для каждого шарда, поэтому, если клиентский запрос встречает пять сегментов и все они пересекают порог slowlog, у вас будет пять идентичных запросов в журнале, и JMeter воспроизведет их все. Вы можете получить только один запрос от одного из сегментов (например, путем фильтрации по номеру сегмента в Logstash), но часто с нагрузочными тестами будет хорошо, если вы увеличите нагрузку на кластер.

Надеюсь, вы сочли этот пост полезным, и если вас так волнует, я рад сообщить, что Sematext  нанимает людей по всему миру . Вы также можете подписаться на нас @sematext .

[ Примечание: мы проводим 2-дневный практический семинар Elasticsearch / ELK Stack в Нью-Йорке с 19 по 20 октября 2015 г. Нажмите здесь для подробностей!]