Progressive Web Apps  

Performance Benchmarking and Stress Testing Web Applications using K6 and Apache JMeter

Introduction

In any enterprise-grade web application, ensuring performance under real-world traffic conditions is as important as developing the core functionality. Performance degradation under heavy load can lead to poor user experience, lost customers, and even downtime during critical business operations.

This article focuses on Performance Benchmarking and Stress Testing using two of the most widely adopted tools K6 and Apache JMeter.
We’ll explore how to set up these tools, run effective load and stress tests, interpret results, and integrate testing into a CI/CD pipeline for ASP.NET Core and Angular applications.

What is Performance Testing?

Performance testing is the process of evaluating how a system behaves under varying workloads. It identifies bottlenecks, scalability issues, and performance thresholds before an application goes live.

Common Types of Performance Tests

TypePurposeExample
Load TestingMeasures system performance under expected load1000 concurrent users logging in
Stress TestingEvaluates system stability beyond normal loadGradually increase users until failure
Spike TestingTests reaction to sudden traffic increaseFlash sale or sudden API surge
Endurance TestingChecks performance over an extended periodApp stability for 24-hour uptime
Scalability TestingDetermines how performance scales with resourcesIncreasing CPU/memory instances

Why K6 and JMeter?

Both K6 and JMeter are open-source, developer-friendly tools for load testing web apps and APIs.

FeatureK6Apache JMeter
LanguageJavaScriptJava
Ease of SetupLightweight CLI toolGUI + CLI
ScriptingJS-basedXML Test Plans
IntegrationGreat with CI/CDExtensive plugin ecosystem
ReportingBuilt-in metrics and Grafana dashboardsCSV, HTML, or custom reports

Technical Workflow

Performance Testing Lifecycle:

[Define Performance Goals]
          ↓
[Design Test Scenarios]
          ↓
[Configure K6 / JMeter]
          ↓
[Execute Load and Stress Tests]
          ↓
[Analyze Results & Identify Bottlenecks]
          ↓
[Optimize Code, Queries, or Infrastructure]
          ↓
[Re-Test and Validate Performance]

Setting Up K6 for Benchmarking

K6 is a modern, scriptable load testing tool built with performance and automation in mind. It allows developers to write tests in JavaScript and easily integrate with DevOps pipelines.

Step 1: Install K6

For Windows

choco install k6

For Linux/Mac

brew install k6

Step 2: Create a Test Script

Create a file named load_test.js

import http from 'k6/http';
import { sleep, check } from 'k6';

export let options = {
  stages: [
    { duration: '1m', target: 50 },   // ramp-up to 50 users
    { duration: '3m', target: 50 },   // stay at 50 users
    { duration: '1m', target: 0 }     // ramp-down
  ]
};

export default function () {
  let response = http.get('https://myapi.example.com/api/products');
  
  check(response, {
    'status is 200': (r) => r.status === 200,
    'response time < 500ms': (r) => r.timings.duration < 500
  });
  
  sleep(1);
}

Step 3: Run the Test

k6 run load_test.js

Step 4: Analyze Output

K6 provides metrics like:

  • Requests per second (RPS)

  • Response time percentiles (p(95), p(99))

  • Error rate

  • Throughput and latency

You can also integrate with Grafana + Prometheus for live visualization.

Setting Up Apache JMeter

JMeter has been a long-time favorite for load testing web and enterprise APIs, offering a graphical interface and detailed reporting.

Step 1: Install JMeter

Download from: https://jmeter.apache.org/download_jmeter.cgi

Extract and run:

./bin/jmeter.sh

or on Windows:

jmeter.bat

Step 2: Create a Test Plan

  1. Open JMeter GUI

  2. Add Thread Group → define number of users, ramp-up, and loop count

  3. Add HTTP Request Sampler → specify the API endpoint

  4. Add View Results in Table or Summary Report listeners

  5. Save the plan as api_test_plan.jmx

Step 3: Run the Test

From GUI, click Start, or run in command-line mode:

jmeter -n -t api_test_plan.jmx -l results.jtl -e -o ./report

Step 4: Analyze Results

The JMeter HTML report includes:

  • Response time distribution

  • Throughput (transactions/sec)

  • Error % per request

  • Active thread count

  • Server resource utilization

ASP.NET Core API Benchmark Example

Let’s take an example of a simple ASP.NET Core Web API:

[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
    private static readonly List<string> Products = 
        Enumerable.Range(1, 100).Select(i => $"Product {i}").ToList();

    [HttpGet]
    public IActionResult Get() => Ok(Products);
}

Run the above API locally and use either K6 or JMeter to simulate 500+ users calling /api/products concurrently.

After execution, you’ll observe:

  • Average response times

  • Peak latency

  • Server CPU/memory usage under load

This helps identify if you need to optimize:

  • Database queries (e.g., indexing or caching)

  • Middleware configurations

  • Thread pool and Kestrel settings

  • API compression or response caching

Integration with CI/CD Pipelines

K6 Integration Example (Jenkins or GitHub Actions):

name: Load Test

on:push:
    branches: [ main ]

jobs:load-test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Install K6
        run: sudo apt install -y k6
      - name: Run Load Test
        run: k6 run load_test.js

This ensures every deployment is automatically validated for performance before going live.

JMeter Integration Example (Jenkins):

Add a Jenkins stage:

stage('Performance Test') {
  steps {
    sh 'jmeter -n -t tests/api_test_plan.jmx -l results.jtl -e -o reports/'
  }
}

Benchmarking Metrics to Track

MetricDescriptionIdeal Range
Average Response TimeTime taken per request< 500ms
Throughput (RPS)Number of successful requests/secHigher is better
Error Rate% of failed requests< 1%
CPU/Memory UsageServer resource utilization< 70%
p(95) Latency95th percentile response timeConsistent performance

Optimizing Based on Results

After identifying bottlenecks:

  • Use Response Caching and MemoryCache in ASP.NET Core

  • Optimize EF Core queries and add database indexes

  • Introduce Redis caching for frequently accessed data

  • Implement CDN caching for static Angular assets

  • Enable HTTP/2 and GZip compression in the server configuration

Example optimization in Program.cs:

builder.Services.AddResponseCaching();

app.UseResponseCaching();

app.Use(async (context, next) =>
{
    context.Response.GetTypedHeaders().CacheControl =
        new Microsoft.Net.Http.Headers.CacheControlHeaderValue()
        {
            Public = true,
            MaxAge = TimeSpan.FromSeconds(60)
        };
    await next();
});

Best Practices

  1. Always test in an environment similar to production.

  2. Use realistic user behavior (think-time, varied endpoints).

  3. Gradually increase load to identify thresholds.

  4. Test with both authenticated and anonymous users.

  5. Include database and external API latency in analysis.

  6. Run regular tests after feature changes or infrastructure updates.

Conclusion

Performance benchmarking and stress testing are not optional — they are an integral part of software quality assurance.

By using K6 for scriptable, developer-friendly load testing and JMeter for GUI-based comprehensive tests, developers can validate the resilience and scalability of both ASP.NET Core backends and Angular frontends under real-world conditions.

When integrated into your CI/CD pipeline, these tools ensure that performance regressions are caught early resulting in faster, more reliable, and enterprise-ready web applications.