Компания
315,84
рейтинг
14 ноября 2013 в 12:34

Разработка → Наши танки. История нагрузочного тестирования в Яндексе

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

image

Кстати, если вам понравится этот рассказ, приходите на Тестовую среду в нашем питерском офисе 30 ноября (зарегистрироваться), – там я расскажу больше об игровых механиках в тестировании и с удовольствием вживую с вами поговорю. Итак.

В 2005-2006 годах часть не поисковой инфраструктуры Яндекса стала испытывать нагрузки растущего как на дрожжах Рунета. Появилась необходимость тестировать производительность смежных с поиском сервисов, в первую очередь — баннерную крутилку. Тимур Хайруллин, на тот момент руководивший нагрузочным тестированием, озадачился поиском подходящего инструмента.

Но существующие в то время открытые решения были либо очень примитивны (ab/siege), либо недостаточно производительны (jmeter). Из коммерческих утилит выделялся HP Load Runner, но дороговизна лицензий и завязка на проприетарный софт нас не обрадовала. Поэтому Тимур вместе с разработчиком высокопроизводительного веб-сервера phantom Женей Мамчицем придумали хитрый трюк: они научили сервер работать в режиме клиента. Так получился модуль phantom-benchmark. Сам код фантома теперь открыт и его можно скачать отсюда, а рассказ про фантом можно посмотреть видео с презентации здесь.

Тогда Phantom был очень прост, умел измерять только максимальную производительность сервера, а мы могли лишь ограничивать количество потоков. Но уже в то время наша утилита была на голову производительней аналогов. Поэтому за нагрузочным тестированием к нам стали обращаться все чаще и все больше сервисов. С 2006 до 2009 года команда нагрузочного тестирования разрослась до десяти человек. К нам очень быстро прикрепилось название «танкисты», которые заряжают «ленты» с «патронами» и “стреляют” из «танков» по «мишеням». Танковая тематика до сих пор с нами. Для экономии ресурсов мы создали специальный «полигон» или «курятник», где держали виртуальные машины для нагрузочного тестирования. Платформа виртуализации в то время была на openvz, а сейчас мы полностью перешли на lxc из-за лучшей поддержки новых ядер и дистрибутивов ubuntu server. Респект сообществу lxc!

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

При содействии разработчиков и под руководством «танкиста» Андрея baabaka Кузьмичева мы стали развивать phantom в настоящий фреймворк для поддержки нагрузочного тестирования — Лунапарк. Ранее из-за плохой организации отчетов результаты складировались бессистемно — в Wiki, JIRA, почту и пр. Это было очень неудобно, мы вложили много труда в это больное место и постепенно у нас появился настоящий веб-интерфейс с дашбордом и графиками, где все тесты были провязаны с тикетами в JIRA, все отчеты наконец получили единообразие и понятный дизайн. Веб-интерфейс научился отображать процентили, тайминги, средние времена, коды ответа, объем получаемых и передаваемых данных и еще около 30 различных графиков и таблиц. Помимо этого Лунапарк был провязан с почтой, джаббером и другими сервисами. Изменения не обошли стороной и сам генератор нагрузки Phantom — он научился делать очень многое из того, чего не умел раньше. Например, подавать запросы по расписанию — линейно, ступенчато, снижать нагрузку и даже(!) подавать нулевую и дробную нагрузку. В консольный вывод добавился агрегационный вывод с процентилями, мониторинг объема данных, ошибок, ответов. Так выглядел консольный вывод образца 2009 года.

image

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

image

image

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

В 2011 году произошло важное событие — мы стали первой командой в Яндексе, запустившей настоящую геймификацию рабочего процесса, о которой у меня будет отдельный доклад на Тестовой среде. Такое даже сейчас редко встречается и в самых продвинутых IT-компаниях. На странице Лунапарка мы разместили «Зал Cлавы» и очень гордимся этой частью фреймворка. За конкретный тест можно сказать нагрузочному тестировщику настоящее дружеское «Спасибо!». Каждый тестер получает различные бэйджи за то или иное событие, становится «командиром танка» (а-ля мэром в Форскверике) и даже “звание”, которое выдается за число проведенных тестов. Среди рутинной работы любая ачивка или спасибка на вес золота. Это очень здорово мотивирует.

image

