Tutorial: Run a load test to identify performance bottlenecks in a web app

In this tutorial, you'll learn how to identify performance bottlenecks in a web application by using Azure Load Testing Preview. You'll create a load test for a sample Node.js application.

The sample application consists of a Node.js web API, which interacts with a NoSQL database. You'll deploy the web API to Azure App Service web apps and use Cosmos DB as the database.

In this tutorial, you'll learn how to:

  • Deploy the sample app.
  • Create and run a load test.
  • Identify performance bottlenecks in the app.
  • Remove the bottleneck.
  • Re-run the load test to check performance improvements.

Important

Azure Load Testing is currently in PREVIEW. See the Supplemental Terms of Use for Microsoft Azure Previews for legal terms that apply to Azure features that are in beta, preview, or otherwise not yet released into general availability.

Prerequisites

  • An Azure account with an active subscription. If you don't have an Azure subscription, create a free account before you begin.
  • This tutorial requires that you run the Azure CLI locally. You must have the Azure CLI version 2.2.0 or later installed. Run az --version to find the version. If you need to install or upgrade the CLI, see How to install the Azure CLI.
  • Download and install VS Code.
  • Download and install Git

Deploy the sample app

Before you can load test the sample app, you have to get it up and running. Use Azure CLI commands, Git commands, and PowerShell commands to make that happen.

  1. Open Windows PowerShell, sign in to Azure, and set the subscription:

    az login
    az account set --subscription <your-Azure-Subscription-ID>
    
  2. Clone the sample application's source repo.

     git clone https://github.com/Azure-Samples/nodejs-appsvc-cosmosdb-bottleneck.git
    

    The sample application is a Node.js app consisting of an Azure App Service web component and a Cosmos DB database. The repo includes a PowerShell script that deploys the sample app to your Azure subscription. It also has an Apache JMeter script that you'll use in later steps.

  3. Go to the Node.js app's directory and deploy the sample app using the PowerShell script.

     cd nodejs-appsvc-cosmosdb-bottleneck
     .\deploymentscript.ps1
    

    Tip

    You can install PowerShell Core on Linux/WSL or macOS.

    After installing it, you can run the previous command as pwsh ./deploymentscript.ps1.

  4. At the prompt, provide:

    • Your Azure subscription ID.
    • A unique name for your web app.
    • A location. By default, the location is eastus. You can obtain region codes by running the Get-AzLocation command.

    Important

    For your webapp name, use only lowercase letters and numbers. No spaces. No special characters.

  5. Once deployment finishes, go to the running sample application by opening https://<yourappname>.azurewebsites.net in a browser window.

  6. To see the application's components, sign in to the Azure portal and go to the resource group you created.

    Screenshot that shows the list of Azure Resource Groups.

Now that you have the application deployed and running, go ahead and get started with running your first load test against it.

Configure and create the load test

In this section, you'll create a load test by using an existing Apache JMeter test script.

Configure the Apache JMeter script

The sample application's source repo includes an Apache JMeter script named SampleApp.jmx. This script carries out three API calls on each test iteration:

  • add - Carries out a data insert operation on Cosmos DB for the number of visitors on the webapp.
  • get - Carries out a GET operation from Cosmos DB to retrieve the count.
  • lasttimestamp - Updates the timestamp since the last user went to the website.

In this section, you'll update the Apache JMeter script with the URL of the sample web app you deployed in the previous section.

Before you start, make sure you have the directory of the cloned sample app open in VS Code.

  1. Open the directory of the cloned sample app in VS Code.

    cd nodejs-appsvc-cosmosdb-bottleneck
    code .
    
  2. Open SampleApp.jmx.

  3. Search for <stringProp name="HTTPSampler.domain">.

    You'll see three instances of <stringProp name="HTTPSampler.domain"> in the file.

  4. Replace the value with the URL of the newly deployed sample application in all three instances.

    <stringProp name="HTTPSampler.domain">yourappname.azurewebsites.net</stringProp>
    

    Update the value in all three places. Don't include the https:// prefix.

  5. Save your changes and close the file.

Create the Azure Load Testing resource

The Load Testing resource is a top-level resource for your load testing activities. This resource provides a centralized place to view and manage load tests, test results, and other related artifacts.

If you already have a Load Testing resource, skip this section and continue to Create a load test.

