Моей мотивацией для проведения бенчмарков всех вариантов компилятора, развертывания и времени выполнения было удовлетворение моего любопытства. Я видел различные записи в блогах, в которых рекомендовались одни настройки над другими, но они никогда не давали обоснования.
К сожалению, мы не можем использовать выдающийся инструмент BenchmarkDotNet с AWS Lambda. Поэтому я создал бенчмарк, чтобы собрать данные для всех вариантов развертывания и, надеюсь, определить «оптимальную» комбинацию.
Как упоминалось в первой статье этой серии, есть два разных случая, для которых мы можем оптимизировать: «Минимизация продолжительности холодного запуска» или «Минимизация эксплуатационных расходов». Теперь, когда основа заложена, мы можем формально описать, что это значит.
Оптимальные стратегии
-
Чтобы минимизировать продолжительность холодного запуска, нам нужно минимизировать фазу INIT и первую фазу INVOKE. Оптимальная конфигурация обеспечивает наименьшую продолжительность обработки запроса, измеряемую в миллисекундах (мс). Для этого измерения мы полагаемся на данные, сообщаемые AWS Lambda в журналах. Это те же данные, которые используются для выставления счетов, и они являются наиболее точными из всех, к которым мы имеем доступ.
-
Чтобы минимизировать стоимость выполнения, нам нужно минимизировать сумму всех фаз INVOKE (холодной и теплой), принимая во внимание конфигурацию памяти Lambda и архитектуру процессора. Оптимальная конфигурация дает наименьшую стоимость выполнения для 1 холодного запуска с последующими 100 теплыми вызовами. Выполнение AWS Lambe имеет чрезвычайно низкую удельную стоимость. Чтобы сделать число более интуитивно понятным, я решил представить стоимость выполнения в миллионных долях доллара, или микродолларах (µ$).
Варианты бенчмарков
Чтобы не оставить ни одного камня без внимания, система бенчмаркинга выполняет все возможные варианты следующих опций.
- Многоуровневая компиляция: Вкл. и Выкл.
- ReadyToRun: Вкл. и Выкл.
- Память лямбды: 128 МБ, 256 МБ, 512 МБ, 1024 МБ, 1769 МБ и 5120 МБ.
- Архитектура процессора: x86-64 и ARM64
- Время выполнения .NET: .NET Core 3.1 и .NET 6
- Pre-JIT .NET: Вкл. и Выкл.
Эти опции создают 192 уникальные комбинации, которые подвергаются бенчмаркингу.
Подход к бенчмаркингу
Лямбда-функция для каждого проекта измеряется при выполнении 100 холодных запусков. За каждым холодным запуском следует 100 теплых вызовов. Затем результаты усредняются.
Я обсуждал возможность использования медианы или перцентиля вместо среднего значения. Сложность заключается в том, чтобы объединить эти значения. Например, суммирование значения p99 для фазы INIT с p99 для первой фазы INVOKE кажется неправильным. Кроме того, в реальной жизни случаются выбросы. Я надеюсь, что 100 холодных и теплых вызовов достаточно, чтобы справедливо представить то, что следует ожидать в реальных ситуациях.
Тем не менее, необработанные измерения были записаны для каждого бенчмарка. Таким образом, можно проводить альтернативные анализы без необходимости повторного сбора данных.
Эталонные проекты
Мой интерес заключался в изучении того, как опции влияют на вычислительный аспект функций Lambda. Поэтому я выбрал только те проекты, которые не выполняют операций ввода-вывода.
Минимальная базовая линия
Проект Minimal устанавливает базовый уровень для всех проектов. Он не содержит бизнес-логики и включает только необходимые библиотеки.
Сериализаторы JSON
Сериализация JSON необходима практически для всех функций Lambda. В .NET 6 существует 3 распространенных подхода к решению этой задачи.
-
NewtonsoftJson: использование Newtonsoft JSON.NET
-
SourceGeneratorJson: использование генераторов исходников .NET 6 для разбора JSON
-
SystemTextJson: использование System.Text.Json
AWS SDK
Большинство функций Lambda будут взаимодействовать с другими сервисами AWS через AWS SDK. Проект AwsSdk используется для оценки затрат на инициализацию SDK.
Утверждения верхнего уровня
Начиная с .NET 6, функции Lambda могут использовать утверждения верхнего уровня вместо объявления класса. Как это влияет на производительность?
-
AwsNewtonsoftJson: использование AWS .NET SDK и Newtonsoft JSON.NET
-
SampleAwsNewtonsoftTopLevel: использование AWS .NET SDK, Newtonsoft JSON.NET и утверждений верхнего уровня
-
SampleAwsSystemTextJsonTopLevel: использование AWS .NET SDK, System.Text.Json и утверждений верхнего уровня.
Минимальный API
Также новым в .NET 6 является новый подход к выражению маршрутов ASP.NET с помощью утверждений верхнего уровня. Этот пример взят из сообщения в блоге об анонсе поддержки .NET 6 в AWS Lambda.
- SampleMinimalApi: использование ASP.NET Core Minimal API
Исследователь бенчмарков
Результаты бенчмарков были собраны в интерактивную таблицу Google. Не стесняйтесь исследовать данные как угодно и делать собственные выводы. Любые замечания по улучшению анализа или визуализации приветствуются.
Что дальше
Наконец, мы можем погрузиться в результаты и посмотреть, какие новые выводы мы можем сделать! Первое — это измерение базовой производительности. Хотя это не критично для производственного кода, это дает нам основу для работы.