Load testing is an important part when you are designing any type of application, whether it is traditional EC2 based or container-based or a complete serverless application.
Why is Load Testing important?
Load testing will help us to find the following
- How fast is the system
- How much load can the system handle
- Under what conditions will the system fail
- Determine our application’s capabilities by measuring its response time, throughput, CPU utilization, latency, etc. during average and heavy user load. This will eventually help in determining the infrastructure needs as the system scales upward.
- It gives us an opportunity to find strange behavior or surprises when we subject an application to an insane amount of load (stress testing). Strange behaviors include request timeouts, IO Exceptions, memory leaks, or any security issues.
Choosing a Load testing tool or framework
There are many great load testing frameworks available. Some of the leading tools are,
- Jmeter
- Locust
- Artillery.io
Each of the above tools provides common and some additional features and different methods of load testing. But the only problem with these tools is the throughput it can generate towards your application is limited to the host systems’ memory and CPU capacity. If you want to want to test high and quick traffic ramp-up scenarios it’s not possible to do it from your laptop or PC. You can either have a high-end PC or you can run it on a Cloud Virtual Machine, it can be expensive, plus some of the above tools come with a GUI, which cannot be accessed via VM’s.
So how can we do load tests at scale without having a high-end testing infrastructure?
Load Testing Serverless Applications with Serverless Artillery
Serverless artillery is a combination of serverless framework and artillery.io
Combine serverless with artillery and you get serverless-artillery for an instant, cheap, and easy performance testing at scale
Serverless-artillery makes it easy to test your services for performance and functionality quickly, easily, and without having to maintain any servers or testing infrastructure.
Use serverless-artillery if
1. You want to know if your services (either internal or public) can handle different amounts of traffic load (i.e. performance or load testing).
2. You want to test if your services behave as you expect after you deploy new changes (i.e. acceptance testing).
3. You want to constantly monitor your services overtime to make sure the latency of your services is under control (i.e. monitoring mode).
How It Works
- Serverless-artillery would be installed and run on your local machine. From the command line run slsart --help
to see various serverless-artillery commands
- It takes your JSON or YAML load script `script.yml` that specifies,
- test target/URL/endpoint/service
- load progression
- and the scenarios that are important for your service to test.
Let’s See It in Action
*Load Testing A Sample Application*
In this example, we will load test a single endpoint(GET) serverless API built with AWS API Gateway, Lambda, and DynamoDB
*Installing Serverless Artillery on local machine*
*Prerequisite*
- NodeJS v8 +
- Serverless Framework CLI
npm install -g serverless
Installing serverless-artillery
npm install -g serverless-artillery
To check that the installation succeeded, run:
slsart --version
We can also install it on a [docker container](https://github.com/Nordstrom/serverless-artillery#installing-in-docker)
*Setting up the Load Test Configuration*
mkdir load-test
cd load-test
slsart script // this will create script.yml
config:
target: "https://xxxxxxx.execute-api.us-east-1.amazonaws.com"
phases:
-
duration: 300
arrivalRate: 500
rampTo: 10000
scenarios:
-
flow:
-
get:
url: "/dev/get?id=john"
Understanding `script.yml`
config:
The config section defines the target (the hostname or IP address of the system under test),the load progression, and protocol-specific settings such as HTTP response timeouts or [Socket.io](http://socket.io/) transport options
target:
the URI of the application under test. For an HTTP application, it’s the base URL for all requests
phases:
specify the duration of the test and the frequency of requests
scenarios:
The scenarios section contains definitions for one or more scenarios for the virtual users that Artillery will create.
flow:
a “flow” is an array of operations that a virtual user performs, e.g. GET and POST requests for an HTTP-based application
*Deploy to AWS*
slsart deploy --stage <your-unique-stage-name>
Start the load Test
slsart invoke --stage <your-unique-stage-name>
The above “script.yml” will try to generate 500 user request/second towards the API Gateway Endpoint and it will try to ramp up the requests to 10000/RPS in a period of 5 minutes
And the result of the test will look like this in a cloud watch dashboard.
As we can see in the above graph, there are a lot of requests that were throttled by lambda. That is because of lambda’s concurrency limit of 1000.
How Load Testing Helps Serverless Applications
One of the important insights we can get from load testing serverless applications is, It helps to find out the default soft limits or hidden limits of serverless tools. By knowing this we will be able to architecture our application to handle high traffic without throttling the request and hitting the AWS limits.
It also helps to find out the following things,
- Lambda Insights
- To find concurrency limits
- To find out the timeouts
- To find out Memory Exceptions
- To find out Cold starts (You can warm up or add provisioned concurrency to those functions)
- API Gateway
- To understand the request throttling limits, increase or decrease them according to application needs
- DynamoDB
- To get the read write usage metrics and do capacity planning for handling different level of traffic