Performance TestingIntermediate

Performance Testing Fundamentals

Master the basics of performance testing including load testing, stress testing, and performance optimization

6 min read
...
performanceload-testingoptimizationmonitoring

Introduction

Performance testing ensures your application can handle expected user loads while maintaining acceptable response times. This guide covers fundamental concepts and practical approaches.

Types of Performance Testing

Load Testing

Tests system behavior under expected load conditions.

// Using k6 for load testing
import http from 'k6/http';
import { check, sleep } from 'k6';
 
export const options = {
  vus: 100, // 100 virtual users
  duration: '5m', // 5 minutes
  thresholds: {
    http_req_duration: ['p(95)<500'], // 95% of requests < 500ms
    http_req_failed: ['rate<0.01'], // Error rate < 1%
  },
};
 
export default function () {
  const res = http.get('https://api.example.com/users');
  check(res, {
    'status is 200': (r) => r.status === 200,
    'response time < 500ms': (r) => r.timings.duration < 500,
  });
  sleep(1);
}

Stress Testing

Tests system limits by gradually increasing load beyond normal capacity.

export const options = {
  stages: [
    { duration: '2m', target: 100 }, // Ramp up to 100 users
    { duration: '5m', target: 100 }, // Stay at 100 users
    { duration: '2m', target: 200 }, // Ramp up to 200 users
    { duration: '5m', target: 200 }, // Stay at 200 users
    { duration: '2m', target: 300 }, // Push to 300 users
    { duration: '5m', target: 300 }, // Stay at 300 users
    { duration: '2m', target: 0 },   // Ramp down
  ],
};

Spike Testing

Tests system response to sudden traffic spikes.

export const options = {
  stages: [
    { duration: '10s', target: 100 }, // Normal load
    { duration: '1m', target: 5000 }, // Sudden spike
    { duration: '3m', target: 5000 }, // Maintain spike
    { duration: '10s', target: 100 }, // Return to normal
  ],
};

Key Performance Metrics

Response Time Metrics

// Monitor various response time percentiles
export const options = {
  thresholds: {
    'http_req_duration': [
      'p(50)<200',   // 50th percentile < 200ms
      'p(95)<500',   // 95th percentile < 500ms
      'p(99)<1000',  // 99th percentile < 1s
    ],
  },
};

Throughput

Requests per second (RPS) your system can handle:

import { Rate } from 'k6/metrics';
 
const successRate = new Rate('successful_requests');
 
export default function() {
  const res = http.get('https://api.example.com/products');
  successRate.add(res.status === 200);
}

Error Rate

Percentage of failed requests:

export const options = {
  thresholds: {
    'http_req_failed': ['rate<0.01'], // Less than 1% errors
  },
};

Database Performance

Identify Slow Queries

-- PostgreSQL: Find slow queries
SELECT 
  query,
  calls,
  total_time,
  mean_time,
  max_time
FROM pg_stat_statements
ORDER BY mean_time DESC
LIMIT 10;

Add Indexes

-- Before: Slow query
SELECT * FROM users WHERE email = 'user@example.com';
-- Execution time: 150ms
 
-- Add index
CREATE INDEX idx_users_email ON users(email);
 
-- After: Fast query
SELECT * FROM users WHERE email = 'user@example.com';
-- Execution time: 2ms

Use Connection Pooling

// With connection pooling
import { Pool } from 'pg';
 
const pool = new Pool({
  max: 20, // Maximum connections
  idleTimeoutMillis: 30000,
  connectionTimeoutMillis: 2000,
});
 
async function getUser(id) {
  const client = await pool.connect();
  try {
    const result = await client.query('SELECT * FROM users WHERE id = $1', [id]);
    return result.rows[0];
  } finally {
    client.release();
  }
}

API Performance Optimization

Implement Caching

import Redis from 'ioredis';
 
const redis = new Redis();
 
async function getProduct(id) {
  // Try cache first
  const cached = await redis.get(`product:${id}`);
  if (cached) {
    return JSON.parse(cached);
  }
 
  // Fetch from database
  const product = await db.products.findById(id);
 
  // Cache for 1 hour
  await redis.setex(`product:${id}`, 3600, JSON.stringify(product));
 
  return product;
}

