Как бороться с задержкой хвоста

Завершено

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

Что такое задержка хвоста?

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

Latency due to scale-out.

Рис. 7. Задержка из-за горизонтального масштабирования

Рассмотрим пример поиска фильма на Netflix. Когда пользователь начинает вводить текст в поле поиска, он вызывает несколько параллельных событий с корневого веб-сервера. Эти события включают, как минимум, следующие запросы.

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

Такие примеры являются чрезвычайно распространенными. Известно, что один запрос Facebook обращается к тысячам серверов memcached, а один поиск Bing часто обращается более чем к десяти тысячам индексных серверов.

Очевидно, что потребность в масштабировании привела к большой развернутой системе в тыловой части для каждого отдельного запроса, обслуживаемого внешним интерфейсом. Для служб, которые должны быть "отзывчивыми" для удержания своей базы пользователей, эвристика показывает, что ответ предполагается получить в течение 100 мс. По мере увеличения количества серверов, необходимых для ответа на запрос, общее время часто зависит от наихудшего отклика конечного узла на корневой узел. Учитывая, что все конечные узлы должны завершить выполнение до возврата результата, общая задержка всегда должна быть больше задержки самого медленного компонента.

Как и большинство стохастических процессов, время отклика одного конечного узла можно выразить как распределение. Многолетний опыт показывает, что в общем случае большинство (>99 %) запросов правильно настроенной облачной системы будут выполняться очень быстро. Но часто в системе очень мало выбросов, которые выполняются очень медленно.

Tail latency example.

Рис. 8. Пример задержкихвоста 5

Рассмотрим систему, в которой все конечные узлы имеют среднее время отклика 1 мс, но существует вероятность 1 %, что время отклика будет больше 1000 мс (одна секунда). Если каждый запрос обрабатывается только одним конечным узлом, вероятность того, что запрос занимает больше одной секунды, также будет иметь значение 1 %. Однако, по мере увеличения числа узлов до 100, вероятность того, что запрос выполнится в пределах одной секунды падает до 36,6 %. То есть вероятность того, что время выполнения запроса будет определяться хвостом (наименьшим значением в 1 %) распределения задержки, будет равна 63,4 %.

$(.99^{100})$

Если мы смоделируем это для различных случаев, мы увидим, что при увеличении числа серверов влияние одного медленного запроса становится более выраженным (обратите внимание, что график ниже является монотонно возрастающим). Кроме того, при снижении вероятности этих выбросов с 1 % до 0,01 % график оказывается значительно ниже.

Recent study of response time probability that shows the fiftieth, ninety-fifth, and ninety-ninth percentiles for latency of requests.

Рис. 9. Недавнее исследование вероятности времени отклика, показывающее 50-е, 95-е и 99-е процентили для задержки запросов4

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

Вариативность в облаке: источники и способы устранения рисков

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

  • Использование общих ресурсов: многие разные виртуальные машины (и приложения в этих виртуальных машинах) утверждают, что общий пул вычислительных ресурсов. В редких случаях такое состязание может привести к низкой задержке для некоторых запросов. Для критически важных задач может быть целесообразно использовать выделенные экземпляры и периодически запускать тесты производительности при простое, чтобы убедиться, что они работают правильно.
  • Фоновые программы и обслуживание: мы уже говорили о необходимости фоновых процессов для создания проверка точек, создания резервных копий, журналов обновления, сбора мусора и обработки очистки ресурсов. Однако это может привести к снижению производительности системы во время выполнения. Чтобы избежать этого, важно синхронизировать нарушения работы, вызванные потоками обслуживания, чтобы минимизировать влияние на поток трафика. Это приведет к тому, что все вариации будут происходить в коротком, хорошо известном окне, а не в случайном порядке в течение всего жизненного цикла приложения.
  • Очередь: другой распространенный источник изменчивости — это всплеск шаблонов прибытия трафика.1 Это изменение усугубляется, если ОС использует алгоритм планирования, отличный от FIFO. Системы Linux часто планируют потоки неупорядоченно, чтобы оптимизировать общую пропускную способность и максимизировать использование сервера. Обнаружено, что использование планирования FIFO в операционной системе сокращает задержку хвоста за счет снижения общей пропускной способности системы.
  • Все к всем данным: шаблон, показанный на рисунке 8 выше, называется связью "все ко всем". Так как большая часть сетевого взаимодействия осуществляется по протоколу TCP, это приводит к тысячам одновременных запросов и ответов между веб-сервером переднего плана и всеми узлами серверной обработки. Это чрезвычайно взрывной шаблон взаимодействия, который часто приводит к специальному виду перегрузки, известной как коллапс TCP incast1, 2. Внезапный интенсивный ответ от тысяч серверов приводит к множеству отброшенных и повторно передаваемых пакетов, что в конечном итоге вызывает сетевую лавину трафика из очень маленьких пакетов данных. Для больших центров обработки данных и облачных приложений часто требуется использовать модифицированные сетевые драйверы для динамической настройки окна приема TCP и таймера повторной передачи. Маршрутизаторы также могут быть настроены на отбрасывания трафика, который превышает определенную скорость, и уменьшает размер отправки.
  • Управление питанием и температурой. Наконец, вариативность является побочным продуктом других методов сокращения затрат, таких как использование состояний простоя или уменьшения частоты ЦП. Процессор часто может тратить нетривиальное количество времени на масштабирование из состояния простоя. Отключение такой оптимизации затрат приводит к более высокому энергопотреблению и затратам, но снижает вариативность. Это в меньшей степени является проблемой в общедоступном облаке, так как модели ценообразования редко учитывают внутренние показатели использования ресурсов клиента.

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

