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

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

В этой части мы рассмотрим:

  • проблема и как произошло снижение производительности
  • факторы планирования, которые учитывались для этого примера
  • контрольный список для фазы 1 и показать результаты
  • контрольный список для фазы 2 и показать результаты

Итак, без лишних слов, давайте перейдем к делу.

Проблема

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

В этой статье мы рассмотрим возможность построения графиков валютных пар. Поскольку мы создаем торговое приложение, одной из основных функций является предоставление пользователям возможности отслеживать поведение валютных пар (например, EURUSD) с течением времени. Библиотека графиков на стороне интерфейса может показать, как валютные пары вели себя в течение наблюдаемых периодов времени, с возможностью выбора между несколькими наблюдаемыми периодами (периоды 1,5,15 минут и т. Д.). Эти периоды в функциональности нашего графика называются тиками, и у них есть значения цены открытия, закрытия, максимума и минимума. Библиотека опрашивает данные с нашего сервера каждые 0,5 секунды, и вы можете вернуться во времени, так как также включена отложенная загрузка.

Итак, как он был построен в первую очередь?

Мы построили прокси-сервер, который использовал стороннюю библиотеку для связи с сервером торговых данных (который не контролировался нами). Итак, когда пользователи запрашивали данные графиков, мы просто ретранслировали эти вызовы на сервер торговых данных и отправили ответ. Это сработало бы хорошо, если бы сервер торговых данных не использовался также для других целей. Основная причина, по которой у нас было снижение производительности, даже не была одной из причин, упомянутых ранее. Мы не были знакомы с тем, как сервер торговых данных работал за сценой. Он был построен таким образом, чтобы при высокой нагрузке снижать приоритет запросов данных диаграммы. Если вы примете этот факт во внимание, учесть механизм опроса библиотеки графических интерфейсов и умножить его на десятки тысяч пользователей, использующих эту функцию, когда торговый рынок горячий, вы получите катастрофический эффект от опросов, продолжающихся 5-10, иногда даже по 15 секунд каждый. Мягко говоря, это был медленный, вялый и очень разочаровывающий опыт для пользователей.

План и факторы планирования

Давайте сначала рассмотрим факторы планирования. К тому времени, когда мне было поручено это дело, пользователи привыкли к плохому поведению графиков и уже не жаловались так сильно, как раньше. Кроме того, поскольку я был единственным, кто участвовал в этих усилиях, я мог предположить, что это был не раскаленный докрасна приоритет «Земля будет выжжена, если вы не исправите это». Это не значит, что у меня было все время на свете. Я подумал, что у меня, может быть, будет два месяца, чтобы сделать это и показать некоторые результаты, прежде чем на меня начнут давить. У меня не было ограниченного бюджета, но я тоже не мог броситься в глаза. Скажем так, у меня была возможность выбирать технологии и другие ресурсы, если это выглядело достаточно разумно.

Имея это в виду, первоначальный план был следующим:

  • По-прежнему использовать прокси-сервер, но как вторичный источник данных. Сохраняйте данные в моих собственных хранилищах данных, оптимизированных для чтения (хранилища чтения). Поскольку только мои службы используют прокси-сервер, у него не должно быть таких же проблем с производительностью, поскольку количество экземпляров, использующих прокси-сервер, будет ограничено.
  • Выберите Go для создания сервисов для обслуживания и обработки данных диаграмм, Cassandra для построения моделей чтения и хранения в них данных диаграмм, Redis для кэширования.
  • Используйте все другие службы и компоненты, которые уже существуют в системе.
  • Выполняйте развертывание как можно быстрее с устойчивыми результатами производительности, а затем вносите дальнейшие улучшения в последующих итерациях.

Этап 1 - ознакомьтесь с контрольным списком и результатами

Чтобы дать вам представление о том путешествии, в которое я попал, мы рассмотрим контрольный список.

Время планировать

