×
THANKS FOR SIGNING UP!
We’ll make sure to share the best materials crafted for you!
4 minutes read
Migrating Spring Boot Applications to AWS Lambda with No Code Change
Written by Oguzhan Gencel
Software Developer @Thundra
Migrating Spring Boot Applications to AWS Lambda with No Code Change
According to a survey conducted by Jetbrains, Spring Boot is the top Java framework for developing web applications. Spring Boot applications are usually deployed on a dedicated server and/or container via necessary orchestration. Normally, this inevitably includes the work of managing the infrastructure and scalability of the application. Deploying Spring Boot applications on AWS Lambda can be an alternative with comparatively less time spent on operational aspects of maintaining a Spring Boot application. Thanks to the pay-per-use nature and highly lessened operational burden of AWS Lambda, application teams can have many advantages when they migrate their existing Spring Boot applications to AWS Lambda. However, developers have hesitations about switching to AWS Lambda because of cold starts and other limitations of AWS Lambda. In this blog post, we will eliminate some common myths and prove that migrating your Spring Boot application to AWS Lambda will not degrade (and will instead boost) the performance of your applications.
(So-Called) Problems Associated with Lambda
The first issue is the need to make Spring Boot applications event-driven. When an AWS Lambda function is invoked, it sends a request object to the handler. However, Spring Boot cannot handle this request, so we need to change our app. To solve this problem, AWS has published a library that enables developers to create a custom handler (follow this tutorial). Thundra’s agent has an in-built HTTP API handler for your Spring Boot 2 application. So, if you add Thundra to your application, you don’t need to change your code at all. That means you can use your current Spring Boot application as-is without any modifications on AWS Lambda.
The second issue is cold starts. It’s a general problem of serverless, but its impact intensifies with Spring Boot applications due to a long initialization time: AWS Lambda has a 10-second initialization duration limit for cold start, but some complex Spring Boot applications take more than 10 seconds during the start-up process. Fortunately, with Thundra’s custom Java runtime, enabling the thundra_agent_lambda_jvm_optimizeForFastStartup
environment variable helps to decrease your Spring Boot AWS Lambda app initialization duration by 50%. You can set the thundra_agent_lambda_jvm_optimizeForFastStartup
environment variable as true
to achieve a fast start-up and less of a cold start overhead. Of note, your application can still have problems getting initialized in 10 seconds while loading dependencies. But good news: Thundra has another layer of built-in solutions for this issue. If you set the thundra_agent_lambda_container_springboot_app_initasync
environment variable as true
, Thundra initializes the application asynchronously without blocking Lambda initialization, but assures that initialization is completed before handling the request.
The most frequently asked question we receive is about the monitoring overhead for applications like Thundra APM. With its collectors on every AWS region, Thundra’s agent adds (at most) 5 ms latency when it reports monitoring data in synchronous mode. However, there’s still an overhead associated with loading security-related JDK classes, due to security components being initialized because of initial HTTPS handshake at cold start invocations. As a result, there will be 1-2 seconds of cold start overhead. If you are curious about this topic, you may find our blog post on this subject interesting. To get rid of this initialization overhead and network delay at each invocation, we also support asynchronous monitoring for ZER0 overhead. To enable asynchronous monitoring, you can set the thundra_agent_lambda_report_cloudwatch_enable
environment variable as true
. In this mode, reporting data will be done separately from function execution and saves you some more time.
Benchmark with a PetClinic Application
In this blog post, we are using the infamous Spring Boot Pet Clinic application with the Spring Boot 2.1.11 version. This application has four endpoints; three use DynamoDB with Spring Data. The other serves to make an HTTP request to an external web service with Apache HttpClient. When the application starts, the Spring Data DynamoDB sync application models with a remote database. The sample application looks like a microservice app that contains real-world cases. Of course, our application is monitored by Thundra APM.
For this benchmark, we have three main scenarios, depending on the deployment method and Thundra configuration. Each deployment method has four memory configurations. In total, we have 12 different test cases. For each test case, we run the same invocation seven times and take into consideration the best six results for comparison.
In the scope of our tests, we have used two different modes of deployment.
Zipped Spring Boot Fat Jar
- Create a fat (bootable) jar by following this tutorial using Spring Boot Maven or Gradle plugin.
- Upload the generated jar to AWS Lambda in the zip archive.
- Add the Thundra layer by following this doc.
- Set Spring Boot fat jar name in the
thundra_agent_lambda_container_springboot_app_artifact
environment variable.
Docker Image
Follow this tutorial to create and publish a docker image based on the Lambda function.
Benchmarks
The graph shows three test cases:
- The first case used AWS Serverless Java Container – Spring Boot 2 library to expose Spring Web Rest endpoints as the Lambda handler (
API Gateway request -> Lambda handler -> AWS Serverless Java Container - Spring Boot 2-> Spring Web Rest Controller
) and didn’t include any Thundra components. It was deployed with AWS SAM CLI tools without the Spring Boot build plugin.
- For the second test case, the application was bundled (zipped) as a fat (bootable) jar with the Spring Boot Gradle plugin and uploaded to AWS Lambda as a zip archive. Then, the Thundra Java layer was added and added the following configurations:
- In the third test case, the application was packaged as a Docker Image and published to Lambda AWS ECR to be used by AWS Lambda. Next, the following configurations are applied:
- Add Thundra’s API key.
- Set the
thundra_agent_lambda_container_springboot_app_artifact
environment variable with the application jar name (e.g., petlinic.jar
).
- Set the
thundra_agent_lambda_jvm_optimizeForFastStartup
environment variable to true
so the Lambda runtime JVM process will be started with configured VM arguments optimized for fast start-up (see docs).
- Set the
thundra_agent_lambda_report_cloudwatch_enable environment
variable totrue
so collected telemetry data will be reported asynchronously over AWS CloudWatch logs without any network overhead (see docs).
- Set runtime to
Custom Runtime.
- Set handler to
io.thundra.agent.container.springboot2.ContainerHandler .
- Set the
thundra_agent_lambda_container_springboot_app_artifact
environment variable with the application jar name (e.g., petlinic.jar
).
- Set the
thundra_agent_lambda_jvm_optimizeForFastStartup
environment variable to true
so Lambda runtime JVM process will be started with configured VM arguments optimized for fast start-up.
- Set the
thundra_agent_lambda_report_cloudwatch_enable
environment variable to true so collected telemetry data will be reported asynchronously over AWS CloudWatch logs without any network overhead.
As seen from the benchmark results, Thundra boosts application initialization duration up to 30% and produces highly informative distributed traces automatically.
Also, according to our findings, AWS Lambda Docker images have some overhead (1-2 seconds lost) before our runtime starts. If you want to use your Docker image in Lambda but don’t want to accept the cold start, you can read another Thundra solution for dealing with cold start.
Wrapping Up
Millions of developers all around the world pick Spring Boot as an easy way of developing web applications with Java runtime. However, they also have to deal with the operational aspect of those applications because of the infrastructure the applications run on. AWS Lambda removes the operational burden of application teams due to lessened operational tasks. Moreover, there are cost advantages due to the pay-per-use nature of AWS Lambda and from the total cost of ownership perspective. Thundra makes it possible to migrate existing VM or containerized applications to AWS Lambda platforms without need for any modification. So, with the help of Thundra, lift-and-shift to serverless is very straightforward: Just upload and add Thundra. That’s all!
Get started with Thundra APM today and don’t forget to have a look at Thundra Sidekick!
Migrating Spring Boot Applications to AWS Lambda with No Code Change
According to a survey conducted by Jetbrains, Spring Boot is the top Java framework for developing web applications. Spring Boot applications are usually deployed on a dedicated server and/or container via necessary orchestration. Normally, this inevitably includes the work of managing the infrastructure and scalability of the application. Deploying Spring Boot applications on AWS Lambda can be an alternative with comparatively less time spent on operational aspects of maintaining a Spring Boot application. Thanks to the pay-per-use nature and highly lessened operational burden of AWS Lambda, application teams can have many advantages when they migrate their existing Spring Boot applications to AWS Lambda. However, developers have hesitations about switching to AWS Lambda because of cold starts and other limitations of AWS Lambda. In this blog post, we will eliminate some common myths and prove that migrating your Spring Boot application to AWS Lambda will not degrade (and will instead boost) the performance of your applications.
(So-Called) Problems Associated with Lambda
The first issue is the need to make Spring Boot applications event-driven. When an AWS Lambda function is invoked, it sends a request object to the handler. However, Spring Boot cannot handle this request, so we need to change our app. To solve this problem, AWS has published a library that enables developers to create a custom handler (follow this tutorial). Thundra’s agent has an in-built HTTP API handler for your Spring Boot 2 application. So, if you add Thundra to your application, you don’t need to change your code at all. That means you can use your current Spring Boot application as-is without any modifications on AWS Lambda.
The second issue is cold starts. It’s a general problem of serverless, but its impact intensifies with Spring Boot applications due to a long initialization time: AWS Lambda has a 10-second initialization duration limit for cold start, but some complex Spring Boot applications take more than 10 seconds during the start-up process. Fortunately, with Thundra’s custom Java runtime, enabling the thundra_agent_lambda_jvm_optimizeForFastStartup
environment variable helps to decrease your Spring Boot AWS Lambda app initialization duration by 50%. You can set the thundra_agent_lambda_jvm_optimizeForFastStartup
environment variable as true
to achieve a fast start-up and less of a cold start overhead. Of note, your application can still have problems getting initialized in 10 seconds while loading dependencies. But good news: Thundra has another layer of built-in solutions for this issue. If you set the thundra_agent_lambda_container_springboot_app_initasync
environment variable as true
, Thundra initializes the application asynchronously without blocking Lambda initialization, but assures that initialization is completed before handling the request.
The most frequently asked question we receive is about the monitoring overhead for applications like Thundra APM. With its collectors on every AWS region, Thundra’s agent adds (at most) 5 ms latency when it reports monitoring data in synchronous mode. However, there’s still an overhead associated with loading security-related JDK classes, due to security components being initialized because of initial HTTPS handshake at cold start invocations. As a result, there will be 1-2 seconds of cold start overhead. If you are curious about this topic, you may find our blog post on this subject interesting. To get rid of this initialization overhead and network delay at each invocation, we also support asynchronous monitoring for ZER0 overhead. To enable asynchronous monitoring, you can set the thundra_agent_lambda_report_cloudwatch_enable
environment variable as true
. In this mode, reporting data will be done separately from function execution and saves you some more time.
Benchmark with a PetClinic Application
In this blog post, we are using the infamous Spring Boot Pet Clinic application with the Spring Boot 2.1.11 version. This application has four endpoints; three use DynamoDB with Spring Data. The other serves to make an HTTP request to an external web service with Apache HttpClient. When the application starts, the Spring Data DynamoDB sync application models with a remote database. The sample application looks like a microservice app that contains real-world cases. Of course, our application is monitored by Thundra APM.
For this benchmark, we have three main scenarios, depending on the deployment method and Thundra configuration. Each deployment method has four memory configurations. In total, we have 12 different test cases. For each test case, we run the same invocation seven times and take into consideration the best six results for comparison.
In the scope of our tests, we have used two different modes of deployment.
Zipped Spring Boot Fat Jar
- Create a fat (bootable) jar by following this tutorial using Spring Boot Maven or Gradle plugin.
- Upload the generated jar to AWS Lambda in the zip archive.
- Add the Thundra layer by following this doc.
- Set Spring Boot fat jar name in the
thundra_agent_lambda_container_springboot_app_artifact
environment variable.
Docker Image
Follow this tutorial to create and publish a docker image based on the Lambda function.
Benchmarks
The graph shows three test cases:
- The first case used AWS Serverless Java Container – Spring Boot 2 library to expose Spring Web Rest endpoints as the Lambda handler (
API Gateway request -> Lambda handler -> AWS Serverless Java Container - Spring Boot 2-> Spring Web Rest Controller
) and didn’t include any Thundra components. It was deployed with AWS SAM CLI tools without the Spring Boot build plugin.
- For the second test case, the application was bundled (zipped) as a fat (bootable) jar with the Spring Boot Gradle plugin and uploaded to AWS Lambda as a zip archive. Then, the Thundra Java layer was added and added the following configurations:
- In the third test case, the application was packaged as a Docker Image and published to Lambda AWS ECR to be used by AWS Lambda. Next, the following configurations are applied:
- Add Thundra’s API key.
- Set the
thundra_agent_lambda_container_springboot_app_artifact
environment variable with the application jar name (e.g., petlinic.jar
).
- Set the
thundra_agent_lambda_jvm_optimizeForFastStartup
environment variable to true
so the Lambda runtime JVM process will be started with configured VM arguments optimized for fast start-up (see docs).
- Set the
thundra_agent_lambda_report_cloudwatch_enable environment
variable totrue
so collected telemetry data will be reported asynchronously over AWS CloudWatch logs without any network overhead (see docs).
- Set runtime to
Custom Runtime.
- Set handler to
io.thundra.agent.container.springboot2.ContainerHandler .
- Set the
thundra_agent_lambda_container_springboot_app_artifact
environment variable with the application jar name (e.g., petlinic.jar
).
- Set the
thundra_agent_lambda_jvm_optimizeForFastStartup
environment variable to true
so Lambda runtime JVM process will be started with configured VM arguments optimized for fast start-up.
- Set the
thundra_agent_lambda_report_cloudwatch_enable
environment variable to true so collected telemetry data will be reported asynchronously over AWS CloudWatch logs without any network overhead.
As seen from the benchmark results, Thundra boosts application initialization duration up to 30% and produces highly informative distributed traces automatically.
Also, according to our findings, AWS Lambda Docker images have some overhead (1-2 seconds lost) before our runtime starts. If you want to use your Docker image in Lambda but don’t want to accept the cold start, you can read another Thundra solution for dealing with cold start.
Wrapping Up
Millions of developers all around the world pick Spring Boot as an easy way of developing web applications with Java runtime. However, they also have to deal with the operational aspect of those applications because of the infrastructure the applications run on. AWS Lambda removes the operational burden of application teams due to lessened operational tasks. Moreover, there are cost advantages due to the pay-per-use nature of AWS Lambda and from the total cost of ownership perspective. Thundra makes it possible to migrate existing VM or containerized applications to AWS Lambda platforms without need for any modification. So, with the help of Thundra, lift-and-shift to serverless is very straightforward: Just upload and add Thundra. That’s all!
Get started with Thundra APM today and don’t forget to have a look at Thundra Sidekick!
Migrating Spring Boot Applications to AWS Lambda with No Code Change
According to a survey conducted by Jetbrains, Spring Boot is the top Java framework for developing web applications. Spring Boot applications are usually deployed on a dedicated server and/or container via necessary orchestration. Normally, this inevitably includes the work of managing the infrastructure and scalability of the application. Deploying Spring Boot applications on AWS Lambda can be an alternative with comparatively less time spent on operational aspects of maintaining a Spring Boot application. Thanks to the pay-per-use nature and highly lessened operational burden of AWS Lambda, application teams can have many advantages when they migrate their existing Spring Boot applications to AWS Lambda. However, developers have hesitations about switching to AWS Lambda because of cold starts and other limitations of AWS Lambda. In this blog post, we will eliminate some common myths and prove that migrating your Spring Boot application to AWS Lambda will not degrade (and will instead boost) the performance of your applications.
(So-Called) Problems Associated with Lambda
The first issue is the need to make Spring Boot applications event-driven. When an AWS Lambda function is invoked, it sends a request object to the handler. However, Spring Boot cannot handle this request, so we need to change our app. To solve this problem, AWS has published a library that enables developers to create a custom handler (follow this tutorial). Thundra’s agent has an in-built HTTP API handler for your Spring Boot 2 application. So, if you add Thundra to your application, you don’t need to change your code at all. That means you can use your current Spring Boot application as-is without any modifications on AWS Lambda.
The second issue is cold starts. It’s a general problem of serverless, but its impact intensifies with Spring Boot applications due to a long initialization time: AWS Lambda has a 10-second initialization duration limit for cold start, but some complex Spring Boot applications take more than 10 seconds during the start-up process. Fortunately, with Thundra’s custom Java runtime, enabling the thundra_agent_lambda_jvm_optimizeForFastStartup
environment variable helps to decrease your Spring Boot AWS Lambda app initialization duration by 50%. You can set the thundra_agent_lambda_jvm_optimizeForFastStartup
environment variable as true
to achieve a fast start-up and less of a cold start overhead. Of note, your application can still have problems getting initialized in 10 seconds while loading dependencies. But good news: Thundra has another layer of built-in solutions for this issue. If you set the thundra_agent_lambda_container_springboot_app_initasync
environment variable as true
, Thundra initializes the application asynchronously without blocking Lambda initialization, but assures that initialization is completed before handling the request.
The most frequently asked question we receive is about the monitoring overhead for applications like Thundra APM. With its collectors on every AWS region, Thundra’s agent adds (at most) 5 ms latency when it reports monitoring data in synchronous mode. However, there’s still an overhead associated with loading security-related JDK classes, due to security components being initialized because of initial HTTPS handshake at cold start invocations. As a result, there will be 1-2 seconds of cold start overhead. If you are curious about this topic, you may find our blog post on this subject interesting. To get rid of this initialization overhead and network delay at each invocation, we also support asynchronous monitoring for ZER0 overhead. To enable asynchronous monitoring, you can set the thundra_agent_lambda_report_cloudwatch_enable
environment variable as true
. In this mode, reporting data will be done separately from function execution and saves you some more time.
Benchmark with a PetClinic Application
In this blog post, we are using the infamous Spring Boot Pet Clinic application with the Spring Boot 2.1.11 version. This application has four endpoints; three use DynamoDB with Spring Data. The other serves to make an HTTP request to an external web service with Apache HttpClient. When the application starts, the Spring Data DynamoDB sync application models with a remote database. The sample application looks like a microservice app that contains real-world cases. Of course, our application is monitored by Thundra APM.
For this benchmark, we have three main scenarios, depending on the deployment method and Thundra configuration. Each deployment method has four memory configurations. In total, we have 12 different test cases. For each test case, we run the same invocation seven times and take into consideration the best six results for comparison.
In the scope of our tests, we have used two different modes of deployment.
Zipped Spring Boot Fat Jar
- Create a fat (bootable) jar by following this tutorial using Spring Boot Maven or Gradle plugin.
- Upload the generated jar to AWS Lambda in the zip archive.
- Add the Thundra layer by following this doc.
- Set Spring Boot fat jar name in the
thundra_agent_lambda_container_springboot_app_artifact
environment variable.
Docker Image
Follow this tutorial to create and publish a docker image based on the Lambda function.
Benchmarks
The graph shows three test cases:
- The first case used AWS Serverless Java Container – Spring Boot 2 library to expose Spring Web Rest endpoints as the Lambda handler (
API Gateway request -> Lambda handler -> AWS Serverless Java Container - Spring Boot 2-> Spring Web Rest Controller
) and didn’t include any Thundra components. It was deployed with AWS SAM CLI tools without the Spring Boot build plugin.
- For the second test case, the application was bundled (zipped) as a fat (bootable) jar with the Spring Boot Gradle plugin and uploaded to AWS Lambda as a zip archive. Then, the Thundra Java layer was added and added the following configurations:
- In the third test case, the application was packaged as a Docker Image and published to Lambda AWS ECR to be used by AWS Lambda. Next, the following configurations are applied:
- Add Thundra’s API key.
- Set the
thundra_agent_lambda_container_springboot_app_artifact
environment variable with the application jar name (e.g., petlinic.jar
).
- Set the
thundra_agent_lambda_jvm_optimizeForFastStartup
environment variable to true
so the Lambda runtime JVM process will be started with configured VM arguments optimized for fast start-up (see docs).
- Set the
thundra_agent_lambda_report_cloudwatch_enable environment
variable totrue
so collected telemetry data will be reported asynchronously over AWS CloudWatch logs without any network overhead (see docs).
- Set runtime to
Custom Runtime.
- Set handler to
io.thundra.agent.container.springboot2.ContainerHandler .
- Set the
thundra_agent_lambda_container_springboot_app_artifact
environment variable with the application jar name (e.g., petlinic.jar
).
- Set the
thundra_agent_lambda_jvm_optimizeForFastStartup
environment variable to true
so Lambda runtime JVM process will be started with configured VM arguments optimized for fast start-up.
- Set the
thundra_agent_lambda_report_cloudwatch_enable
environment variable to true so collected telemetry data will be reported asynchronously over AWS CloudWatch logs without any network overhead.
As seen from the benchmark results, Thundra boosts application initialization duration up to 30% and produces highly informative distributed traces automatically.
Also, according to our findings, AWS Lambda Docker images have some overhead (1-2 seconds lost) before our runtime starts. If you want to use your Docker image in Lambda but don’t want to accept the cold start, you can read another Thundra solution for dealing with cold start.
Wrapping Up
Millions of developers all around the world pick Spring Boot as an easy way of developing web applications with Java runtime. However, they also have to deal with the operational aspect of those applications because of the infrastructure the applications run on. AWS Lambda removes the operational burden of application teams due to lessened operational tasks. Moreover, there are cost advantages due to the pay-per-use nature of AWS Lambda and from the total cost of ownership perspective. Thundra makes it possible to migrate existing VM or containerized applications to AWS Lambda platforms without need for any modification. So, with the help of Thundra, lift-and-shift to serverless is very straightforward: Just upload and add Thundra. That’s all!
Get started with Thundra APM today and don’t forget to have a look at Thundra Sidekick!