• Что бы вступить в ряды "Принятый кодер" Вам нужно:
    Написать 10 полезных сообщений или тем и Получить 10 симпатий.
    Для того кто не хочет терять время,может пожертвовать средства для поддержки сервеса, и вступить в ряды VIP на месяц, дополнительная информация в лс.

  • Пользаватели которые будут спамить, уходят в бан без предупреждения. Спам сообщения определяется администрацией и модератором.

  • Гость, Что бы Вы хотели увидеть на нашем Форуме? Изложить свои идеи и пожелания по улучшению форума Вы можете поделиться с нами здесь. ----> Перейдите сюда
  • Все пользователи не прошедшие проверку электронной почты будут заблокированы. Все вопросы с разблокировкой обращайтесь по адресу электронной почте : info@guardianelinks.com . Не пришло сообщение о проверке или о сбросе также сообщите нам.

Quarkus 3 application on AWS Lambda- Part 4 Reducing Lambda cold starts with SnapStart and API Gateway request event priming

Sascha Оффлайн

Sascha

Заместитель Администратора
Команда форума
Администратор
Регистрация
9 Май 2015
Сообщения
1,483
Баллы
155

Introduction


In the

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

of our series about how to develop, run and optimize Quarkus web application on AWS Lambda, we demonstrated how to write a

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

which uses the Quarkus framework, AWS Lambda, Amazon API Gateway and Amazon DynamoDB. We also made the first Lambda performance (cold and warm start time) measurements and observed quite a big cold start time.

In the

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

of the series, we introduced Lambda SnapStart and measured how its enabling reduces the Lambda cold start time by more than 50%.

In the

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

of the series, we introduced how to apply Lambda SnapStart priming techniques by starting with DynamoDB request priming with the goal to even further improve the performance of our Lambda functions. We saw that by doing this kind of priming by writing some additional code we could significantly further reduce the Lambda cold start times compared to simply activating the SnapStart.

We also clearly observed the impact of the AWS SnapStart Snapshot tiered cache in our measurements.

In this part of our article series, we'll introduce another Lambda SnapStart priming technique which is API Gateway request event priming. We'll then measure the Lambda performance by applying it and compare the results with other already introduced approaches.

Sample application with the activated AWS Lambda SnapStart with using API Gateway request event priming


We'll re-use the same

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

introduced in the

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

of our series.

Activating Lambda SnapStart is also a prerequisite for this method.


Globals:
Function:
Handler: io.quarkus.amazon.lambda.runtime.QuarkusStreamHandler::handleRequest
CodeUri: target/function.zip
Runtime: java21
SnapStart:
ApplyOn: PublishedVersions
....




This can be done in the globals section of the Lambda functions, in which case SnapStart applies to all Lambda functions defined in the AWS SAM template, or you can add the 2 lines


SnapStart:
ApplyOn: PublishedVersions




to activate SnapStart only for the individual Lambda function.

You can read more about the concepts behind the Lambda SnapStart in the

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

.


Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

offer you new possibilities to create your Lambda functions for low startup latency. With the pre-snapshot hook, we can prepare our Java application as much as possible for the first call. We load and initialize as much as possible which our Lambda function needs before the snapshot is created. This technique is known as priming.

Here I'll present you another experimental priming technique that preinitializes the entire web request (API gateway request event). This preinitializes more than DynamoDB request described in

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

, but also requires significantly more code to be written. The idea is nevertheless comparable. Activating Lambda SnapStart is also a prerequisite for this method. Let's take a look at the implementation in the

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

class:


