Introduction
In part 1 of the series, we set up our sample application, which has API Gateway in front of Lambda functions that communicate with Aurora Serverless v2 PostgreSQL database via Data API to create the products and retrieve them (by id). In part 2, we dove deeper into the new Data API for Aurora Serverless v2 itself and its capabilities, like executing SQL Statements and using AWS SDK for Java for it. In part 3, we explored Data API capabilities to batch SQL statements over an array of data for bulk update and insert operations. In part 4 of the series, we explored how to use database transactions with Data API, and in part 5, we made cold and warm start measurements of the Data API for the Aurora Serverless v2 without the usage of Lambda SnapStart.
In this article, we'll make a comparison of the cold and warm starts between 4 scenarios of connecting a Lambda function to the Amazon Aurora Serverless v2:
- Using Data API, see part 5.
- Using Amazon RDS Proxy for database connection management and JDBC. I also refer to my article for further details about RDS Proxy setup for our scenario.
- Using a new database connection per Lambda invocation and JDBC.
- Re-using one database connection per Lambda life cycle and JDBC.
Measuring cold and warm measurements using the standard connection management solutions with JDBC
In our experiment, we'll re-use the application introduced in part 1. You can find the source code here. For the execution of those experiments, we need to deploy the following SAM template template-with-and-without-data-api-and-rds-proxy.yaml by executing sam deploy -t template-with-and-without-data-api-and-rds-proxy.yaml.
This template introduces 2 additional Lambda functions:
- GetProductByIdViaAuroraServerlessV2WithoutDataApi for retrieving a product by id using JDBC and without using Amazon RDS Proxy. Here you can find the implementation of the GetProductByIdViaAuroraServerlessV2WithoutDataApiHandler. This handler, by default, was used for 2 upcoming measurements:
Creating a PostgreSQL database connection once for the lifetime of the Lambda function and then always reusing it.
Always creating the new database connection for each Lambda execution can be achieved by a small source code modification of the createConnection function:
private Connection createConnection (String url, String userName, String userPassword) throws SQLException {
return DriverManager.getConnection(url, userName, userPassword);
}
Both approaches are only explored for demonstration purposes, and they don't introduce the proper connection management/pool technique
- GetProductByIdViaAuroraServerlessV2WithRDSProxy for retrieving a product by id using JDBC and using Amazon RDS Proxy. Here you can find the implementation of the GetProductByIdViaAuroraServerlessV2RDSProxyHandler. This approach introduces the proper scalable connection management/pool technique. In the template-with-and-without-data-api-and-rds-proxy.yaml, we can explore how to set up Amazon RDS Proxy with Infrastructure as a Code. I also refer to my article How to set up Amazon RDS Proxy for Amazon Aurora (Serverless) database cluster and connect AWS Lambda function to it for further details.
The word of caution: Only for demonstration purposes, we passed the database name and password as the Lambda environment variables to connect to RDS Proxy, which introduces a security risk. The proper solution is to store the database password in Amazon Secret Manager and then retrieve it in the Lambda function.
The results of the experiments to retrieve the existing product from the database with all approaches by its id with Lambda functions with 1024 MB memory setting were based on reproducing more than 100 cold and approximately 10.000 warm starts with the experiment, which ran for approximately 1 hour. For it (and experiments from my previous article), I used the load test tool hey, but you can use whatever tool you want, like Serverless-artillery or Postman. We won't enable SnapStart on the Lambda functions first.
Cold (c) and warm (m) start time in ms:
| Approach | c p50 | c p75 | c p90 | c p99 | c p99.9 | c max | w p50 | w p75 | w p90 | w p99 | w p99.9 | w max |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| New database connecton per Lambda invocation | 2455.53 | 2727.23 | 2942.48 | 3354.11 | 3684.52 | 3685.73 | 1084.10 | 1383.52 | 1693.04 | 2291.89 | 2782.31 | 3069.79 |
| One database connection reused per Lambda life cycle | 1983.14 | 2061.53 | 2137.93 | 2243.39 | 2445.59 | 2587.12 | 3.42 | 18.72 | 49.69 | 77.23 | 175.17 | 1619.61 |
| Amazon RDS Proxy | 1972.80 | 2063.56 | 2221.97 | 2426.25 | 2520.18 | 2522.17 | 143.79 | 179.57 | 197.52 | 361.05 | 1348.17 | 1752.54 |
| Data API, see part 5 | 3154.35 | 3237 | 3284.91 | 3581.49 | 3702.12 | 3764.92 | 104.68 | 173.96 | 271.32 | 572.11 | 1482.89 | 2179.7 |
Conclusion
In this part of the series, we compared warm and cold start measurements of the Data API for Amazon Aurora Serverless v2 with AWS SDK for Java with the same measurements using the standard connection management with JDBC. The most important comparison is with using Amazon RDS Proxy by providing a scalable database connection management solution for PostgreSQL database, and we saw that Data API introduces higher cold start times but quite competitive warm start times compared to using RDS Proxy. In the next part of the series, we'll explore how to optimize warm and cold start times of the Data API for Amazon Aurora Serverless v2 using Lambda SnapStart and priming techniques.
Please also check out my website for more technical content and upcoming public speaking activities.
Top comments (0)