If you don't yet have a Load Testing resource, create one now:

  1. Sign in to the Azure portal by using the credentials for your Azure subscription.

  2. Select the menu button in the upper-left corner of the portal, and then select + Create a resource.

    Screenshot showing + Create a resource.

  3. Use the search bar to find Azure Load Testing.

  4. Select Azure Load Testing.

  5. In the Azure Load Testing pane, select Create.

    Screenshot that shows the Azure Load Testing creation page.

  6. Provide the following information to configure your new Azure Load Testing resource.

    Field Description
    Subscription Select the Azure subscription you want to use for this Azure Load Testing resource.
    Resource Group Select an existing resource group, or select Create new, and then enter a unique name for the new resource group.
    Name Enter a unique name to identify your Azure Load Testing resource.
    The name can't contain special characters, such as \/""[]:|<>+=;,?*@&, or whitespace. The name can't begin with '_', or end with '.' or '-'. The length must be between 1 and 64 characters.
    Location Select a geographic location to host your Azure Load Testing resource.

    Screenshot that shows the Basics tabs when creating an Azure Load Testing resource.

    Note

    Optionally, you can configure more details in the Tags tab. Tags are name/value pairs that enable you to categorize resources and view consolidated billing by applying the same tag to multiple resources and resource groups.

  7. After you're finished configuring the resource, select Review + Create.

  8. Review all the configuration settings and select Create to start the deployment of the Azure Load Testing resource.

    When the process has finished, a deployment success message appears.

  9. To view the new resource, select Go to resource.

    Screenshot that shows the deployment completion screen.

  10. In the Azure Load Testing resource page, select Access Control (IAM), and then select Add role assignment.

    Before you can manage load tests in the Azure Load Testing resource, you need to have the right access permissions.

    Screenshot that shows how to configure access control.

    You need to assign the Load Test Contributor or Load Test Owner role to your Azure account. For details about how to assign roles, see Assign Azure roles using the Azure portal.

    Screenshot that shows the role assignment screen.

    Important

    To assign Azure roles, you must have Microsoft.Authorization/roleAssignments/write permissions, such as User Access Administrator or Owner. The role assignments might take a few minutes to become active for your account. Refresh the web page for the user interface to reflect the updated permissions.

In the next section, you'll create a load test in the Load Testing resource for the sample app.

Create a load test

  1. Navigate to the load test resource and select Create new test in the command bar.

    Screenshot that shows Create new test.

  2. In the Basics tab, enter the Test name and Test description information. Optionally, you can check the Run test after creation box to automatically start the load test after creating it.

    Screenshot that shows the basics tab when creating a new test.

  3. In the Test plan tab, select the JMeter script test method, and then select the SampleApp.jmx test script from the cloned sample application directory. Next, select Upload to upload the file to Azure and configure the load test.

    Screenshot that shows the Test plan tab and how to upload an Apache JMeter script.

    Optionally, you can select and upload additional Apache JMeter configuration files.

  4. In the Load tab, configure the following details. You can leave the default values for this tutorial:

    Setting Value Description
    Engine instances 1 The number of parallel test engines that execute the Apache JMeter script.

    Screenshot that shows the Load tab when creating a new test.

  5. In the Monitoring tab, specify the application components you want to monitor the resource metrics. Select Add/modify to manage the list of application components.

    Screenshot that shows the Monitoring tab when creating a new test.

    Screenshot that shows how to add Azure resources to monitor during the load test.

    Screenshot that shows the Monitoring tab with the list of Azure resources to monitor.

  6. Select Review + create, review all settings, and select Create.

    Screenshot that shows the Review + create tab when creating a new test.

Run the load test in the Azure portal

In this section, you'll use the Azure portal to manually start the load test you created previously. If you checked the Run test after creation box, the test will already be running.

  1. Select Tests to view the list of tests, and then select the test you created previously.

    Screenshot that shows the list of tests.

    Tip

    You can use the search box and the Time range filter to limit the number of tests.

  2. In the test runs page, select Run or Run test.

    Screenshot that shows how to run a test.

  3. Select Run on the run summary page to start the load test. You'll then see the list of test runs.

    Screenshot that shows the run summary page.

    Azure Load Testing begins to monitor and display the application's server metrics in the dashboard.

    You can see the streaming client-side metrics while the test is running. By default, the results refresh automatically every five seconds.

    Screenshot that shows the test results dashboard.

    You can apply multiple filters or aggregate the results to different percentiles to customize the charts.

    Tip

    You can stop a load test at any time from the Azure portal UI by selecting Stop.