@Startup
@ApplicationScoped
public class AmazonAPIGatewayPrimingResource implements Resource {

@PostConstruct
public void init () {
Core.getGlobalContext().register(this);
}

@Override
public void beforeCheckpoint(org.crac.Context<? extends Resource> context) throws Exception {
new QuarkusStreamHandler().handleRequest
(new ByteArrayInputStream(convertAwsProxRequestToJsonBytes()),
new ByteArrayOutputStream(), new MockLambdaContext());
}

@Override
public void afterRestore(org.crac.Context<? extends Resource> context) throws Exception {
}

private static byte[] convertAwsProxRequestToJsonBytes () throws JsonProcessingException {
ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
return ow.writeValueAsBytes(getAwsProxyRequest());
}

private static AwsProxyRequest getAwsProxyRequest () {
final APIGatewayProxyRequestEvent aPIGatewayProxyRequestEvent = new APIGatewayProxyRequestEvent ();
aPIGatewayProxyRequestEvent.setHttpMethod("GET");
aPIGatewayProxyRequestEvent.setPathParameters(Map.of("id","0"));
return aPIGatewayProxyRequestEvent;
}
}





We use

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

here. To do this, we need to declare the following dependency in

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

:


<dependency>
<groupId>io.github.crac</groupId>
<artifactId>org-crac</artifactId>
</dependency>




Please make sure that @ Startup annotation is present in the AmazonAPIGatewayPrimingResource class so that the priming takes effect. As we can see, in the method getAwsProxyRequest we create an object of type APIGatewayProxyRequestEvent and set some of its properties like HTTP Method to "GET" and path parameter ID to 0. This basically mocks

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

which is the input parameter of the handleRequest method. Only this properties of the APIGatewayProxyRequestEvent are required to be set to invoke GetProductByIdHandler Lambda function which then accesses the product id by invoking requestEvent.getPathParameters().get("id").
In the CRaC runtime hook beforeCheckpoint method, AwsProxyRequest is converted into a byte array and processed by calling QuarkusStreamHandler().handleRequest which in turn invokes GetProductByIdHandler Lambda function (which is mapped in the template.yaml to the /products/{id} path and HTTP GET method), whose handleRequest method is called directly. The priming is performed locally in AWS, so no network trip is required.

The purpose of this priming is to instantiate all required classes and to translate the AWS Lambda programming model (and invocation) into the Quarkus programming model. Through the preinitialized call of the handleRequest method of the GetProductByIdHandler, the DynamoDB request priming presented in the

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

is also carried out automatically by the DynamoDB call.

To ensure that only this priming takes effect, please either comment out or remove the @ Startup annotation in the following class

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

.

However, I consider this priming technique to be experimental, as it naturally leads to a lot of extra code, which can be significantly simplified using a few utility methods. Therefore, the decision to use this priming method is left to the reader.

Measurements of cold and warm start times of our application with Lambda SnapStart and API Gateway request event priming


In the following, we will measure the performance of our GetProductByIdFunction Lambda function, which we will trigger by invoking curl -H "X-API-Key: a6ZbcDefQW12BN56WEV318" https://{$API_GATEWAY_URL}/prod/products/1.

The results of the experiment are based on reproducing more than 100 cold starts and about 100,000 warm starts with the Lambda function GetProductByIdFunction (we ask for the already existing product with ID=1 ) for the duration of about 1 hour. We give Lambda function 1024 MB memory, which is a good trade-off between performance and cost. We also use (default) x86 Lambda architecture. For the load tests I used the load test tool

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

, but you can use whatever tool you want, like

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

or

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

.