2011 год мы считаем переломным в нашем нагрузочном тестировании. Команду разработки возглавил Андрей undera Похилько. Сообщество тестеров знает его как разработчика замечательных плагинов для Jmeter. Андрей принес свежие идеи и подходы, которые сейчас очень помогают в работе.

Во-первых, мы поняли, что развивать инструмент в старой парадигме «некогда объяснять, кодируй» не получается, и перешли на модульную парадигму разработки, где большой монолит разбивается на компоненты и развивается отдельным частями, не создавая угрозу всему проекту. Во-вторых, так как заказы на нагрузочное тестирование стали поступать от сервисов, которым http-трафик был не интересен, нам понадобился инструмент, которым можно было бы тестировать SMTP/POP3/FTP/DNS и прочие протоколы. Писать phantom-протоколеры на каждый такой сервис нам показалось дорого, и мы решили встроить в Лунапарк обычный Jmeter. Тем самым небольшими усилиями мы научились поддерживать в нагрузочном тестировании несколько десятков новых протоколов. Встраивание помогло нам оставить стандартный вебинтерфейс без перехода на Jmeter GUI. Помимо поддержки Jmeter наш танк со временем научился поддерживать SSL, IPv6, UDP, elliptics, “мультитесты” в несколько адресов с одного генератора, подачу нагрузки в несколько миллионов rps с распределенных генераторов и многое другое.

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

  • Для тестирования прототипов или экспериментальных сборок мы сделали отчуждаемую версию генератора нагрузки и, чтобы не отвлекать нагрузочников от более подготовленных проектов, стали рекомендовать ее разработчикам или системным администраторам для отладочных нагрузочных тестов своего прототипа. Получаемые результаты совместимы с фреймворком Лунапарк и не бывает ситуаций «я потестировал свой прототип с помощью ab, он выдавал 1000 rps, а в Лунапарке только 500!».
  • Для тестирования разовых или событийных сервисов, где нагрузка может внезапно вырастать в несколько раз (Спорт, ЕГЭ, Новости, Промопроекты), мы держим быстроподнимаемые виртуальные машины, где раскатываются готовые пакетированные сервисы. Тесты проходят в ручном режиме со снятием удаленной телеметрии с объекта нагрузки. Иногда процесс координируется в специальных чат-комнатах, где может сидеть до 5-10 человек: “танкистов”, разработчиков, менеджеров. По нашей внутренней статистике 50% ручных тестов(!) вылавливают различные проблемы с производительностью — от неправильно построенных индексов, “спайков” на файловых операциях, недостаточного количества воркеров и тд. Окончательные результаты документируются в JIRA.

Пример онлайн страницы проводимого теста.
image

Для анализа по желанию можно включать дополнительные графики, например, времена ответа.

image

HTTP и сетевые ошибки:

image

Времена на разных стадиях взаимодействия и потоки:

image

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

В конце 2011 мы поняли, что по сути все операции теста могут делаться скриптами, вызовами, или, проще говоря, каким-то исполняющим механизмом. Идеологически ближе всего к такой деятельности стоят CI фреймворки, которые умеют собирать проекты, запускать набор тестов, уведомлять о событиях и выносить вердикт о прохождении. Мы посмотрели на варианты этих инструментов и обнаружили, что открытых фреймворков не так много. Jenkins показался нам наиболее удобным для расширения функциональности с помощью плагинов и, потестировав его рядом с Лунапарком, внедрили его в тестирование. С помощью внешних вызовов к специальному API и встроенного планировщика мы смогли переложить всю рутинную работу тестеровщика на Jenkins. Разработчики получили заветную кнопку «Протестировать мой сервис сейчас!», нагрузочники получили десятки, а то и сотни тестов в день без их участия, менеджеры и системные администраторы получили регрессионные графики производительности от билда к билду. На данный момент автоматические тесты составляют около 70% от всего потока, и этот показатель постоянно растет. Это экономит нам десятки человек в штате и позволяет сконцентрировать интеллект тестера на ручных и исследовательских тестах.

image

