Modern Applications and AWS Aurora Serverless
By: Derek Lewis, Solutions Architect
At Silex Data Solutions we have been evaluating AWS Aurora Serverless for some of our internally-developed customer-facing applications to minimize our cloud costs. In this post, we’ll cover our experience migrating an application from a traditional RDS instance to an Aurora Serverless cluster. Lastly, we’ll provide some best practices that we have learned during our evaluation.
Aurora Serverless provides a “serverless” database experience, where based on utilization, the serverless database cluster is paused. While AWS calls it serverless, there are obviously still servers on the back-end, but from a customer AWS experience, there are no database instances to manage – only the database, itself, and the underlying storage, snapshots, security, and network configuration. Compute charges incurred are based on an Aurora Capacity Unit (ACU) in 5-minute blocks. The number of capacity units allocated determines CPU and memory capacity. The important part is that when paused, the database cluster consumes no compute resources, and therefore, incurs no compute AWS billing charges. With that said, the underlying block storage and snapshots still incur billing charges when the serverless cluster is paused or running.
Additionally, as we will see Aurora Serverless provides the capability for a database to grow compute resources online, elastically and with minimum interruption. Aurora Serverless can recognize when the workload exceeds the current resources and based on configuration, scale to additional compute.
The application in question utilizes Spring Boot, Spring Data JPA for persistence, Spring Cloud AWS for AWS integration, and a PostgreSQL back-end that we had hosted on a RDS PostgreSQL instance. A traditional RDS instance has several downsides for applications where the workload is not always active – examples would be development, test, and QA environments; applications where the workload is only active during times of the day, e.g. 8AM-5PM; or databases that do not always need to be available, e.g. day or month-end reporting. For those particular situations, you can utilize a Lambda function or other automation to stop/start an RDS database, assuming it is not in a multi-AZ configuration; however, Aurora Serverless provides a fully automated solution to suspend the compute resources when there is no database workload.
For this particular application, the application is only used by a few users from 8AM-5PM, so this application would be a potential candidate to utilize Aurora Serverless for the database back-end. Since the application has been built with Spring Data JPA and PostgreSQL, there are no database configuration changes moving to Aurora Serverless. We simply provision an Aurora Serverless PostgreSQL database cluster using the Amazon RDS console.
Next, select “Serverless”. Afterwards, define a database name and database credentials, as you would for any other RDS instance.
The only other Aurora Serverless-specific configuration are the capacity and scaling settings.
Checking “Pause compute capacity after consecutive minutes of inactivity” will provide the pause functionality discussed earlier. Once enabled, Aurora Serverless will recognize when there is no database workload and suspend the compute resources for the database. A time interval can be selected for a period of inactivity. The other important setting on this section is the Minimum/Maximum Aurora capacity units – this specifies the minimum compute capacity and maximum compute capacity of the Aurora Serverless instance. Aurora Serverless can also detect when the workload exceeds the current capacity and can automatically scale the compute capacity elastically to more compute resources. Similarly, when the workload shrinks to a smaller size, Aurora Serverless will shrink the compute resources. This elastic expansion & shrinking of the compute resources is done in Aurora capacity units. Available capacity ranges from 4GB of memory to 768GB of memory.
Once the configuration in the Amazon RDS console is completed, the Aurora Serverless instance will be provisioned.
At this point, the database has been paused no CPU is consumed. This can be verified by looking at the event log and monitoring graphs for the database in the Amazon RDS console.
Now, we can simply point our application towards the database connection string provided by RDS. In our case, we’re using Elastic Beanstalk as the compute for our Spring Boot application, as well as Systems Manager Parameter Store for our runtime configuration. Changing our database from the RDS PostgreSQL instance to the Aurora Serverless PostgreSQL cluster is as simple as changing the connection string in our Parameter Store for the application.
After restarting the application to connect to our new Aurora Serverless PostgreSQL cluster, we see the database connections from the application via the Amazon RDS Console. The database cluster is no longer paused. We see that 10 database connections are now active because we are using the default HikariCP JDBC pool size with Spring Boot.
With the default HikariCP configuration the 10 database connections from our application will stay active even though the application is idle. This will cause the Aurora Serverless cluster to never pause. How Aurora Serverless recognizes whether or not a database is idle is based on the database connection count – this is an important consideration for anyone looking at Aurora Serverless. An application needs to support shutdown of all idle database connections, as well as handling a short delay in reconnecting to the database – most modern JDBC connection pooling implementations support this capability.
In our case, we will simply update the Spring Boot application profile with a few HikariCP parameters.
spring.datasource.hikari.minimum-idle=0 spring.datasource.hikari.maximum-pool-size=10 spring.datasource.hikari.connection-timeout=60000 spring.datasource.hikari.max-lifetime=90000 spring.datasource.hikari.idle-timeout=90000
Together, these settings will:
- Change the minimum idle connection count to 0 from 10 – this will allow the application to spin-down idle database connections all the way to zero.
- We retain a maximum connection pool size of 10 connections – this means our application can never make more than 10 connections to the database.
- We increase our connection timeout to 60 seconds. This allows our application to tolerate the brief delay that Aurora Serverless requires to resume the database after it has been paused. From our experience, this tends to be 15 seconds or less. Without some ability to change the configuration with your pooling implementation or database connection, your application may receive errors and exit prematurely before the database resume can complete.
- Connections will have a maximum lifetime of 90 seconds. For a transaction web-based application, this will be fine as our application will create new connections after 90 seconds once the connection is idle. This ensures that we have fresh connections going to our Aurora Serverless cluster always.
- Lastly, the idle timeout has been changed to 90 seconds. This controls how long the database connection can be idle before it is closed. This is the setting that will cause our application to close database connections to the Aurora Serverless cluster once it becomes idle.
After these settings have been deployed to our application, we can expect our application to close connections appropriately once it is idle and allow our Aurora Serverless cluster to pause.
Once 5 minutes have passed, we will see the Aurora Server cluster database pause successfully.
We can now see that once our application is idle, the Aurora Serverless database cluster will now pause successfully.
Before this post wraps up, there are a few other important financial considerations with Aurora Serverless that need to be evaluated to determine whether or not it makes sense for your application and workload.
- Aurora Serverless clusters are more expensive than traditional RDS database instances. As an example, take a RDS PostgreSQL db.t2.medium instance w/ 4GB of memory. The cost to run it for a full month is $55.74. The cost to run an Aurora Serverless PostgreSQL cluster w/ 2 capacity units (4GB memory) for a full month is $89.84. The break-even point in terms of utilization is around 60%-65%.
- Based on the above Aurora Serverless would not make financial sense if you have a need for a database to be available and 100% utilized throughout the month.
- Again, where Aurora Serverless has significant cost savings is with database workloads that run only for a few hours a day or a few days out of the month.
- Likewise, another situation where Aurora Serverless makes significant financial sense is where you have a workload that needs to scale elastically during certain times of the month or year. Let’s say that you have a workload that requires 2 CPUs and 32GB of memory most of the time; however, there are certain peak periods where the workload requires 8 CPUs and 128GB of memory. Aurora Serverless could be setup to elastically grow your database cluster with minimum online disruption from 16 capacity units to 64 capacity units, and then, as needed, shrink back down to 16 capacity units. Assuming this would be required less than half of the time, there would be significant cost savings over provisioning a db.r5.4xlarge RDS instance, for example.
Our cloud practice at Silex Data Solutions can assist you with assessing your on-premise or cloud environment to determine whether or not your applications would be a fit for Aurora Serverless or other cloud-native database solutions. Please feel free to reach out to me at dlewis@silexdata.com if you have any questions regarding AWS Aurora Serverless or our cloud practice.