Около четверти всей работы по повышению производительности ушло на этапы планирования и разработки решения. Почти половина этой суммы ушла на планирование. Это включало в себя текущие исследования решения, исследование потенциального использования технологий и оценку текущего набора навыков. Последний вариант занимал больше всего времени на исследование, потому что было важно, чтобы, если я собирался использовать технологию, фреймворк и / или библиотеку, с которой у меня раньше не было опыта, я бы оценил кривую обучения, чтобы предотвратить возможное неправильное использование тем же. Я уже упоминал, что рассматривал Го и Кассандру. Хотя я уверен, что могу построить практически все что угодно с помощью Go, в случае с Кассандрой это было не так. Оценив существующие учебные ресурсы, я решил, что смогу быстро освоить необходимые навыки для проектирования и создания правильного решения.

Пора разработать правильное решение

Итак, я выбрал Го и Кассандру. И я не торопился с проектированием архитектуры. Я потратил большую часть времени на разработку моделей чтения. У меня не было проблем с записью в магазины чтения. Что касается чтения из хранилищ чтения, я хотел сделать это как можно быстрее, минимизируя количество обращений к хранилищам чтения. Кроме того, я хотел использовать тот факт, что время для получения всего раздела в Cassandra почти постоянно из-за согласованного хеширования ключей разделов. Имея это в виду и правильно управляя хранилищами для чтения, я мог бы иметь прочную основу для любых будущих улучшений.

Получение измеримых и сопоставимых данных

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

Создайте решение, которое легко масштабируется

Здесь в игру вступает почти постоянное время чтения разделов хранилища. Решение заключалось в том, чтобы выделить каждую галочку в отдельную таблицу с разделами, настроенными для этого конкретного тика. Получение данных осуществлялось путем извлечения данных из одного раздела, из двух в худшем случае (что происходило, может быть, в 20% случаев). Это заложило бы прочную основу для любых будущих улучшений.

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

Я должен сказать, что при разработке решения, подобного описанному выше, я мог бы приложить гораздо больше усилий к планированию доставки. Я этого не сделал. Помимо разработки моделей чтения, большая часть усилий была потрачена на написание кода для сервисов. Решение не могло бы работать, если бы все службы не работали должным образом, поэтому я легко отказался от предоставления небольших фрагментов и пошел одним большим толчком. Оглядываясь назад, я мог бы потратить больше времени на прерывание доставки решения. Я мог бы осуществить несколько родов с интервалом в 1–3 дня. Это не выглядит так много, но я бы начал доставлять и развертывать в производственной среде по крайней мере за неделю до того, как вся функциональность была выдвинута.

Общайтесь, общайтесь, общайтесь

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

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

Этап 2 - доверяйте процессу и повторяйте шаги

Успех фазы 1 был больше, чем я планировал. Высшее руководство было доволен, а пользователи не жаловались. Сообщается, что время загрузки «чувствовалось» лучше в часы пик. Я ненавижу слово «чувствовать» в этом контексте, но это все, что у меня было без каких-либо измеримых данных, взятых в начале фазы 1.

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

Время планировать

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

Пора разработать правильное решение

В конце этапа 1 я более подробно рассмотрел, как работает библиотека графиков на стороне клиента. Для каждого тика при загрузке графиков есть два этапа. Первый загружал больший объем данных для перемещения вперед и назад по временной шкале. Второй этап - это опрос набора текущих значений, гораздо меньшего фрагмента данных (последние десять полос тиков). Это вряд ли было оптимальным решением, поскольку мы извлекаем весь раздел за эти десять тиков и текущую временную метку. Как видно из гистограммы таблицы выше (полученной в конце фазы 1), это примерно 24–35 КБ данных, извлеченных из базы данных только для того, чтобы взять 10 тиковых полос. Новое решение включало наличие двух таблиц для каждого временного интервала; один для получения массовых данных, которые будут использоваться для начальной загрузки, а другой для опроса, который будет иметь гораздо меньший раздел.

Получение измеримых и сопоставимых данных

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

Создайте решение, которое легко масштабируется

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

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

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

Общайтесь, общайтесь, общайтесь

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

Заключение

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

По сути, это сводится к следующему:

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

Я хотел бы услышать, что вы думаете по этому поводу. У вас есть свои правила или вы их просто придерживаетесь? Кроме того, я хотел бы услышать ваши рассказы о ваших усилиях по повышению производительности, особенно страшилки. Может быть, когда-нибудь появится телешоу о самых чудовищных попытках улучшить производительность с Лиамом Нисоном, Морганом Фриманом или Джеймсом Эрлом Джонсом в роли рассказчиков;).