Жизнь с изменчивостью: инженерные решения

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

  • "Достаточно хорошие" результаты: часто, когда система ожидает получения результатов от тысяч узлов, важность любого одного результата может быть довольно низкой. Следовательно, многие приложения могут просто отвечать пользователям, если результаты получены в определенном окне с небольшой задержкой, и отбрасывать остальные.
  • Канарии: еще одна альтернатива, которая часто используется для редких путей кода, заключается в тестировании запроса на небольшом подмножестве конечных узлов, чтобы проверить, вызывает ли он сбой или сбой, который может повлиять на всю систему. Полный размноженный запрос генерируется только в том случае, если канарейка не приводит к сбою. Это похоже на запуск канарейки (птицы) в угольную шахту, чтобы проверить, безопасна ли она для людей.
  • Задержка и работоспособность, вызванные задержкой, и проверка работоспособности: конечно, большая часть запросов к системе слишком распространена для тестирования с помощью канарной. Такие запросы, скорее всего, будут иметь длинный хвост в случаях, когда один из конечных узлов работает плохо. Для этого система должна периодически отслеживать работоспособность и задержку каждого конечного узла и не маршрутизировать запросы к узлам, которые демонстрируют низкую производительность (из-за обслуживания или сбоев).
  • Разностный QoS: отдельные классы служб можно создать для интерактивных запросов, что позволяет им принимать приоритет в любой очереди. Нечувствительные к задержкам приложения могут допускать более длительное время ожидания для своих операций.
  • Настройка запросов. Это простое решение, чтобы уменьшить влияние изменчивости, переадресовав один и тот же запрос нескольким реплика и используя ответ, поступающий первым. Разумеется, для этого может потребоваться удвоение или утроение количества ресурсов. Чтобы уменьшить количество хеджированных запросов, второй запрос можно отправлять только в том случае, если ожидание первого ответа превысило 95-й процентиль ожидаемой задержки для этого запроса. Это приводит всего к около 5 % дополнительной нагрузки, но значительно сокращает задержки хвоста (в типичном примере, показанном на рис. 9, где задержка 95-го процентиля гораздо ниже, чем задержка 99-го процентиля).
  • Спекулятивное выполнение и выборочное реплика tion: задачи на узлах, которые особенно заняты, могут быть спекулятивно запущены на других недоиспользуемых конечных узлах. Это особенно эффективно, если сбой в определенном узле вызывает перегрузку.
  • Решения на основе пользовательского интерфейса. Наконец, задержка может быть интеллектуально скрыта от пользователя через хорошо разработанный пользовательский интерфейс, который снижает ощущение задержки, возникающей у человека. К таким методам могут относиться использование анимации, отображение предварительных результатов или вовлечение пользователя путем отправки сопутствующих сообщений.

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


Ссылки

  1. Li, J., Sharma, N. K., Порты, D. R., & Gribble, S. D. (2014). Tales of the Tail: Hardware, OS, and Application-Level Sources of Tail Latency from the Proceedings of the ACM Symposium on Cloud Computing, ACM
  2. Wu, Haitao and Feng, Zhenqian and Guo, Chuanxiong and Zhang, Yongguang (2013). ICTCP: Incast Congestion Control for TCP in Data-Center Networks, IEEE/ACM Transactions on Networking (TON), IEEE Press
  3. Xu, Yunjing and Musgrave, Zachary and Noble, Brian and Bailey, Michael (2013). Bobtail: Avoiding Long Tails in the Cloud, 10th USENIX Conference on Networked Systems Design and Implementation, USENIX Association
  4. Dean, Jeffrey and Barroso, Luiz André (2013). The tail at scale, Communications of the ACM, ACM
  5. Tene, Gil (2014). [Understanding Latency - Some Key Lessons and Tools](https://www.infoq.com/presentations/latency-lessons-tools/, QCon London

Проверьте свои знания

1.

Что из следующего не является рекомендуемым способом решения проблемы вариативности, которая приводит к длинному хвосту?