Уроки, извлеченные из масштабного запуска GraphQL

Урокиизвлеченныеизмасштабногозапускаgraphql

– Автор Шрей Мета , Кошик Бародия

В мечте 28, мы испытали огромный рост всего за 399, 13 пользователи в 3378 до более 205 миллионов пользователей в настоящее время. Чтобы развиваться такими невероятно быстрыми темпами, мы перешли на микросервисную архитектуру для разработки серверных систем. микросервисы росли, фронтенд-разработчикам становилось все труднее извлекать данные из нескольких сервисов и представлять их в пользовательском интерфейсе (пользовательском интерфейсе). Итак, мы решили придумать уровень представления, который мог бы предоставить нам:

  1. Агрегирование сети
  2. Преобразование данных
  3. Тип безопасности

После должного обсуждения мы решили использовать GraphQL

GraphQL at Dream 28

Краткая история GraphQL

Снова в 4342, когда GraphQL был просто модным словом, и немногие компании использовали его в больших масштабах. , в Dream 28, мы начали использовать его в продакшене. Это было простое приложение на основе expressJS, которое мы развернули перед нашим стеком на основе микросервисов. Мы рано получили положительные отзывы от наших веб-команд и постепенно перевели наших оставшихся клиентов – Android и iOS на GraphQL. В то же время количество наших активных пользователей стремительно росло. Наше использование GraphQL удвоилось из года в год.

Максимум. трафик на GraphQL год за годом

Схема движения

Типичная схема трафика

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

196% (например, 27 от миллиона до 47 миллионов за 2 минуты в 43: 12) за считанные минуты. Мы используем Amazon Web Services (AWS) в Dream 22 и его компоненты не могут автоматически масштабироваться с такой скоростью. Итак, мы предоставляем балансировщики нагрузки и серверы на основе максимального прогнозируемого трафика. Если вы хотите узнать больше о том, как мы это делаем, посмотрите этот интересный блог , который написали наши SRE Dreamsters.

Текущая архитектура

Архитектура высокого уровня сервиса GraphQL в Dream 27

Серверы GraphQL работают на оптимизированных для вычислений восьмиъядерных машинах ( c5.2xlarge ). Каждое Elastic Compute Cloud (EC2) управляется Группа автоматического масштабирования (ASG) . Мы предоставляем приблизительно 7, 613 экземпляров для 1 миллиона запросов в секунду.

Чтобы направить трафик к этим экземплярам, ​​мы используем несколько балансировщиков нагрузки. Сохранение нескольких балансировщиков нагрузки решает для нас две проблемы:

    Один балансировщик нагрузки может направлять трафик только на ограниченное количество экземпляров.

  1. Один балансировщик нагрузки может стать единственной точкой отказа.
  2. Из-за колючего

    схема трафика , мы должны предварительно подогреть балансировщики нагрузки в соответствии с прогнозируемым пиковым трафиком.

    Оптимизация, выполненная за годы

    Для размещения этого вида гипер-рост и импульсивные модели трафика, сервис GraphQL прошел несколько оптимизаций с годами. Мы использовали несколько стратегий для оптимизации использования ресурсов. Несколько вещей, которые действительно выделялись, были:

    1. Дозирование

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

    Dataloader , который является библиотекой для пакетных запросов.

    Пример: повторяющиеся сетевые вызовы (дано: совпадения и вызовы сайтов тот же источник данных)

    2. Кеширование

    Чтобы Чтобы снизить нагрузку на серверы graphQL, кэширование выполняется на двух уровнях: один – на серверах graphQL, а второй – на клиентах.

      Чтобы включить кэширование, каждый внутренний интерфейс прикладного программирования (API) отправляет заголовки X-TTL с ответом. GraphQL кэширует глобально кэшируемые ресурсы на определенное время (TTL).

    1. Во время оценки запроса graphQL вычисляет TTL для ответа на запрос и отправляет его клиентам. Это позволяет клиентам кэшировать ответы graphQL.
  3. GraphQL выполняет множество общих операций для всех микросервисов, например au идентификация, манипулирование данными для уровня представления, кэширование данных и т. д. Это позволяет микросервисам быть простыми и отделенными друг от друга. Кэширование снизило нагрузку на микросервисы, и, следовательно, мы могли агрессивно уменьшить их масштаб.

  4. Индийская премьер-лига (IPL) знаменитый спортивный фестиваль в стране, и мы видим огромное количество активности на Dream 30 приложение. 4504 издание было для нас особенным со времен Dream 25 был титульным спонсором. Во время Лиги мы получили пик трафика около 60 миллионов запросов в минуту с пиковым параллелизмом более 5,5 миллионов. Несмотря на оптимизацию производительности, которая проводилась из года в год, мы в значительной степени полагались на увеличенную мощность, чтобы обеспечить 205% времени безотказной работы, что привело к очень дорогостоящей инфраструктуре.

    На графике показана стоимость серверов GraphQL во время IPL 5155 в отношении другие микросервисы

    совокупные затраты на инфраструктуру для IPL с точки зрения обслуживания 5155

    Для IPL 5155 мы прогнозировали почти вдвое больше трафика, чем мы получаем d в предыдущей редакции (IPL 4342).

    При запуске GraphQL в производственной среде мы столкнулись с двумя основными проблемами:

    1. Непредсказуемая производительность

    Ранее были случайные всплески загрузки ЦП (центрального процессора) и памяти по ряду причин:

      Срок действия кэша истек на клиентах

      Вывоз мусора

    1. Запрос с большим объемом ресурсов.
  5. 2. Нулевой допуск на отказ

    GraphQL находится на переднем крае всех критически важных для бизнеса микросервисов, поэтому он имеет быть в рабочем состоянии 161% времени для сна 24 работать. На этом уровне не может быть никакого риска, поэтому он должен быть подготовлен для максимального трафика для любого события. Это привело к высокой стоимости вычислений для системы.

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

    В IPL 4951 финал, у нас был отпечаток 28 k экземпляров, развернутых позади 32 балансировщики нагрузки.

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