Use Compression

import express from 'express';
import compression from 'compression';
 
const app = express();
 
// Enable gzip compression
app.use(compression());
 
// Response size reduced from 500KB to 50KB
app.get('/api/data', (req, res) => {
  res.json(largeDataset);
});

Implement Pagination

// Bad: Return all results
app.get('/api/users', async (req, res) => {
  const users = await db.users.findAll(); // Could be 100k+ records
  res.json(users);
});
 
// Good: Paginate results
app.get('/api/users', async (req, res) => {
  const page = parseInt(req.query.page) || 1;
  const limit = parseInt(req.query.limit) || 20;
  const offset = (page - 1) * limit;
 
  const users = await db.users.findAll({
    limit,
    offset,
  });
 
  const total = await db.users.count();
 
  res.json({
    data: users,
    pagination: {
      page,
      limit,
      total,
      pages: Math.ceil(total / limit),
    },
  });
});

Frontend Performance

Optimize Bundle Size

// webpack.config.js
module.exports = {
  optimization: {
    splitChunks: {
      chunks: 'all',
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          chunks: 'all',
        },
      },
    },
  },
};

Lazy Loading

// React lazy loading
import { lazy, Suspense } from 'react';
 
const HeavyComponent = lazy(() => import('./HeavyComponent'));
 
function App() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <HeavyComponent />
    </Suspense>
  );
}

Image Optimization

// Next.js Image component (automatic optimization)
import Image from 'next/image';
 
function ProductImage({ src, alt }) {
  return (
    <Image
      src={src}
      alt={alt}
      width={800}
      height={600}
      loading="lazy"
      quality={85}
    />
  );
}

Monitoring and Alerting

Application Performance Monitoring

// Using New Relic
import newrelic from 'newrelic';
 
app.get('/api/checkout', async (req, res) => {
  const transaction = newrelic.getTransaction();
  transaction.setAttribute('user_id', req.user.id);
 
  try {
    const result = await processCheckout(req.body);
    res.json(result);
  } catch (error) {
    newrelic.noticeError(error);
    res.status(500).json({ error: error.message });
  }
});

Set Up Alerts

# Example: Prometheus alert rules
groups:
  - name: api_performance
    rules:
      - alert: HighResponseTime
        expr: http_request_duration_seconds{quantile="0.95"} > 1
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "High API response time"
 
      - alert: HighErrorRate
        expr: rate(http_requests_total{status=~"5.."}[5m]) > 0.05
        for: 2m
        labels:
          severity: critical
        annotations:
          summary: "High error rate detected"

Best Practices

  1. Set Performance Budgets: Define acceptable limits before building
  2. Test Early: Performance test during development, not just before release
  3. Monitor Production: Use APM tools to catch real-world issues
  4. Optimize Database: Proper indexes and query optimization
  5. Use CDN: Serve static assets from CDN for faster delivery
  6. Cache Wisely: Cache at multiple levels (browser, CDN, application, database)
  7. Regular Testing: Run performance tests as part of CI/CD

Common Performance Bottlenecks

  1. N+1 Queries: Fetch related data in single query
  2. Large Payloads: Implement pagination and filtering
  3. Synchronous Operations: Use async/await and job queues
  4. Memory Leaks: Profile and fix memory issues
  5. Unoptimized Images: Compress and properly size images
  6. Too Many Dependencies: Audit and remove unused packages

Conclusion

Effective performance testing requires:

  • Understanding different test types
  • Monitoring key metrics
  • Optimizing at all layers (DB, API, Frontend)
  • Continuous monitoring
  • Regular performance testing in CI/CD

Start with realistic goals, measure everything, and optimize based on data.

Tools to Explore

  • Load Testing: k6, JMeter, Gatling
  • APM: New Relic, Datadog, Dynatrace
  • Profiling: Chrome DevTools, Node.js Profiler
  • Database: pgAdmin, MySQL Workbench

Comments (0)

Loading comments...