Как мы обслуживаем 25 миллионов вызовов API от 10 масштабируемых глобальных конечных точек за 150 долларов США в месяц

1656635891 kak my obsluzhivaem 25 millionov vyzovov api ot 10 masshtabiruemyh

Джонатан Косгей

jhBtc8nH4oQOixUtYJu8MKzazdaNcSlk-k4y

В Черную пятницу в прошлом году я проснулся от шквала электронных писем от пользователей, которые сообщали об ошибках 503 из API ipdata.

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

В тот день я потерял только одного пользователя, но подошел к тому, чтобы потерять гораздо больше.

Эта последовательность событий и их непонятная природа – ЦП, память и ввод-вывод были далеко не мощными. А также беспокойство по поводу того, насколько хорошо (если вообще) мы будем масштабироваться, учитывая наш сбой, стало серьезным тревожным звонком для переосмысления нашей существующей инфраструктуры.

Наша техника в то время

rqzWDcdQF8izmRhxYtIyeJF0PATKA2yddmv5
  • Платформа Japronto Python
  • Redis
  • Узлы AWS EC2
  • AWS Elastic Loadbalancers
  • Маршрутизация на основе задержки Route53

Я провел тесты на нескольких новых, многообещающих микрофреймворках Python.

Выбирая между aiohttp, sanic и japronto, я остановился на Japronto после сравнительного анализа 3 и обнаружил, что у него самая высокая пропускная способность.

API работал на 3 узлах EC2 в 3 регионах по балансировщикам нагрузки ELB с маршрутизацией на основе задержки Route53 для маршрутизации запросов в ближайший пользовательский регион для обеспечения низкой задержки.

Выбор нового стека технологий

diPMaejoDxpsKkQxbBsp8J5orTLZn6CIsawU
Пример API погоды с использованием нашего текущего стека

Приблизительно в это время я начал серьезно изучать использование API Gateway с AWS Lambda, учитывая их:

  1. Выгодная цена – около 3,50 долларов за миллион на API Gateway и 0,20 долларов за миллион для AWS Lambda.
  2. Бесконечный масштаб и высокая пропускная способность – ограничение аккаунта на API Gateway составляет 10 000 запросов в секунду или около 864 миллионов вызовов ежедневно. Снятый лимит, открыв запрос в службу поддержки.

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

Разработка мультирегионального API на основе шлюза API

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

  1. Каждая лямбда-функция в каждом регионе должна была иметь возможность искать данные об использовании в базе данных в том же регионе, чтобы минимизировать задержку
  2. Мне нужно было найти способ определить количество вызовов API, сделанных каждым IP-адресом, реферером и ключом API.
  3. Средство синхронизации данных об использовании во всех регионах. Например, если Route53 послал 10 000 запросов в нашу конечную точку в Сиднее, а затем решил отправить следующие 50 000 в нашу конечную точку в Сеуле (в зависимости от того, какая конечная точка имела наименьшую задержку сети в этот момент времени). Каждая лямбда-функция должна знать, что пользователь сделал в общей сложности 60 000 запросов, чтобы правильно обработать ограничение скорости.
  4. Авторизация – шлюз API дает планы использования и генерацию ключей API, а также позволяет связать ключ API с планом использования. С дополнительным преимуществом в том, что с вас не взимается плата за запросы, которые пользователи отправляют за пределы своих квот. Однако я не смог воспользоваться этим, потому что для меня было важно предоставить уровень без регистрации и без кредитной карты.

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

Локальный доступ к данным об использовании (для каждой лямбда-функции)

Очевидным решением для этого было использование DynamoDB, это было экономически выгодно в масштабе, быстро, и первые 200 миллионов запросов в месяц были бесплатными.

DynamoDB также обеспечивал неизменно низкие задержки чтения 1–2 мс.

dwE0L8p8fjQekAXNod7CLuJ9bnFSOhnNmy7I

И это можно ускорить в микросекундный диапазон с помощью DynamoDB Accelerator (DAX).

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

Сбор данных об использовании для всех идентификаторов

Следующей задачей было подсчитать в режиме реального времени количество запросов, сделанных на IP-адрес, реферер или ключ API.

Самым простым и прямым способом сделать это было бы обновить количество в таблице DynamoDB во время каждого вызова.

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

