Настраиваем AWS SDK для Java (версии 2.х) для ускорения запуска функций AWS Lambda

Оригинал статьи: ссылка (Zoe Wang, Software Dev Engineer)

Одним из самых популярных пожеланий пользователей AWS SDK for Java было уменьшение задержки при старте SDK, поэтому при разработке AWS SDK для Java версии 2.x мы уделили особое внимание длительности холодного старта SDK в функциях AWS Lambda. В этом посте мы поделимся лучшими практиками опытом по оптимизации Lambda функций с использованием AWS SDK for Java 2.x, чтобы вы могли достичь минимального времени запуска SDK.

Используйте встроенный HTTP-клиент HttpUrlConnection, чтобы сократить время инстанцирования Java классов

AWS SDK для Java версии 2.x содержит подключаемый HTTP-слой, который позволяет использовать различные реализации HTTP-стека. Три HTTP-клиента поддерживаются «из коробки»: HTTP-клиент Apache, HTTP-клиент Netty и HTTP-клиент Java URL Connection. В конфигурации по умолчанию клиент Apache используется для синхронных вызовов, а Netty — для асинхронных. Они оба — универсальные HTTP-клиенты с большим количеством функций. Тем не менее, из-за своего размера они отличаются более высокого времени инстанцирования. В то же время встроенная в JDK библиотека HTTPUrlConnection более легкая и запускается быстрее. Кроме того, поскольку HTTPUrlConnection является частью JDK, ее использование не требует подключения внешних зависимостей. Это позволит вам сохранить размер ZIP-пакета развертывания (deployment package) небольшим и, таким образом, сократить время, необходимое для его скачивания и распаковки. Поэтому мы рекомендуем использовать HttpUrlConnectionClient при настройке SDK- клиента. Обратите внимание, что он поддерживает только синхронные API- вызовы. Если вы хотите, чтобы SDK поддерживал асинхронные вызовы со встроенным в JDK 11 HTTP-клиентом, проголосуйте за этот GitHub issue.

Используйте EnvironmentVariableCredentialProvider для поиска учетных записей

По умолчанию SDK автоматически определяет, какой провайдер учетных записей использовать, просматривая различные системные переменные, файлы учетных записей и т.д. Если использовать EnvironmentVariableCredentialProvider, он будет загружать учетные данные из переменных окружения Lambda, и вы сможете не терять дополнительное время на поиск в других местах.

Задавайте регион AWS в переменной окружения AWS_REGION

Как и с провайдером учетных записей, SDK также автоматически определяет, какой AWS регион использовать, просматривая различные источники. Если мы читаем регион из переменной окружения AWS_REGION в Lambda, и передаем ее непосредственно в билдер, не тратится дополнительное время на инициализацию цепочки провайдеров региона и поиск региона.

Вот пример рекомендуемой конфигурации SDK-клиента:

S3Client.builder()
.credentialsProvider(EnvironmentVariableCredentialsProvider.create())
.region(Region.of(System.getenv(SdkSystemSetting.AWS_REGION.environmentVariable())))
.httpClientBuilder(UrlConnectionHttpClient.builder())
.build();

Исключите неиспользуемые зависимости HTTP в SDK

SDK по умолчанию включает в себя библиотеки с HTTP-клиентами Apache и Netty. Если время запуска важно для вашего приложения, и вам не нужны эти обе имплементации, мы рекомендуем исключить неиспользуемые HTTP-зависимости из SDK. Это позволит минимизировать размер установочного пакета. Ниже приведен пример Maven POM файла для приложения, которое использует только url-connection-client и исключает netty-nio-client и apache-client

<dependencyManagement>
<dependencies>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>bom</artifactId>
<version>${aws.java.sdk.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<dependencies>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>s3</artifactId>
<exclusions>
<exclusion>
<groupId>software.amazon.awssdk</groupId>
<artifactId>netty-nio-client</artifactId>
</exclusion>
<exclusion>
<groupId>software.amazon.awssdk</groupId>
<artifactId>apache-client</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>url-connection-client</artifactId>
</dependency>
</dependencies>

Инициализируйте SDK-клиент вне обработчика Lambda-функции

После завершения выполнения Lambda-функции, сервис AWS Lambda может повторно использовать ее предыдущий контейнер для последующих вызовов. В этом случае объекты, объявленные вне метода обработчика функции, остаются инициализированными. Чтобы воспользоваться преимуществом повторного использования runtime-контекста Lambda, мы рекомендуем инициализировать SDK-клиент вне метода обработчика, чтобы последующие исполнения, запущенные в том же самом контейнере, могли повторно использовать сам SDK-клиент и его соединения. Ниже приведен пример кода обработчика Lambda-функции с таким подходом:

public class App implements RequestHandler<Object, Object> {
private final S3Client s3Client;

public App() {
s3Client = DependencyFactory.s3Client();
}

@Override
public Object handleRequest(final Object input, final Context context) {
s3Client.listBuckets();
// Function logic here
}
}

Заключение

В этом посте мы показали вам наши рекомендации по настройке AWS SDK для Java версии 2.x, которые помогают сократить время запуска. У нас также есть архетип Maven, который позволяет быстро создавать Lambda-функции на Java, с учетом наших лучших практик. Вы можете взглянуть на этот пост, чтобы узнать о нем больше. В наших публикациях в блоге мы расскажем сообществу разработчиков AWS о передовых подходах, связанных с улучшением производительности, и о том, как их применять в своем коде. Для получения обновлений AWS SDK для Java ознакомьтесь с репозиторием aws-java-sdk-v2 на GitHub и дайте нам знать, если у вас есть какие-либо отзывы, комментарии или проблемы, через нашу страницу GitHub issues.