Wait until the load test finishes fully before proceeding to the next section.

Identify performance bottlenecks

In this section, you'll analyze the load test results to identify performance bottlenecks in the application. Examine both the client-side and server-side metrics to determine the root cause of the problem.

  1. First, take a look at the client-side metrics. You'll notice that the 90th percentile for the Response time metric for the add and get API requests are higher than for the lasttimestamp API.

    Screenshot that shows the client-side metrics.

    You can see a similar pattern for Errors, where the lasttimestamp API has fewer errors than the other APIs.

    Screenshot that shows the errors chart.

    The results of the add and get APIs are similar, whereas the lasttimestamp API behaves differently. The cause might be database-related, because both the add and get APIs involve a database access.

  2. To investigate this issue in more detail, scroll down to the Server-side metrics dashboard section.

    The server-side metrics show you detailed information about your Azure application components: Azure App Service Plan, Azure App Service Web App, and Azure Cosmos DB.

    Screenshot that shows the Azure App Service Plan metrics.

    In the Azure App Service Plan metrics, you can see that the CPU Percentage and Memory Percentage metrics are within an acceptable range.

  3. Now, take a look at the Cosmos DB server-side metrics.

    Screenshot that shows Azure Cosmos DB metrics.

    You'll notice that the Normalized RU Consumption metric shows that the database was quickly running at 100% resource utilization. The high resource usage might have caused database throttling errors, and increased response times for the add and get web APIs.

    You can also see that the Provisioned Throughput metric for the Azure Cosmos DB instance has a maximum throughput of 400 RUs. By increasing the provisioned throughput of the database, the performance issue might be resolved.

In the next section, you'll increase the database provisioned throughput, and then verify if the application performance bottleneck has been resolved.

Increase the database throughput

In this section, you'll allocate more resources to the database, to resolve the performance bottleneck.

For Azure Cosmos DB, you'll increase the database RU scale setting.

  1. Go to the Cosmos DB resource that you provisioned as part of the sample application deployment.

  2. Select the Data Explorer tab.

    Screenshot that shows Cosmos DB scale settings.

  3. Select the Scale & Settings option, and update the throughput value to 1200.

    Screenshot that shows the updated Cosmos DB scale settings.

  4. Select Save to confirm the changes.

Validate the performance improvements

Now that you've increased the database throughput, you'll rerun the load test and verify that the performance results have improved.

  1. Return to the test run details page, select Rerun, and then select Run in the run summary page.

    Screenshot that shows how to run the load test.

    You'll see a new test run entry with the status column that cycles through the Provisioning, Executing, and Done state. At any time, select the test run item to monitor how the load test is progressing.

  2. Once the load test finishes, check the Response time and the Errors of the client-side metrics.

  3. Then check the server-side metrics for Azure Cosmos DB and ensure that the performance has improved.

    Screenshot that shows the Cosmos DB client-side metrics after the scale settings update.

    You'll notice that the Cosmos DB Normalized RU Consumption is now well below 100%.

After changing the scale settings of the database, you now see that:

  • The response time for the add and get APIs has improved.
  • The normalized RU consumption remains well under the maximum limit.

As a result, the overall performance of your application was improved.

Clean up resources

Important

You can reuse the Azure Load Testing resource that you created for other Azure Load Testing tutorials and how-to articles.

If you don't plan to use any of the resources that you created, delete them so you don't incur any further charges. If you've deployed the sample application in a different resource group, you might want to repeat the following steps.

  • In the Azure portal:

    1. Select the menu button in the upper-left corner, then select Resource groups.

    2. From the list, select the resource group that you created.

    3. Select Delete resource group.

      Screenshot of the selections to delete a resource group in the Azure portal.

    4. Enter the resource group name. Then select Delete.

  • Alternately, you can use the Azure CLI.

    az group delete --name <yourresourcegroup>
    

    Remember, deleting the resource group deletes all of the resources within it.

Next steps

Advance to the next tutorial to learn how to set up an automated regression testing workflow by using Azure Pipelines or GitHub Actions.