Мне удалось найти простое и элегантное решение:

  1. Сначала распечатайте журнал (объект JSON) со всеми запросами для каждого запроса. Это IP-адрес, реферер и ключ API, если он есть. Действительно просто;
print(event)
  1. Добавьте фильтр подписки Cloudwatch в поток журналов Cloudwatch каждой функции Lambda в каждом регионе и отправьте все журналы в поток Kinesis. Это позволит мне обрабатывать события журнала по каждому региону в центральном месте. Я выбрал Kinesis вместо SQS (Amazon’s Simple Queue Service) из-за возможности воспроизводить события. SQS удаляет событие, как только потребитель его прочтет. И я хотел возобновить после сбоя узла и потери данных.
  2. Читайте из потока Kinesis и обновляйте локальный экземпляр DynamoDB данными об использовании
  3. Используйте библиотеку межрегиональной репликации DynamoDB, чтобы передавать все изменения из моего локального экземпляра DynamoDB во все таблицы во всех регионах в реальном времени.

Аутентификация запросов

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

Как это получилось

Сегодня мы обслуживаем 25 миллионов вызовов API ежемесячно, примерно 1 миллион вызовов каждый день.

Большинство из них менее чем за 30 мс, что обеспечивает быстрый в области поиск геолокации IP через SSL.

Hyperping.io

D4hfVJDYxsX8O2rz5B-67wN3QE-w-ExvS2eh

Наша страница статуса

OqGMUdPHAQIKxH7SlYTFMu3g9yGCoTBrQ5yg

Задержка является основной причиной, почему разработчики стесняются использовать сторонние API для поиска GeoIP.

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

Расходы

yqRZHcP929fjBeROjup4i1SIQbStNx3GQBNd
Разбивка наших расходов

Уроки

  1. CloudWatch может быть удивительно дорогим, а не хранить журналы. Мы сохраняем журналы CloudWatch только в течение 24 часов. Сигналы тревоги, показатели и запросы CloudWatch действительно могут прилагаться.
  2. На шлюзе API чем больше запросов вы получаете, тем ниже будут ваши задержки из-за меньшего количества холодных запусков, поэтому я видел задержки от 17 мс в нашем наиболее загруженном регионе (Франкфурт) до 40 мс в наших менее загруженных регионах, таких как Сидней.
  3. DynamoDB быстро и будет стоить вам меньше, чем вы думаете (или, возможно, нет). Посмотрите на то, что я сначала думал, что с меня будут взиматься плата за количество единиц емкости чтения (RCU) и единиц емкости записи (WCU), которые я предоставляю. Однако, похоже, выставление счетов осуществляется только при использовании, поэтому если вы предоставляете 1000 RCU и 1000 WCU, но используете только 5 RCU и WCU, вы будете получать плату только за использование. Этот аспект ценообразования DynamoDB был несколько сложным для меня в начале.
  4. Увеличение оперативной памяти Lambda может вдвое сократить время выполнения и сделать время ответа более последовательным (а также удвоить ваши затраты!)
  5. Kinesis доказал свою надежность при высокой производительности. Передача всех событий журнала для обработки практически в реальном времени.
  6. Локальная DynamoDB ограничена только вашими системными ресурсами, что делает ее превосходной для сканирования таблиц или запросов (например, при создании отчетов), которые в противном случае были бы дороги для DynamoDB AWS. Имейте в виду, что Local DynamoDB является просто оберткой Dynamo вокруг SQLite. ? Это полезно и удобно для нашего случая использования, но может быть не так для вас.

Примечания

  • В прошлом году на Re:invent компания AWS анонсировала глобальные таблицы DynamoDB, синхронизирующие между собой все записи во всех таблицах в разных регионах. Сейчас мы не переходим к этому, поскольку он доступен только в 5 регионах.
  • Amazon также представил Custom Authorizers REQUEST введите в Amazon API Gateway. Это потенциально позволит вам ограничить скорость по IP-адресу, а также любому заголовку, запросу или параметру пути.

Читайте о других реальных архитектурах в блоге highscalability.com.

Обновление:

Просмотрите наш подробный анализ 8 лучших API геолокации IP.

Добавить комментарий

Ваш адрес email не будет опубликован.