Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!
Недавно я решил поэкспериментировать с API на нашем сайте CardGames.io и попробовать фреймворк Serverless. Последние несколько лет он стал горячей темой в мире технологий, а я прокрастинировал хотел поддерживать технические навыки в актуальном состоянии и попробовать что-то новое. Поэтому решил потратить несколько часов на изучение Serverless и посмотреть, есть ли смысл в таком размещении API.
CardGames.io работает на AWS. Все html-страницы, CSS, JavaScript и изображения хранятся на S3. У нас есть API на C#, размещённый на Elastic Beanstalk, он работает на серверах Linux под управлением .NET Core с Docker. Наконец, мы используем CloudFront CDN перед статикой на S3 и API. Ниже приведён счёт EC2 за август 2019 года. У нас есть несколько других инстансов, но API работают на m1.small (да, вероятно, t2.small лучше подходит) с классической балансировкой нагрузки. Если суммировать выделенное красным, то выходит $164,21 в месяц, неплохо. Я даже включил туда EBS, поскольку не уверен, как разбить эти расходы, у нас ведь несколько проектов на EC2.
Счет AWS для Elastic Beanstalk
У нас два окружения с 1-3 инстансами в каждом: активное и неактивное, потому что деплой .NET Core в Docker на AWS занимает несколько минут, так что мы делаем его в неактивной среде, а затем переключаем записи CNAME на недавно развёрнутый. Медленный деплой был одной из причин, по которым я хотел попробовать что-то новое. У нас несколько серверов с приложениями node.js на Beanstalk — и те развёртываются за считанные секунды. Хотелось, чтобы так было и для API.
Я изучил очень хороший учебник по размещению ASP.NET Web API с фреймворком Serverless и обнаружил, что в существующий проект API нужно только добавить простой файл конфигурации, одну зависимость и небольшой класс запуска. Деплой занял секунд двадцать — намного лучше, чем в Beanstalk. Думаю, благодаря встроенной в Lambda поддержке .NET Core (впрочем, только 2.2), тогда как в Beanstalk она поддерживается только если использовать Docker с самостоятельным управлением. В любом случае, я был счастлив, не думая о группах автомасштабирования, max instances и тому подобном.
Serverless на AWS — это Lambda, которая реально хостит ваши функции, и фронт API Gateway, который позволяет добавлять такие вещи, как ограничение скорости, ключи API и многое другое. Я разместил функции Lambda в регионе us-west-2, где и серверы Beanstalk. Затем настроил инстанс CloudFront на маршрутизацию запросов одной из наших игр в новую бессерверную конфигурацию, а другой — в старую конфигурацию Beanstalk. Затем запустил простой тест на двух URL: один Serverless, другой Beanstalk. Оба URL вызывали один и тот же API, сохраняя одно событие в БД. Я запустил 100 запросов для каждого, вот результаты:
Сравнение производительности
В многократных прогонах конфигурация Serverless была на 15% медленнее (если что, я запускал это из Исландии, отсюда большой пинг). Скорость стала разочарованием, но оставалась достаточно высокой — я понял, что есть некоторые накладные расходы на фронт API Gateway перед нашим API: там слишком много функций, даже если мы их не используем. Итак, печально, но не критично!
Честно говоря, я вообще сначала не думал о ценах. Просто решил, что платить за реальное использование будет наверняка дешевле, чем платить за инстансы 24/7. Поэтому позволил новой бессерверной установке работать несколько дней, а затем начал проверять счета. Упс! Счет за Lambda + API Gateway уже перевалил за сто долларов! Сначала я начал возиться с настройкой Lambda, выделяя ей меньше памяти для экономии, но когда хорошенько посмотрел на происходящее, то стало очевидно, что проблема в шлюзе. Вот тарифы на API Gateway:
Тарифы на API Gateway
Наш API принимает около 10 миллионов запросов в день. Это примерно $35 только на шлюз каждый день. Кроме того, Lambda стоит около $10 в день, хотя это можно уменьшить, выделив меньше памяти. Вместе получается около $45 в день, или $1350 в месяц, против $164 в месяц на Elastic Beanstalk. В восемь раз дороже! Мне нравятся новые технологии и быстрый деплой, но я не собираюсь платить за это дополнительные $1200 в месяц. Назад к Beanstalk!
Вероятно, мне следовало заранее ознакомиться с ценами и сделать некоторые математические расчёты! Но конечно, тогда пришлось бы заниматься реальной работой, а не осваивать ценные технические навыки! Уверен, что в каких-то ситуациях API Gateway и Lambda лучше, чем Elastic Beanstalk. Просто это не наш случай. Возможно, если вы используете ключи API, ограничение скорости и другие функции API Gateway, тогда имеет смысл платить $3,50 за миллион запросов. Нам было бы лучше просто поставить нормальный балансировщик нагрузки перед Lambda. Насколько я знаю, это невозможно, для доступа по http к Lambda необходим API Gateway.
Но даже если бы мы просто платили за Lambda, при $10 в день вышло бы $300 в месяц вместо $164. У нас много запросов, но каждый запрос делает очень мало: в основном, один вызов БД на запрос. Возможно, более тяжёлые запросы, которые используют больше вычислительного времени, лучше подходят для Lambda, где вы платите за 100 мс вычислительного времени. Ниже приведен отчёт для одного запроса. Как видите, мы используем 3,50 мс вычислительного времени, но выставляется счёт за 100 мс, это неслабое округление.
Отчёт Lambda для одного запроса
Наконец, я вообще тут не критикую API Gateway, Lambda или Serverless. Просто показываю, что для некоторых рабочих нагрузок они намного дороже, чем скучные старые EC2 и Elastic Beanstalk. На чём мы и останемся. Также вполне вероятно, что есть гораздо лучший или более эффективный способ настроить систему, я ни в коем случае не эксперт по AWS, так что если видите какие-то вопиющие ошибки, обязательно укажите в комментариях.
Текущая конфигурация
CardGames.io работает на AWS. Все html-страницы, CSS, JavaScript и изображения хранятся на S3. У нас есть API на C#, размещённый на Elastic Beanstalk, он работает на серверах Linux под управлением .NET Core с Docker. Наконец, мы используем CloudFront CDN перед статикой на S3 и API. Ниже приведён счёт EC2 за август 2019 года. У нас есть несколько других инстансов, но API работают на m1.small (да, вероятно, t2.small лучше подходит) с классической балансировкой нагрузки. Если суммировать выделенное красным, то выходит $164,21 в месяц, неплохо. Я даже включил туда EBS, поскольку не уверен, как разбить эти расходы, у нас ведь несколько проектов на EC2.
Счет AWS для Elastic Beanstalk
У нас два окружения с 1-3 инстансами в каждом: активное и неактивное, потому что деплой .NET Core в Docker на AWS занимает несколько минут, так что мы делаем его в неактивной среде, а затем переключаем записи CNAME на недавно развёрнутый. Медленный деплой был одной из причин, по которым я хотел попробовать что-то новое. У нас несколько серверов с приложениями node.js на Beanstalk — и те развёртываются за считанные секунды. Хотелось, чтобы так было и для API.
Переход на Serverless
Я изучил очень хороший учебник по размещению ASP.NET Web API с фреймворком Serverless и обнаружил, что в существующий проект API нужно только добавить простой файл конфигурации, одну зависимость и небольшой класс запуска. Деплой занял секунд двадцать — намного лучше, чем в Beanstalk. Думаю, благодаря встроенной в Lambda поддержке .NET Core (впрочем, только 2.2), тогда как в Beanstalk она поддерживается только если использовать Docker с самостоятельным управлением. В любом случае, я был счастлив, не думая о группах автомасштабирования, max instances и тому подобном.
Тестирование производительности
Serverless на AWS — это Lambda, которая реально хостит ваши функции, и фронт API Gateway, который позволяет добавлять такие вещи, как ограничение скорости, ключи API и многое другое. Я разместил функции Lambda в регионе us-west-2, где и серверы Beanstalk. Затем настроил инстанс CloudFront на маршрутизацию запросов одной из наших игр в новую бессерверную конфигурацию, а другой — в старую конфигурацию Beanstalk. Затем запустил простой тест на двух URL: один Serverless, другой Beanstalk. Оба URL вызывали один и тот же API, сохраняя одно событие в БД. Я запустил 100 запросов для каждого, вот результаты:
Сравнение производительности
В многократных прогонах конфигурация Serverless была на 15% медленнее (если что, я запускал это из Исландии, отсюда большой пинг). Скорость стала разочарованием, но оставалась достаточно высокой — я понял, что есть некоторые накладные расходы на фронт API Gateway перед нашим API: там слишком много функций, даже если мы их не используем. Итак, печально, но не критично!
Цены
Честно говоря, я вообще сначала не думал о ценах. Просто решил, что платить за реальное использование будет наверняка дешевле, чем платить за инстансы 24/7. Поэтому позволил новой бессерверной установке работать несколько дней, а затем начал проверять счета. Упс! Счет за Lambda + API Gateway уже перевалил за сто долларов! Сначала я начал возиться с настройкой Lambda, выделяя ей меньше памяти для экономии, но когда хорошенько посмотрел на происходящее, то стало очевидно, что проблема в шлюзе. Вот тарифы на API Gateway:
Тарифы на API Gateway
Наш API принимает около 10 миллионов запросов в день. Это примерно $35 только на шлюз каждый день. Кроме того, Lambda стоит около $10 в день, хотя это можно уменьшить, выделив меньше памяти. Вместе получается около $45 в день, или $1350 в месяц, против $164 в месяц на Elastic Beanstalk. В восемь раз дороже! Мне нравятся новые технологии и быстрый деплой, но я не собираюсь платить за это дополнительные $1200 в месяц. Назад к Beanstalk!
Вывод
Вероятно, мне следовало заранее ознакомиться с ценами и сделать некоторые математические расчёты! Но конечно, тогда пришлось бы заниматься реальной работой, а не осваивать ценные технические навыки! Уверен, что в каких-то ситуациях API Gateway и Lambda лучше, чем Elastic Beanstalk. Просто это не наш случай. Возможно, если вы используете ключи API, ограничение скорости и другие функции API Gateway, тогда имеет смысл платить $3,50 за миллион запросов. Нам было бы лучше просто поставить нормальный балансировщик нагрузки перед Lambda. Насколько я знаю, это невозможно, для доступа по http к Lambda необходим API Gateway.
Но даже если бы мы просто платили за Lambda, при $10 в день вышло бы $300 в месяц вместо $164. У нас много запросов, но каждый запрос делает очень мало: в основном, один вызов БД на запрос. Возможно, более тяжёлые запросы, которые используют больше вычислительного времени, лучше подходят для Lambda, где вы платите за 100 мс вычислительного времени. Ниже приведен отчёт для одного запроса. Как видите, мы используем 3,50 мс вычислительного времени, но выставляется счёт за 100 мс, это неслабое округление.
Отчёт Lambda для одного запроса
Наконец, я вообще тут не критикую API Gateway, Lambda или Serverless. Просто показываю, что для некоторых рабочих нагрузок они намного дороже, чем скучные старые EC2 и Elastic Beanstalk. На чём мы и останемся. Также вполне вероятно, что есть гораздо лучший или более эффективный способ настроить систему, я ни в коем случае не эксперт по AWS, так что если видите какие-то вопиющие ошибки, обязательно укажите в комментариях.