UNPKG

serverless-artillery

Version:

A serverless performance testing tool. `serverless` + `artillery` = crush. a.k.a. Orbital Laziers [sic]

772 lines (659 loc) 111 kB
# Serverless-artillery [![Build Status](https://travis-ci.org/Nordstrom/serverless-artillery.svg?branch=master)](https://travis-ci.org/Nordstrom/serverless-artillery) [![Coverage Status](https://coveralls.io/repos/github/Nordstrom/serverless-artillery/badge.svg?branch=master)](https://coveralls.io/github/Nordstrom/serverless-artillery?branch=master) [//]: # (Thanks to https://www.divio.com/en/blog/documentation/) # Introduction Combine [`serverless`](https://serverless.com) with [`artillery`](https://artillery.io) and you get `serverless-artillery` (a.k.a. `slsart`). 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 amount of traffic load (i.e. performance or load testing). 1. You want to test if your services behave as you expect after you deploy new changes (i.e. acceptance testing). 1. You want to constantly monitor your services over time to make sure the latency of your services is under control (i.e. monitoring mode). # Table of Contents - [Installation](#installation) - [Installing on local machine](#installing-on-local-machine) - [Prerequisite](#prerequisite) - [1. Node JS](#1-node-js) - [2. Serverless Framework CLI](#2-serverless-framework-cli) - [Installing serverless-artillery](#installing-serverless-artillery) - [Installing in Docker](#installing-in-docker) - [Uninstallation](#uninstallation) - [How it works?](#how-it-works) - [Load generator Lambda function on AWS](#load-generator-lambda-function-on-aws) - [Before running serverless-artillery](#before-running-serverless-artillery) - [Setup for Nordstrom Technology](#setup-for-nordstrom-technology) - [Setup for everyone else](#setup-for-everyone-else) - [Tutorial 1: Run a quick performance test](#tutorial-1-run-a-quick-performance-test) - [1. Setup AWS account credentials](#1-setup-aws-account-credentials) - [2. Command line](#2-command-line) - [3. Deploy](#3-deploy) - [4. Invoke](#4-invoke) - [5. Remove](#5-remove) - [Tutorial 2: Performance test with custom script](#tutorial-2-performance-test-with-custom-script) - [1. Create new directory](#1-create-new-directory) - [2. Create `script.yml`](#2-create-scriptyml) - [3. Understanding `script.yml`](#3-understanding-scriptyml) - [4. Customizing `script.yml`](#4-customizing-scriptyml) - [5. Setup AWS account credentials](#5-setup-aws-account-credentials) - [6. Deploy assets to AWS](#6-deploy-assets-to-aws) - [7. Invoke performance test](#7-invoke-performance-test) - [8. Remove assets from AWS](#8-remove-assets-from-aws) - [Tutorial 3: Performance test with custom deployment assets](#tutorial-3-performance-test-with-custom-deployment-assets) - [1. Create new directory](#1-create-new-directory-1) - [2. Create `script.yml`](#2-create-scriptyml) - [3. Understanding `script.yml`](#3-understanding-scriptyml) - [4. Customizing `script.yml`](#4-customizing-scriptyml) - [5. Create custom deployment assets](#5-create-custom-deployment-assets) - [6. Understanding `serverless.yml`](#6-understanding-serverlessyml) - [a. Service name](#a-service-name) - [b. Load generator Lambda function name](#b-load-generator-lambda-function-name) - [c. Load generator Lambda function permissions](#c-load-generator-lambda-function-permissions) - [7. Customizing `serverless.yml`](#7-customizing-serverlessyml) - [a. Customization for Nordstrom Engineers](#a-customization-for-nordstrom-engineers) - [b. Service name](#b-service-name) - [c. Plugins](#c-plugins) - [i. CloudWatch plugin](#i-cloudwatch-plugin) - [ii. Datadog plugin](#ii-datadog-plugin) - [8. Setup AWS account credentials](#8-setup-aws-account-credentials) - [9. Deploy assets to AWS](#9-deploy-assets-to-aws) - [10. Invoke performance test](#10-invoke-performance-test) - [11. Remove assets from AWS](#11-remove-assets-from-aws) - [Tutorial 4: Killing in-progress performance test](#tutorial-4-killing-in-progress-performance-test) - [1. Increase `duration`](#1-increase-duration) - [2. Setup AWS account credentials](#2-setup-aws-account-credentials) - [3. Deploy assets to AWS](#3-deploy-assets-to-aws) - [4. Invoke performance test](#4-invoke-performance-test) - [5. Kill the in-progress performance test](#5-kill-the-in-progress-performance-test) - [6. Wait before re-deploying](#6-wait-before-re-deploying) - [Performance test workshop](#performance-test-workshop) - [Other commands and use cases](#other-commands-and-use-cases) - [Killing in-progress performance test](#killing-in-progress-performance-test) - [Create customized `script.yml`](#create-customized-scriptyml) - [Performance test using script file with different name/path](#performance-test-using-script-file-with-different-namepath) - [Reserved and unsupported flags](#reserved-and-unsupported-flags) - [Reserved flags](#reserved-flags) - [Unsupported flags](#unsupported-flags) - [Providing a data store to view the results of your performance test](#providing-a-data-store-to-view-the-results-of-your-performance-test) - [Related tools and plugins](#related-tools-and-plugins) - [Performance testing VPC hosted services](#performance-testing-vpc-hosted-services) - [Using Payload/CSV files to inject data in scenarios of your `script.yml`](#using-payloadcsv-files-to-inject-data-in-scenarios-of-your-scriptyml) - [Advanced customization use cases](#advanced-customization-use-cases) - [Deployment assets and settings customization](#deployment-assets-and-settings-customization) - [Test script and execution customization using Artillery.io](#test-script-and-execution-customization-using-artilleryio) - [Script splitting customization](#script-splitting-customization) - [Debugging and Tracing Behavior Customization](#debugging-and-tracing-behavior-customization) - [`_trace`](#_trace) - [`_simulation`](#_simulation) - [Splitting and Distribution Logic Customization](#splitting-and-distribution-logic-customization) - [Scripts](#scripts) - [Splitting](#splitting) - [Acceptance mode](#acceptance-mode) - [`match` clause](#match-clause) - [Acceptance test command](#acceptance-test-command) - [Tutorial 5: Acceptance mode](#tutorial-5-acceptance-mode) - [1. Customize `script.yml`](#1-customize-scriptyml) - [2. Setup AWS account credentials](#2-setup-aws-account-credentials-1) - [3. Deploy assets to AWS](#3-deploy-assets-to-aws-1) - [4. Invoke acceptance test](#4-invoke-acceptance-test) - [5. Observe the results](#5-observe-the-results) - [6. Test failure scenario](#6-test-failure-scenario) - [6.1. Edit `script.yml` to fail `match`](#61-edit-scriptyml-to-fail-match) - [6.2. Invoke acceptance test](#62-invoke-acceptance-test) - [6.3. Observe the results](#63-observe-the-results) - [7. Remove assets from AWS](#7-remove-assets-from-aws) - [More about acceptance mode](#more-about-acceptance-mode) - [Acceptance testing in CI/CD](#acceptance-testing-in-cicd) - [Run `script.yml` exclusively in acceptance mode](#run-scriptyml-exclusively-in-acceptance-mode) - [Use same `script.yml` for performance and acceptance testing and monitoring](#use-same-scriptyml-for-performance-and-acceptance-testing-and-monitoring) - [To configure acceptance behavior](#to-configure-acceptance-behavior) - [Monitoring mode](#monitoring-mode) - [Tutorial 6: Monitoring mode without serverless-artillery alert](#tutorial-6-monitoring-mode-without-serverless-artillery-alert) - [1. Create custom deployment assets](#1-create-custom-deployment-assets) - [2. Setup AWS account credentials](#2-setup-aws-account-credentials-2) - [3. Tryout monitoring mode](#3-tryout-monitoring-mode) - [3.1. Deploy assets to AWS](#31-deploy-assets-to-aws) - [3.2. Invoke monitoring once](#32-invoke-monitoring-once) - [4. Customize deployment assets to turn on monitoring](#4-customize-deployment-assets-to-turn-on-monitoring) - [5. Deploy assets to AWS to start monitoring](#5-deploy-assets-to-aws-to-start-monitoring) - [6. Pause monitoring](#6-pause-monitoring) - [6.1. Method 1: Using CloudWatch Rules](#61-method-1-using-cloudwatch-rules) - [6.2. Method 2: Turn monitoring off in `serverless.yml`](#62-method-2-turn-monitoring-off-in-serverlessyml) - [7. Remove assets from AWS](#7-remove-assets-from-aws-1) - [Tutorial 7: Monitoring mode with serverless-artillery alert](#tutorial-7-monitoring-mode-with-serverless-artillery-alert) - [1. Create custom deployment assets](#1-create-custom-deployment-assets-1) - [2. Setup AWS account credentials](#2-setup-aws-account-credentials-3) - [3. Customize script to have `match` clause](#3-customize-script-to-have-match-clause) - [4. Customize deployment assets to add at least one subscription](#4-customize-deployment-assets-to-add-at-least-one-subscription) - [5. Tryout monitoring mode](#5-tryout-monitoring-mode) - [5.1. Deploy assets to AWS](#51-deploy-assets-to-aws) - [5.2. Invoke monitoring once](#52-invoke-monitoring-once) - [6. Test failure scenario](#6-test-failure-scenario-1) - [6.1. Edit `script.yml` to fail `match`](#61-edit-scriptyml-to-fail-match-1) - [6.2. Invoke monitoring once](#62-invoke-monitoring-once) - [7. Customize deployment assets to turn on monitoring](#7-customize-deployment-assets-to-turn-on-monitoring) - [8. Deploy assets to AWS to start monitoring](#8-deploy-assets-to-aws-to-start-monitoring) - [9. Pause monitoring](#9-pause-monitoring) - [10. Remove assets from AWS](#10-remove-assets-from-aws) - [More about monitoring mode](#more-about-monitoring-mode) - [Run `script.yml` exclusively in monitoring mode](#run-scriptyml-exclusively-in-monitoring-mode) - [Use same `script.yml` for performance and acceptance testing and monitoring](#use-same-scriptyml-for-performance-and-acceptance-testing-and-monitoring-1) - [To configure monitoring behavior](#to-configure-monitoring-behavior) - [Upgrading customized projects built with older versions of serverless-artillery](#upgrading-customized-projects-built-with-older-versions-of-serverless-artillery) - [Known Upgrade Issues](#known-upgrade-issues) - [Detailed Usage](#detailed-usage) - [Commands](#commands) - [`deploy`](#deploy) - [`invoke`](#invoke) - [`kill`](#kill) - [`remove`](#remove) - [`script`](#script) - [`configure`](#configure) - [`upgrade`](#upgrade) - [Troubleshooting](#troubleshooting) - [Problems installing?](#problems-installing) - [External References](#external-references) - [If you've read this far](#if-youve-read-this-far) # Installation ## Installing on local machine You can install serverless-artillery on your local machine as follows. ### Prerequisite #### 1. Node JS Before installing serverless-artillery, install Node JS from https://nodejs.org/en/download/ or with your operating system’s package manager. You can install the latest LTS version. We support any version higher than maintenance LTS (v8+). #### 2. Serverless Framework CLI Before installing serverless-artillery, install Serverless Framework CLI (a.k.a. Serverless) (v1.38+). It should be either installed globally or available in the local node_modules. To install globally use the following command. ``` npm install -g serverless ``` ### Installing serverless-artillery Now you can install serverless-artillery on your local machine using the following command. ``` npm install -g serverless-artillery ``` To check that the installation succeeded, run: ``` slsart --version ``` You should see serverless-artillery print its version if the installation has been successful. ## Installing in Docker If you prefer using Docker, refer to [example Dockerfile](Dockerfile) for installation. Please note that, post installation causes permission issues when installing in a Docker image. To successfully install in Docker make sure to add the following to your Dockerfile before the Serverless Framework CLI (a.k.a. Serverless) and serverless-artillery install. ``` ENV NPM_CONFIG_PREFIX=/home/node/.npm-global ENV PATH=$PATH:/home/node/.npm-global/bin ``` # Uninstallation When needed, you can uninstall serverless-artillery from you local machine using the following command. ``` npm uninstall -g serverless-artillery ``` # How it works? <img src="docs/HowItWorks.jpg" width="442"> * Serverless-artillery would be installed and run on your local machine. From 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. * When you run `slsart deploy` command, serverless-artillery deploys a **load generator Lambda function**, on your AWS account along with other assets. * Running the tests * **Performance test:** When you run `slsart invoke` command, serverless-artillery would invoke the load generator Lambda function. * It would generate the number of requests as specified in `script.yml` to specified test target in order to run the specified scenarios. * **Acceptance test:** When you run `slsart invoke -a` command, serverless-artillery would invoke the load generator Lambda function in acceptance test mode where it runs each scenario in your script exactly once and reports the results. * **Monitoring:** When you customize the deployment assets to turn on monitoring and deploy those assets using `slsart deploy` command, the load generator Lambda function is invoked in monitoring mode once a minute 24x7 where it runs each scenario in your script 5 times and sends an alert if it detects a problem. * When you run `slsart remove` command, serverless-artillery would remove these assets from your AWS account. * When you run `slsart kill` command, serverless-artillery would kill the in-progress test and remove these assets from your AWS account. ## Technologies powering serverless-artillery <details><summary>Click to expand/collapse</summary> <p> ### Serverless Framework - The [Serverless Framework](https://serverless.com) makes managing (deploying/updating/removing) cloud assets easy. - It translates a `yaml` file to deployable assets of the target cloud provider (like AWS). - Serverless-artillery uses it to manage required assets to your cloud account. ### Artillery.io - [Artillery.io](https://artillery.io/) (built by Hassy Veldstra of shoreditch-ops) is an existing open-source node package, built for easy load testing and functional testing of a target/service/endpoint/URL. It provides a simple but powerful means of specifying how much load to create and what requests that load should comprise. - It takes in a developer-friendly JSON or YAML load script that specifies - target/URL/endpoint - load progression - and the scenarios that are important for your service to test. - It generates specified load, and measures and reports the resulting latency and return codes. - It generates the load by running on your local machine or servers. - However, if you specify more load in your script than what can be produced on your machine, artillery will throttle down the load specified in your script. While it is simple to distribute artillery across a fleet of servers, you must then manage, coordinate, and retire them. It is not a serverless solution. This is the task that serverless-artillery steps in to remove from your plate. ### Serverless-artillery - Serverless-artillery allows your script to specify an amount of load far exceeding the capacity of a single server to execute. - It breaks that script into smaller chunks (sized for a single instance of load generator Lambda function) and distribute the chunks for execution across multiple instances of load generator Lambda function. - Since this is done using a FaaS provider, the ephemeral infrastructure used to execute your load disappears as soon as your load tests are complete. </p> </details> ## Load generator Lambda function on AWS <details><summary>Click to expand/collapse</summary> <p> <img src="docs/Architecture.gif"> - Serverless-artillery generates the requests to run the specified tests using load generator Lambda function, which is deployed and invoked on AWS along with other assets. - Naming format is `<customized-service-name default:serverless-artillery>-<optional-unique-string-><stage default:dev>-loadGenerator`. For example, `serverless-artillery-dev-loadGenerator` or `serverless-artillery-XnBa473psJ-dev-loadGenerator`. - It has an ephimeral architecture. It only exists as long as you need it. - It runs Artillery.io node package in AWS Lambda function. - Each lambda function can only generate a certain amount of load, and can only run for up to five minutes (five minutes was a built-in limitation of AWS Lambda. Now it has been raised to 15 minutes). - Given these limitations, it is often necessary to invoke more lambdas - both to scale horizontally (to generate higher load) as well as handing off the work to a new generation of lambdas before their run-time has expired. - Above diagram shows how Serverless Artillery solves this problem. - It first runs the Lamdba function in a **controller** mode. It examines the submitted load config JSON/YAML script (this is identical to the original “servered” [Artillery.io](https://artillery.io/) script). This script is also referred to as original script. If the load in the original script exceeds what a single lambda is configured to handle, then the load config is chopped up into workloads achievable by a single lambda. - Controller lambda then invokes as many **worker** lambdas as necessary to generate the load. Controller lambda passes a script to worker lambda that is created by chopping up the original script. - Towards the end of the Lambda runtime the controller lambda invokes a new controller lambda to produce load for the remaining duration. - The result of the load test can be reported to CloudWatch, InfluxDB or Datadog through plugins and then visualized with CloudWatch, Grafana or Datadog dashboard. </p> </details> # Before running serverless-artillery Serverless-artillery needs to _deploy_ assets like [load generator Lambda function](#load-generator-lambda-function-on-aws) to AWS, _invoke_ the function to run the tests and _remove_ these assets from AWS when not needed. Hence you need an AWS account and setup credentials with which to deploy, invoke and remove the assets from AWS. ## Setup for Nordstrom Technology If you are a **_Nordstrom_** engineer, please see the page titled **_`Serverless Artillery - Nordstrom Technology Setup`_** in **Confluence** and follow the instructions there. ## Setup for everyone else In order to use serverless-artillery, depending on the AWS account environment you're working in, you may need to define `AWS_PROFILE` to declare the AWS credentials to use and possibly `HTTP_PROXY` in order to escape your corporate proxy. See the [Serverless Framework docs](https://serverless.com/framework/docs/) or serverless-artillery workshop's [Lesson 0](https://github.com/Nordstrom/serverless-artillery-workshop/tree/master/Lesson0%20-%20Before%20the%20workshop) followed by [**Step 1** of Lesson 1](https://github.com/Nordstrom/serverless-artillery-workshop/tree/master/Lesson1%20-%20Hello%2C%20artillery#step-1-serverless-artillery-requires-aws-credentials) for details of how to set your local machine for successful deployment, invocation, and removal of assets from your AWS accounts. # Performance mode (performance/load testing) You can use serverless-artillery to performance test or load test your service/target/endpoint/URL. Performance testing framework forms the basis of the other two modes of serverless-artillery, i.e. acceptance mode and monitoring mode. ## Tutorial 1: Run a quick performance test If you want to quickly test your setup or see serverless-artillery in action, do the following to quickly run a **small load/performance test**. ### 1. Setup AWS account credentials Make sure you have [setup your AWS account credentials](#before-running-serverless-artillery) before proceeding. ### 2. Command line Go to command line for all the following steps in this tutorial. You can run the steps of this tutorial from anywhere in command line since the commands you run in this tutorial will not create any files on your local machine. ### 3. Deploy The `slsart deploy` command deploys required assets (like [load generator Lambda function](#load-generator-lambda-function-on-aws)) to the AWS account you selected in the previous step. By _default_ it uses `service` name `serverless-artillery` and `stage` name `dev`. And hence the _default_ AWS CloudFormation Stack name becomes `serverless-artillery-dev` (format: `<service-name default:serverless-artillery>-<stage-name default:dev>`). You will see that if you go to your AWS account console > CloudFormation after running the command. Since multiple developers could share an AWS account, we recommend creating a unique stack for your use. For that we recommend either using custom deployment assets as shown in [Tutorial 3](#tutorial-3-performance-test-with-custom-deployment-assets) or use the _optional_ `stage` argument as shown in the following command. ``` slsart deploy --stage <your-unique-stage-name> ``` The AWS CloudFormation Stack name would be `serverless-artillery-<your-unique-stage-name>`. For example, ``` slsart deploy --stage test1 ``` The AWS CloudFormation Stack name in this case would be `serverless-artillery-test1`. ### 4. Invoke The following command will invoke [load generator Lambda function](#load-generator-lambda-function-on-aws) using the default load script (`script.yml`), creating small traffic against the sample endpoint specified in the default script. Note that this default load script is part of the global install of serverless-artillery and not in the local folder from where you are running the command. ``` slsart invoke --stage <your-unique-stage-name> ``` At the end of the test serverless-artillery will generate a report of the test. **Please note that this report is generated only for small load.** See [here](#providing-a-data-store-to-view-the-results-of-your-performance-test) for details. If you go to AWS Lambda console > find the `loadGenerator` Lambda corresponding to your stack > `Monitoring` tab > `Invocations` graph, you will see that the Lambda function was invoked to generate the load. You can also see the logs produced by the Lambda in CloudWatch Logs. ### 5. Remove The following command will remove the AWS CloudFormation Stack deployed in step 3. If you are a **_Nordstrom_** engineer, please see the page titled **_`Serverless Artillery - Remove Instructions`_** in **Confluence** and follow the instructions there. ``` slsart remove --stage <your-unique-stage-name> ``` ## Tutorial 2: Performance test with custom script Throughout this tutorial we will walk you towards performance testing the AWS website, https://aws.amazon.com/. We would test with our _custom_ script but would use _default_ deployment assets. ### 1. Create new directory Start by creating a new directory for this tutorial and go to that directory in command line. ### 2. Create `script.yml` Serverless-artillery needs to know information about the performance test that user wants to run. It needs information like, the target URL of the service that user wants to test, load progression, user's interaction with the service (scenarios) etc. All these are described in a `yml` file. It is the same `yml` that Artillery.io uses. - **Please see [here for basic concepts for Artillery.io usage](https://artillery.io/docs/basic-concepts/#basic-concepts).** - **Please see [here for Artillery.io's test script reference](https://artillery.io/docs/script-reference/).** Run the following command to create the initial `script.yml` file. ``` slsart script ``` ### 3. Understanding `script.yml` Open `script.yml` with your favorite editor to see what it contains. <details><summary>Click to expand/collapse</summary> <p> ``` # Thank you for trying serverless-artillery! # This default script is intended to get you started quickly. # There is a lot more that Artillery can do. # You can find great documentation of the possibilities at: # https://artillery.io/docs/ config: # this hostname will be used as a prefix for each URI in the flow unless a complete URI is specified target: "http://aws.amazon.com" phases: - duration: 5 arrivalRate: 2 scenarios: - flow: - get: url: "/" ``` </p> </details> - The script has [`config` block](https://artillery.io/docs/script-reference/#the-config-section) - under which it specifies http://aws.amazon.com as the `target` for the test - and that requests should be made using [HTTP protocol](https://artillery.io/docs/http-reference/) - There is one [load `phase`](https://artillery.io/docs/script-reference/#load-phases) of `duration` of 5 sec and `arrivalRate` of 2 new virtual users arriving every second. - The script has [`scenarios` block](https://artillery.io/docs/script-reference/#scenarios) - which contains one scenario - which contains one flow - which has one [flow action](https://artillery.io/docs/http-reference/#flow-actions) to send [GET request](https://artillery.io/docs/http-reference/#get-post-put-patch-delete-requests) for the specified `target`. ### 4. Customizing `script.yml` This step is optional in the tutorial. If you like you can customize `script.yml` as follows. - If you have a public endpoint/service/URL that you would like to load test then you can change `target` to point to that. - You can also change the [load `phase`](https://artillery.io/docs/script-reference/#load-phases) and [`scenarios` block](https://artillery.io/docs/script-reference/#scenarios) as per your need. We recommend using a low load to try the tool first. ### 5. Setup AWS account credentials Make sure you have [setup your AWS account credentials](#before-running-serverless-artillery) before proceeding. ### 6. Deploy assets to AWS This section is same as before. See [here](#3-deploy) for details. ### 7. Invoke performance test Now you are all set to invoke performance test using following command. ``` slsart invoke --stage <your-unique-stage-name> ``` At the end of the test serverless-artillery will generate a report of the test. **Please note that this report is generated only for small load.** See [here](#providing-a-data-store-to-view-the-results-of-your-performance-test) for details. If you go to AWS Lambda console > find the `loadGenerator` Lambda corresponding to your stack > `Monitoring` tab > `Invocations` graph, you will see that the Lambda function was invoked to generate the load. You can also see the logs produced by the Lambda in CloudWatch Logs. **NOTE** that for performance testing, the command will take the `script.yml` from your local machine (and not the one deployed in AWS account) to run the performance test. Hence if you edit it on your local machine after deploying assets to AWS, you don't need to deploy again in order to run the performance test again. Also note that this is true only for performance test and acceptance test and not monitoring. ### 8. Remove assets from AWS After the test is done, you can remove the assets from AWS using following command. If you are a **_Nordstrom_** engineer, please see the page titled **_`Serverless Artillery - Remove Instructions`_** in **Confluence** and follow the instructions there. ``` slsart remove --stage <your-unique-stage-name> ``` ## Tutorial 3: Performance test with custom deployment assets Throughout this tutorial we will walk you towards performance testing the AWS website, https://aws.amazon.com/. We would test with our _custom_ script and _custom_ deployment assets. ### 1. Create new directory Start by creating a new directory for this tutorial and go to that directory in command line. ### 2. Create `script.yml` This section is same as before. See [here](#2-create-scriptyml) for details. ### 3. Understanding `script.yml` This section is same as before. See [here](#3-understanding-scriptyml) for details. ### 4. Customizing `script.yml` This section is same as before. See [here](#4-customizing-scriptyml) for details. ### 5. Create custom deployment assets Create a _local copy_ of the deployment assets for your customization and then deployment to AWS, using following command. The command generates a local copy of the load generator lambda function code (along with other assets) that can be edited and deployed with your changed settings if needed. It also runs `npm install` after creating local copy of the deployment assets. ``` slsart configure ``` The important files among other files created by this command are as follows. |File|Description| |:----|:----------| |`package.json`|Node.js dependencies for the load generator Lambda. Add Artillery.io plugins you want to use here.| |`serverless.yml`|Serverless-artillery's service definition/configuration using Serverless Framework. Change AWS-specific settings here.| |`handler.js`|Load generator Lambda code. **EDIT AT YOUR OWN RISK.**| **Note** that everytime you make changes to these local copy of deployment assets or `serverless.yml` file, you need to redeploy using `slsart deploy` command. **Note** that if you change `package.json` then you need to run `npm install` and then redeploy using `slsart deploy` command. ### 6. Understanding `serverless.yml` `serverless.yml` contains serverless-artillery's service definition/configuration using Serverless Framework. Open `serverless.yml` with your favorite editor to see what it contains. <details><summary>Click to expand/collapse</summary> <p> ``` # We're excited that this project has provided you enough value that you are looking at its code! # # This is a standard [Serverless Framework](https://www.serverless.com) project and you should # feel welcome to customize it to your needs and delight. # # If you do something super cool and would like to share the capability, please open a PR against # https://www.github.com/Nordstrom/serverless-artillery # # Thanks! # If the following value is changed, your service may be duplicated (this value is used to build the CloudFormation # Template script's name) service: serverless-artillery-XnBa473psJ provider: name: aws runtime: nodejs8.10 iamRoleStatements: # This policy allows the function to invoke itself which is important if the script is larger than a single # function can produce - Effect: 'Allow' Action: - 'lambda:InvokeFunction' Resource: 'Fn::Join': - ':' - - 'arn:aws:lambda' - Ref: 'AWS::Region' - Ref: 'AWS::AccountId' - 'function' - '${self:service}-${opt:stage, self:provider.stage}-loadGenerator*' # must match function name # This policy allows the function to publish notifications to the SNS topic defined below with logical ID monitoringAlerts - Effect: 'Allow' Action: - 'sns:Publish' Resource: Ref: monitoringAlerts # must match the SNS topic's logical ID functions: loadGenerator: # !!Do not edit this name!! handler: handler.handler # the serverlessArtilleryLoadTester handler() method can be found in the handler.js source file timeout: 300 # set timeout to be 5 minutes (max for Lambda) environment: TOPIC_ARN: Ref: monitoringAlerts TOPIC_NAME: 'Fn::GetAtt': - monitoringAlerts - TopicName events: - schedule: name: '${self:service}-${opt:stage, self:provider.stage}-monitoring' # !!Do not edit this name!! description: The scheduled event for running the function in monitoring mode rate: rate(1 minute) ######################################################################################################################## ### !! BEFORE ENABLING... !!! ### 0. Change `'>>': script.yml` below to reference the script you want to use for monitoring if that is not its name. ### The script must be in this directory or a subdirectory. ### 1. Modify your `script.yml` to provide the details of invoking every important surface of your service, as per ### https://artillery.io/docs ### 2. Add a `match` clause to your requests, specifying your expectations of a successful request. This relatively ### undocumented feature is implemented at: https://github.com/shoreditch-ops/artillery/blob/82bdcdfc32ce4407bb197deff2cee13b4ecbab3b/core/lib/engine_util.js#L318 ### We would welcome the contribution of a plugin replacing this as discussed in https://github.com/Nordstrom/serverless-artillery/issues/116 ### 3. Modify the `monitoringAlerts` SNS Topic below, uncommenting `Subscription` and providing subscriptions for any ### alerts that might be raised by the monitoring function. (To help you out, we've provided commented-out examples) ### (After all, what good is monitoring if noone is listening?) ### 4. Deploy your new assets/updated service using `slsart deploy` ### 5. [As appropriate] approve the subscription verifications for the SNS topic that will be sent following its creation ######################################################################################################################## enabled: false input: '>>': script.yml mode: monitoring resources: Resources: monitoringAlerts: # !!Do not edit this name!! Type: 'AWS::SNS::Topic' Properties: DisplayName: '${self:service} Monitoring Alerts' # Subscription: # docs at https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sns-subscription.html # - Endpoint: http://<host>/<path> # the endpoint is an URL beginning with "http://" # Protocol: http # - Endpoint: https://<host>/<path> # the endpoint is a URL beginning with "https://" # Protocol: https # - Endpoint: <target>@<host> # the endpoint is an email address # Protocol: email # - Endpoint: <target>@<host> # the endpoint is an email address # Protocol: email-json # - Endpoint: <phone-number> # the endpoint is a phone number of an SMS-enabled device # Protocol: sms # - Endpoint: <sqs-queue-arn> # the endpoint is the ARN of an Amazon SQS queue # Protocol: sqs # - Endpoint: <endpoint-arn> # the endpoint is the EndpointArn of a mobile app and device. # Protocol: application # - Endpoint: <lambda-arn> # the endpoint is the ARN of an AWS Lambda function. # Protocol: lambda ``` </p> </details> Please refer to [`serverless.yml` documentation](https://serverless.com/framework/docs/providers/aws/guide/serverless.yml/) for details. It defines assets needed for monitoring (turned off by default) as well which we will discuss later. #### a. Service name - In above `serverless.yml` the `service` name is set to `serverless-artillery-XnBa473psJ`. In your `serverless.yml` the string at the end (`XnBa473psJ`) would be different. - This will be the AWS CloudFormation stack name when you run `slsart deploy`. Format of the AWS CloudFormation stack name would be `<service-name default:serverless-artillery>-<stage-name default:dev>`. - If you specify the optional stage name with the deploy command, i.e. `slsart deploy --stage <your-unique-stage-name>`, then the AWS CloudFormation stack name would be `<service-name default:serverless-artillery>-<your-unique-stage-name>` - The `slsart configure` command adds a random string at the end of the `service` name so you get a unique stack name that does not conflict with anyone else also deploying to the same AWS account, in case you were to not specify the optional stage name with the deploy command. - You can change `service` name to some other unique string as per your need. For example, `serverless-artillery-myperftestservice` or `myloadtestservice`. - The rest of the `serverless.yml` refers to the service name by using `${self:service}`. #### b. [Load generator Lambda function](#load-generator-lambda-function-on-aws) name The Serverless Framework automatically names the Lambda function based on the service, stage and function name as follows. - The function `loadGenerator` when deployed is named as `${self:service}-${opt:stage, self:provider.stage}-loadGenerator`. - `${self:service}` is name of the service. In this `serverless.yml` it is `serverless-artillery-XnBa473psJ`. - `${opt:stage, self:provider.stage}` will either use `${opt:stage}` or `${self:provider.stage}`. - `${opt:stage}` refers to the (optional) stage name passed in `slsart deploy [--stage <stage-name>]` command. For example, if you run `slsart deploy --stage prod` then `prod` would be used for `${opt:stage}`. - If no stage name is passed in the deploy command then `${self:provider.stage}` would be used. It is the `stage` name set under `provider` block in the `serverless.yml`. If one is not provided (like in above example) it is set to `dev`. See [here](https://serverless.com/framework/docs/providers/aws/guide/serverless.yml/). - In this example function name will be set to `serverless-artillery-XnBa473psJ-dev-loadGenerator` while running `slsart deploy` command (note no stage name specified). #### c. [Load generator Lambda function](#load-generator-lambda-function-on-aws) permissions - In order to generate load the load generator Lambda needs to invoke itself. - The `iamRoleStatements` block in the `serverless.yml` gives the load generator Lambda function to invoke itself (`lambda:InvokeFunction`). ### 7. Customizing `serverless.yml` **NOTE:** Except for [one step for **_Nordstrom_** Engineers](#a-customization-for-nordstrom-engineers), all customizations are **optional** in the tutorial. If you like you can customize `serverless.yml` as follows. #### a. Customization for Nordstrom Engineers If you are a **_Nordstrom_** engineer, please see the page titled **_`Serverless Artillery - Nordstrom Technology Policies`_** in **Confluence** and follow the instructions there. #### b. Service name - You can change `service` name to some other unique string as per your need. - For example, `serverless-artillery-myperftestservice` or `myloadtestservice`. - Format of the AWS CloudFormation stack name would be `<service-name default:serverless-artillery>-<stage-name default:dev>` after you deploy. #### c. Plugins You can customize the `serverless.yml` to use required tools/plugins mentioned [below](#related-tools-and-plugins). ##### i. CloudWatch plugin In this tutorial you can add [artillery-plugin-cloudwatch](https://github.com/Nordstrom/artillery-plugin-cloudwatch) to record test results to [AWS CloudWatch](https://aws.amazon.com/cloudwatch). 1. To allow the Lambda code to write to CloudWatch, the correct NPM package dependency must be added. This modifies the package.json file to include the necessary dependency. ``` npm install --save artillery-plugin-cloudwatch ``` 2. In `script.yml`, at the end of the `config` block (which already exists) ``` config: ``` add CloudWatch plugin as follows: ``` plugins: cloudwatch: namespace: "<cloud-watch-namespace>" ``` For example, you can use ``` namespace: "serverless-artillery-myperftestservice-loadtest" ``` 3. In `serverless.yml`, at the end of the following block (which already exists) ``` provider: iamRoleStatements: ``` add the following: ``` - Effect: 'Allow' Action: - 'cloudwatch:PutMetricData' Resource: - '*' ``` ##### ii. Datadog plugin In this tutorial you can add [artillery-plugin-datadog](https://www.npmjs.com/package/artillery-plugin-datadog) to record test results to [Datadog](https://www.datadoghq.com/). 1. To allow the Lambda code to write to Datadog, the correct NPM package dependency must be added. This modifies the package.json file to include the necessary dependency. ``` npm install --save artillery-plugin-datadog ``` 2. Update the `config` portion of `script.yml` to add Datadog plugin as follows and customize the `host`, `prefix` and `tags` as per your requirement. ``` config: plugins: datadog: # Custom hostname (leave blank if not desired) host: '' # Custom metric prefix (example, to 'serverless-artillery') prefix: 'serverless-artillery' # Additional tags for all metrics tags: - 'mode:test' ``` 3. In `serverless.yml`, under `provider` section specify Datadog API key as an environment variable as follows. **NOTE** that you should not save sensitive information like Datadog API Key in plain text in a source control. Below is just for the tutorial. ``` provider: environment: DATADOG_API_KEY: "<your-datadog-api-key>" ``` ### 8. Setup AWS account credentials This section is same as before. See [here](#before-running-serverless-artillery) for details. ### 9. Deploy assets to AWS This section is same as before. See [here](#3-deploy) for details. You can go to your AWS account console > CloudFormation, and see AWS stack `<service-name default:serverless-artillery>-<stage-name default:dev>` created there depending on the customizations explained in the steps above. ### 10. Invoke performance test This section is same as before. See [here](#7-invoke-performance-test) for details. If you used CloudWatch/Datadog plugins you will be able to view the metrics on the CloudWatch/Datadog dashboard. You can learn more about using CloudWatch dashboard [here](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Dashboards.html). **Note that it can take few minutes for the data to propogate to CloudWatch/Datadog.** ### 11. Remove assets from AWS This section is same as before. See [here](#8-remove-assets-from-aws) for details. ## Tutorial 4: Killing in-progress performance test While running performance/load test it is sometimes necessary to kill the test before it is complete. Read more about the [kill command](#killing-in-progress-performance-test). ### 1. Increase `duration` If you are a **_Nordstrom_** engineer, please follow [Tutorial 3](#tutorial-3-performance-test-with-custom-deployment-assets) to create custom script and custom deployment assets. Make sure you do [customization for Nordstrom Engineers](#a-customization-for-nordstrom-engineers). Other optional customizations are not necessary for this tutorial. Others can follow [Tutorial 2](#tutorial-2-performance-test-with-custom-script) to create custom `script.yml`. Edit `script.yml` in your favorite editor and increase the `duration` to `60` seconds. ### 2. Setup AWS account credentials This section is same as before. See [here](#before-running-serverless-artillery) for details. ### 3. Deploy assets to AWS This section is same as before. See [here](#3-deploy) for details. ### 4. Invoke performance test This section is same as before. See [here](#7-invoke-performance-test) for details. ### 5. Kill the in-progress performance test Run the following command to kill the performance test. Read more about the kill command [here](#killing-in-progress-performance-test). **Note** that _kill_ command will also _remove_ the deployed assets. Hence running `slsart remove` after this is not needed. ``` slsart kill --stage <your-unique-stage-name> --region=<region-used-for-deploy> ``` You must specify a `region` when running this command: - Use `--region` option, e.g. `--region=us-east-1` - or set AWS_REGION in environment, e.g. `AWS_REGION=us-east-1` - or configure a default region using the guide below. Serverless will use the `us-east-1` region by default. ### 6. Wait before re-deploying Wait for ~5 minutes before re-deploying to let the Lambda invocation queue drain. ## Performance test workshop We've created a workshop detailing end-to-end usage of serverless-artillery for performance testing. Check out our conference-style [workshop](https://github.com/Nordstrom/serverless-artillery-workshop) for step by step lessons on how to set your system up for successful deployment, invocation, and removal. ## Other commands and use cases ### Killing in-progress performance test While running performance/load test it is sometimes necessary to kill the test before it is complete. For example, it might be done when the test target is not able to handle the current load and you want to stop the test before the service goes down. You can run the following command to kill the performance test. ``` slsart kill --stage <your-unique-stage-name> --region=<region-used-for-deploy> ``` You must specify a `region` when running this command: - Use `--region` option, e.g. `--region=us-east-1` - or set AWS_REGION in environment, e.g. `AWS_REGION=us-east-1` - or configure a default region using the guide below. Serverless will use the `us-east-1` region by default. The command will do the followings: - It will set the load generator Lambda function's [concurrency level](https://docs.aws.amazon.com/lambda/latest/dg/concurrent-executions.html#per-function-concurrency) to 0. - and then _remove_ the deployed assets. It will remove load generator Lambda function, CloudWatch logs, and IAM role. CloudWatch metrics will remain. Result: - Any further invocations of load generator Lambda will be supressed. - The already executing instances of load generator Lambda will continue and complete the assigned load generation workload. - The load generator Lambda function by default runs for up to 2 minutes. So that would be the default maximum time before the load generation stops. **You will want to wait approximately 5 minutes before redeploying to avoid the killed performance test from resuming.** Behind the scenes, AWS creates a queue for Lambda invocations. While processing the invocation requests from the queue, if a function is not available then that message will be placed back onto the queue for further attempts. As a result, redeploying your function can allow those re-queued messages to be used to invoke your re-deployed function. In our observation based on a limited set of tests, messages will be permanently failed out of the queues after 5 minutes. That is the basis of our recommendation. The default maximum duration of a [script chunk](#splitting) is 2 minutes (`maxChunkDurationInSeconds`). As a result of this, on average, load will not be produced after 1 minute but it could continue for up to the full 2 minutes. To lower the wait times after killing, this value can be overridden in your `script.yml` within the \_split attribute, as shown [here](#script-splitting-customization). This value can be as low as 15 seconds and using this value causes each script chunk to run for a maximum duration of 15 seconds. Theoretically, this means that you’d only have to wait 7.5 seconds on average for tests to stop running after killing your test (in practice we have observed roughly 20 seconds lag between killing a function and termination of invocations). ### Create customized `script.yml` Above you used how to use `slsart script` to create the default `script.yml` (see [here](#2-create-scriptyml)) and how to customize it by manually editing it (see [here](#4-customizing-scriptyml)). `slsart script` command has options to quickly do the above in one command. Run the following command to create custom `script.yml` with **one** load `phase`. ``` slsart script -e <your-target-endpoint> -d <duration-in-sec> -r <arrival-rate-in-virtual-users-arriving-per-second> -t <ramp-to-in-virtual-users-arriving-per-second> ``` For example, following command will create a `script.yml` with test target https://example.com, performance test starting with 10 requests per second, and scaling up to 25 requests per second, over a duration of 60 seconds. ``` slsart script -e https://example.com -d 60 -r 10 -t 25 ``` For more details see ``` slsart script --help ``` ### Performance test using script file with different name/path The `slsart script` command by default gives the file name `script.yml`. If you want to give a different name to your `yml` file then you can use the `-o` option of the `slsart script` command. See`slsart script --help` for more details. ``` slsart script -o <preferred-filename.yml> ``` Example, ``` slsart script -o myservicetests.yml ``` By default `slsart invoke` command will look for `script.yml` under the local folder to run performance test. You can use `-p` option to specify script file with different name/path as follows. ``` slsart invoke -p <path-to-your-script-file> ``` For example, following command will *invoke* performance test using the specified file. ``` slsart invoke -p /my/path/to/myotherscript.yml ``` For more options see, ``` slsart invoke --help ``` ### Reserved and unsupported flags `slsart` commands support most commandline flags of the corresponding `sls` (Serverless Framework) commands. #### Reserved flags Following flags are reserved in `slsart invoke` command. - The flags `-t`, `--type`, `-f`, and `--function` are reserved for `serverless-artillery` use. They cannot be supplied on the command line. - The `-t` and `--type` flags are reserved because the tool uses the script you provide it to cacluate whether an `Event` or `RequestResponse` invocation type is more appropriate. If that argument was supplied, a user mig