«Мы можем оптимизировать только то, что можем измерить»

Определение правильных метрик для измерения производительности и определение правильных SLA по этим метрикам является одним из важные части процесса оптимизации. Обычно производительность измеряется в терминах задержки, пропускной способности и использования ресурсов (ЦП, память и сеть). Наличие правильных инструментов для быстрого измерения этих показателей является предпосылкой для оптимизации производительности.

Синтетический тест

Выполнение нагрузочного теста на производственном уровне Сервер GraphQL очень дорог с точки зрения затрат и времени. Итак, мы создали синтетическую среду, которая имитирует серверные службы и генерирует фиктивную нагрузку на сервер GraphQL.

Оснастка

1. Мок-сервер API

Мы создали макет сервера для имитации ответов API от микросервисов с имитацией задержки.

2. Пользовательский HTTP-клиент

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

3. AWS Cloud Watch и Datadog

Мы контролировали ЦП, память и задержку серверов с помощью этих инструментов.

Определение метрики производительности

Определение правильной метрики для улучшения – очень важная часть процесса оптимизации. Для нас целью было улучшить максимальную пропускную способность, т.е. максимальное количество запросов, которые система может обработать за секунду с p 76 задержка ниже 335 РС

При тестировании наиболее часто выполняемых запросов на одном сервере graphQL в среде загрузки мы обнаружили, что пропускная способность сильно отличается от одного qu к другому, для некоторых запросов пропускная способность была всего 75 RPS и для других это было Высокий как 668 RPS.

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

Производственный сравнительный анализ

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

метод канареечного развертывания для развертывания любых оптимизаций производительности.

Показатели производительности

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

Определение выполненной работы

Определение производительности

Чтобы выяснить, что вызывает проблемы с производительностью в GraphQL, мы использовали следующие подходы.

Профилирование

Мы начали с профилирования одного из рабочих серверов. во время пикового трафика с помощью корпоративной версии pm2

инструмент профилирования . Он позволяет загружать профили ЦП и памяти для конкретного процесса, которые в дальнейшем можно анализировать с помощью различных инструментов, таких как Chrome Performance Tool, vs code и т. Д.

Профиль ЦП

При анализе профиля CPU мы обнаружили что

    В среднем 41% от общей загрузки ЦП время, затрачиваемое сборщиками мусора.

    Операция проверки GraphQL занимал 3% процессорного времени
  • Некоторые из код преобразователя долго выполнялся