Внимательный читатель заметит, что постепенно Лунапарк стал представлять собой раздельную структуру: отчуждаемый лоад-генератор, бэкенд для статистики и телеметрии, а также отдельный автоматизационный фреймворк. Окинув это взглядом и зная, что с YAC'10, где baabaka рассказывал про Лунапарк, тестеры всего Рунета при каждом удобном случае троллят нас открытием Лунапарка наружу, мы решили выложить часть Лунапарка в opensource. Летом 2012 года на одном из Яндекс.Субботников в Москве мы представили лоад-генератор сообществу тестировщиков. Сейчас Яндекс.Танк с легкими графиками, со встроенной поддержкой jmeter и ab развивается только на внешнем гитхабе, мы отвечаем на вопросы пользователей в клубике и принимаем внешние пулреквесты от разработчиков.

Мы знаем, что сообщество нагрузочных тестировщиков в Рунете невелико, доступные знания очень скудны и поверхностны, но тем не менее, интерес к теме производительности только нарастает. Поэтому будем рады поделиться накопленным опытом и знаниями в этой области и обещаем периодически публиковать статьи на тему нагрузок, инструментария и методов тестирования.
Автор: @doctornkz
Яндекс
рейтинг 315,84

Комментарии (47)

  • +6
    Бейджики из 4sq…
    • +5
      Вы правы, надо как-нибудь перерисовать и выложить в опенсорс сразу.
  • +1
    Анализируете ли вы по результатам теста server side метрики? Время выполнения sql-запросов, утилизация диска, процессора?
    Если да, то как их получаете? Есть ли единый инструмент сбора, или с миру по нитки? :)
    • +1
      Присоединяюсь к вопросу.
      Еще бывает интересно насколько изменилась (и изменилиась ли вообще) производительность/отзывчивость сервиса при обновлении ядра, системных пакетов, зависимостей и т.п.
      • 0
        Второй пункт — это все тоже регрессионное тестирование как и в случае нового релиза. Так что это вопрос не технологий, а желания заказчика тестирования. Исходя из описанного, это происходит в большинстве автоматически.
        • 0
          Регрессионное тестирование, это все же отслеживание метрик производительности на большом временном интервале с большим количеством релизов. Он нужен с целью понять тренд производительности.

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

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

          Необходимо просто сделать несколько тестов, сравнить метрики производительности (пропускная способность / время ответа и их распределение / конкуренция). Сравнить системные и софтовые метрики.
          • 0
            Это все и есть регресс. Миша, то что ты описал, лишь уровень анализа.
            • 0
              Данила, я разделяю эти понятия, т.к. в них разные цели тестирования.
              Мне так проще:) Разделяю т.к. исследования нельзя автоматизировать, а вот регрессию разных релизов можно.
              • 0
                В том и дело, что цель, «сравнить версии систем», одна, а вот задачи в рамках достижения цели отличаются.

                Уровень автоматизации в данном случае (полагаем состав профиля постоянным) зависит от глубины анализа. Само скриптогоняние от этого не должно меняться, меняется только система.
    • +2
      В yandex-tank есть отдельный модуль мониторинга.

      В начале теста yandex-tank заходит по ssh на указанные машины и снимает системные метрики. Есть возможность указания кастомных метрик.

      Конфиг мониторинга выглядит примерно так. Для наглядности добавил кастомную метрику количества всех TCP-сокетов на системе.
      <Monitoring>
        <Host address="xxx.load.net">
          <CPU measure="user,system,iowait"/>
          <System measure="csw,int"/>
          <Memory measure="free,used"/>
          <Disk measure="read,write"/>
          <Net measure="recv,send"/>
          <Custom measure="call">ss -s  | grep estab | awk '{print $2}'</Custom>
        </Host>
      </Monitoring>
      
  • +2
    Где же вы были раньше и почему раньше ничего не писали по нагрузочному тестиронию, в начале года пришлось перекопать очень много документации по этой теме. С удовольствием почитаю, обязательно продолжайте писать.

    Яндекс танк пробовал в начале года, не понравилось, слишком все запутанно и не очевидно было на тот момент для меня по сравнению с JMeter. Сейчас появился какой-нибудь гуй или интерфейс?
    • 0
      Раньше мы все писали в клубике clubs.ya.ru/yandex-tank/, в software-testing — software-testing.ru/forum/index.php?/topic/24249/, рассказываем на каждом YAC и тд.

      Нет, Яндекс.Танк без GUI, он специально заточен под консоль. Я бы не сказал, что там все запутанно простейший конфиг состоит из 4 строчек. Задавайте вопросы, будем отвечать или писать статьи.
  • 0
    А с какими нагрузками обычно приходится сталкиваться в яндексе? и какой максимум может выдать ваш инструмент?
    • +1
      От единиц rps, до миллионов rps. При тестировании через свитч, с минимальным оверхэдом без keep-alive получаем 40000rps со средней машинки (8..16 ядер), с keep-alive — за 100к. Тюнинг физической машинки при предельных нагрузках обязателен.
  • 0
    Интересно… У меня следующие вопросы:
    0) Правильно ли я понял — нагрузку можно создавать из нескольких машин и получать результаты на одной?
    1) Какую максимальную нагрузку можно создать с одной машины, например — количество http реквестов в секунду в 1 поток, 100, 500 (можно любую из ваших в пример)?
    2) Какое максимальное количество потоков можно создать на одной машине для имитации конкурентных пользователей?
    3) Есть ли поддержка https?
    • +1
      0) Для агрегации данных с нескольких танков мы используем закрытый пока tank api. Дело в том, что для нагрузочного тестирования обычных сервисов — типа интернет магазинов, порталов, блогов — хватит одного сервера для достижения десятков тысяч хитов. Многохостовая конфигурация по сути не нужна. Но если вы предложите кейс, когда такой нагрузки не хватает, мы подумаем над выкладкой API в опенсорс.
      1) В 1 поток можно подать столько запросов сколько позволит время ответа. Например, если сервер отвечает за 1 секунду, то грубо говоря в один поток влезит 1 запрос в секунду. Если сервер отвечает за 1ms, то 1000 rps. Если мы увеличиваем число потоков, то соответственно танк получает большую свободу и может выдавать все более высокую нагрузку, используя свободные потоки.
      2) По дефолту на машинке можно уткнуться в число дискрипторов 1024, поэтому вам надо снять лимиты — yandextank.readthedocs.org/en/latest/install.html#tuning.
      После снятия лимитов, вы можете работать с десятками тысяч потоков.
      Заметьте, что вы можете упереться в число открытых иходящих портов, поэтому есть такой режим — yandextank.readthedocs.org/en/latest/tutorial.html#gatling, который позволяет навесить исходящие порты на виртуальные IP и вы можете увеличить число открытых портов. Но через некоторое время процессору танка будет тяжело обслуживать большое количество корутин и производительность его уткнется в некий предел.
      3) Есть поддержка https/ipv6, есть встроенные мониторинги, автостопы и куча всяких плюшек.

  • +3
    Спасибо, очень интересно. Я тоже занимался нагрузочным тестированием в университете, как раз защищаюсь на следующей неделе. Если вам интересно, посмотрите мой диплом, там я описываю метод автоматического определения регрессий в результатах нагрузочного тестирования. Ну и заодно там же обзор литературы по теме и описание репозитория для хранения и сравнения разных тестов. Может быть, какие-то мысли покажутся полезными.
    • +1
      Диплом по нагрузочному тестированию это очень круто! Обязательно посмотрим, и удачи в защите!
  • +2
    *Глядя на КДПВ* Кастет в виде танка?
    • 0
      Конкретное тестирование.
      • +3
        Чисто конкретно грузанул)
  • 0
    Как Яндекс.Танки понимают, что страницы готова для пользователя? Ведь на некоторых страницах, возможно, идет догрузка контента через AJAX, например? И не смотря на быстро время ответа сервера, страница будет догружаться еще длительное время. Или диагностика такого рода проблем не входит в задачи команды?

    В блоге O'Reilly наткнулся на следующий пост, где даётся совет использовать технику «ручного» логирования времени загрузки каждой важной страницы. Не используется ли в Яндексе подобное решение?
    • +1
      Яндекс.Танки не оперируют понятиями пользователя, они оперируют на уровне ниже, на уровне HTTP протокола. Когда пользователь открывает страницу, он делает ряд http-запросов в сторону сервиса, и не важно что клиент для этого использует ajax, actionscript,flash,java-апплет. Важно что он делает именно http-запрос.

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

      Человек, который управляет танком, сам выбирает какими запросами тестировать и в итоге можно смотреть на производительность отдельных процессов построения большой страницы целиком:)
      • 0
        Спасибо за ответ. Ситуация резко прояснилась :)
    • +3
      Задача Яндекс.Танка — создать нагрузку на сервер и померить именно время отклика самого сервера на каждый запрос. Танк ничего не знает о том, как страничка отображается в браузере. Если вы запишете трафик между браузером и сервером (tcpdump, логи сервера — смотря что вам нужно) — вы увидите все запросы: и ajax, и actionscript, и остальные — если только вы знаете, по какому порту и протоколу они идут. Если это HTTP — вам повезло и вы довольно просто сможете сервис обстрелять Танком или JMeter. Если нет — то придется подумать, как его распарсить, параметризовать и воспроизвести (хотя например HP LoadRunner умеет записывать и другие протоколы).

      С другой стороны, может быть у вас задача именно в том, чтобы померить, за сколько страничка полностью загрузится у пользователя в браузере. В этом случае используются другие инструменты, о том, как это делается в Яндексе — рассказывала Марина Широчкина.
      • +1
        Спасибо за объяснения и ссылку!
        Путаница в моей голове возникла еще при первой встрече с Яндекс.Танками, когда смотрел презентацию, и там было про использование Phantom. Перепутал с PhantomJS, который как раз используется для анализа времени загрузки фронтэнда.
  • +4
    Может кому пригодится, написал Gentoo ebuild'ы для phantom и yandex-tank.
    Установка и работа проверена с Python2.7.
    Качество написания ebuild'ов, возможно оставляет желать лучшего)))

    • 0
      Леша, промахнулся и минусанул. На самом деле ты очень крутой, спасибо тебе!
  • 0
    как нибудь можно подсунуть я.танку свой парсер который получает новые урлы из ответов сервера чтобы танк также эти урлы дергал?
    • 0
      Вы сейчас говорите о сценари или диалоге. Лучше для этого использовать Jmeter. И если это нужно автоматизировать, то можно использовать Яндекс.Танк для запуска этого jmeter тест-плана.
    • 0
      можно выдать танку сразу всё богатство урлов в нужной пропорции
      • 0
        Я сначала тоже подумал, но перечитал " новые урлы из ответов сервера ". Не зная ответов, урлы заранее не наклепаешь. Сценарий.
        • 0
          спасибо, да, урлы генерятся на сервере, заранее неизвестны.
          Насчет сценариев jmeter понятно, а с быстродействием у такой схемы как?
          планируется стресс 10К rps делать, один сервак jmeter/tank со средним железом столько выдаст?
          • 0
            Возможно, вам стоит обратить внимание на что-то типа wrk, он поддерживает луа скрипты которыми и можно парсить ответ от сервера и подставлять в следующий запрос
            • 0
              спасибо, возможно его и выберем раз фантом в танке не поддерживает диалоги
          • 0
            думаю, если максимально облегчить jmeter, выкинув тяжелые лиснеры, то можно попробовать разогнать.
            • 0
              ясно, спасибо, т.е. jmeter обычно дает около тысячи rps с одной тачки, а если в танке нужно больше то фантом?
              Но фантом не поддерживает такие диалоги?
              • 0
                Нет, фантом это не поддерживает.
              • 0
                т.е. jmeter обычно дает около тысячи rps с одной тачки

                В нашем сценарии целых 300 реквестов =). А нам надо лоад в 20к рек/сек. Заюзали Tsung, он умеет делать то, что вам нужно.

                Наш сценарий — Post request, парсим результат, в зависимости от результата дергаем нужную урлу новым Get request.
                • 0
                  Заюзали Tsung, он умеет делать то, что вам нужно.

                  Наш сценарий — Post request, парсим результат, в зависимости от результата дергаем нужную урлу новым Get request.


                  Так понял имеется ввиду это?
                  И вы используете значение которое распарсили из ответа в параметрах этого нового get запроса?

                  И 20К — это tsung с одной тачки стока посылает?
                  • 0
                    Так понял имеется ввиду это?

                    Почти — JSONPath.

                    И вы используете значение которое распарсили из ответа в параметрах этого нового get запроса?

                    Да.

                    И 20К — это tsung с одной тачки стока посылает?

                    С 2-х. При 10к рек/сек у нас полностью забивается сеть в 100 мб/c на одной машине, процессора еще остается около 20%. Но тсунг отлично скейлится. Вся статистика собирается на мастере.

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.

Самое читаемое Разработка