We will measure with tiered compilation (which is default in Java 21, we don't need to set anything separately) and compilation option XX:+TieredCompilation -XX:TieredStopAtLevel=1. To use the last option, you have to set it in

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

in JAVA_OPTIONS environment variable as follows:


Globals:
Function:
Handler: io.quarkus.amazon.lambda.runtime.QuarkusStreamHandler::handleRequest
...
Environment:
Variables:
JAVA_TOOL_OPTIONS: "-XX:+TieredCompilation -XX:TieredStopAtLevel=1"




Please also note the effect of the

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

. This means that in the case of SnapStart activation, we get the largest cold starts during the first measurements. Due to the tiered cache, the subsequent cold starts will have lower values. For more details about the technical implementation of AWS SnapStart and its tiered cache, I refer you to the presentation by Mike Danilov:

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

. Therefore, I will present the Lambda performance measurements with SnapStart being activated for all approx. 100 cold start times (labelled as all in the table), but also for the last approx. 70 (labelled as last 70 in the table), so that the effect of Snapshot Tiered Cache becomes visible to you. Depending on how often the respective Lambda function is updated and thus some layers of the cache are invalidated, a Lambda function can experience thousands or tens of thousands of cold starts during its life cycle, so that the first longer lasting cold starts no longer carry much weight.

To show the impact of the SnapStart with API Gateway request event priming, we'll also present the Lambda performance measurements without SnapStart being activated from the

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

, with SnapStart being activated but without applying the priming techniques as measured in the

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

and with SnapStart being activated and DynamoDB request priming neing applied as measured in the

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

.

Cold (c) and warm (w) start time with tiered compilation in ms:

Scenario Numberc p50c p75c p90c p99c p99.9c maxw p50w p75w p90w p99w p99.9w max
No SnapStart enabled3344342234943633390439075.926.838.0019.4650.441233
SnapStart enabled but no priming applied, all1643170319532007208420845.686.357.3916.3949.231386
SnapStart enabled but no priming applied, last 701604166417281798179817985.646.307.3315.8747.301286
SnapStart enabled and DynamoDB request priming applied, all6667209441117131713185.736.457.5716.0139.07566
SnapStart enabled and DynamoDB request priming applied, last 706466817741043104310435.646.407.5115.7537.54566
SnapStart enabled and API Gateway request event priming applied, all6046756481181119711985.256.257.3315.6241.64338
SnapStart enabled and API Gateway request event priming applied, last 705885996507907907905.466.107.1614.9039.38241

Cold (c) and warm (w) start time with -XX:+TieredCompilation -XX:TieredStopAtLevel=1 compilation in ms:

Scenario Numberc p50c p75c p90c p99c p99.9c maxw p50w p75w p90w p99w p99.9w max
No SnapStart enabled3357345635544039406040606.016.838.1319.7753.741314
SnapStart enabled but no priming applied, all1593162517221834193019305.556.217.1616.0850.441401
SnapStart enabled but no priming applied, last 701574162116851801180118015.556.207.1615.1449.231401
SnapStart enabled and DynamoDB request priming applied, all636701943973105510555.506.207.2114.6639.07330
SnapStart enabled and DynamoDB request priming applied, last 706286546928598598595.506.157.0414.0837.25270
SnapStart enabled and API Gateway request event priming applied, all6166566179419609615.556.217.3916.0841.40486
SnapStart enabled and API Gateway request event priming applied, last 705956196537657657655.476.217.2716.0839.94486
Conclusion


In this part of the series, we introduced how to apply Lambda SnapStart priming techniques we called API Gateway event request priming with the goal to even further improve the performance of our Lambda functions compared to the DynamoDB request priming. We saw that by doing this kind of priming by writing a some amount of additional code we could further reduce the Lambda cold start times.

We also saw that -XX:+TieredCompilation -XX:TieredStopAtLevel=1 java compilation outperformed the tiered compilation for this type of priming for nearly all percentiles.

We also clearly observed the impact of the AWS SnapStart Snapshot tiered cache in our measurements.

However, as I've already pointed out, I consider this priming technique to be experimental, as it naturally leads to a lot of extra code, which can be significantly simplified using a few utility methods. Therefore, the decision to use this priming method is left to the reader. You can stick to the applying DynamoDB request priming having a bit higher Lambda cold start times.

In the next part of our article series, we'll introduce how to adjust our sample application to one from which we can build the GraalVM Native Image and deploy it as a Lambda Custom Runtime. We'll then measure the Lambda performance with it and compare the results with other already introduced approaches.



Источник:

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

 
Вверх Снизу