techprotrade's picture
Deploy ATOM FastAPI command center runtime (part 8)
aef804e verified
|
Raw
History Blame Contribute Delete
11.8 kB
# Load Testing with k6
This directory contains k6 load tests for validating Atom API performance under concurrent user load.
## Overview
Load testing simulates multiple concurrent users interacting with the API to identify performance bottlenecks, establish capacity limits, and validate that performance benchmarks hold under load.
**Why k6?**
- Modern, developer-friendly load testing tool
- JavaScript-based test scripts (easy to extend)
- Great CI/CD integration
- Built-in metrics and thresholds
- Cloud-based execution available (k6 Cloud)
**Why Add k6 Alongside Locust?**
- **k6**: Better for CI/CD automation, simpler syntax, built-in thresholds
- **Locust**: Better for interactive testing, web UI, distributed load testing
## Prerequisites
### 1. Install k6
**macOS (Homebrew):**
```bash
brew install k6
```
**Linux:**
```bash
curl https://github.com/grafana/k6/releases/download/v0.51.0/k6-v0.51.0-linux-amd64.tar.gz -L | tar xvz
sudo mv k6-v0.51.0-linux-amd64/k6 /usr/local/bin/
```
**Windows:**
```bash
chocolatey install k6
```
**Verify installation:**
```bash
k6 version
```
### 2. Start Application
Ensure the Atom backend is running:
```bash
cd backend
python -m uvicorn main:app --host 0.0.0.0 --port 8000
```
### 3. Create Test User (Optional)
Load tests use `load_test@example.com` with password `test_password_123`. Create this user via:
```bash
curl -X POST http://localhost:8000/api/auth/register \
-H "Content-Type: application/json" \
-d '{"email": "load_test@example.com", "password": "test_password_123"}'
```
## Running Tests
### Quick Test (Development)
Run a quick test for fast feedback:
```bash
cd backend/tests/load
k6 run test_api_load_baseline.js --duration 30s --vus 5
```
### Full Baseline Test (10 Users)
Establish baseline performance:
```bash
cd backend/tests/load
k6 run test_api_load_baseline.js
```
**Duration:** 6 minutes (2m ramp-up, 3m sustained, 1m ramp-down)
**Users:** 10 concurrent
**Thresholds:** p(95)<500ms, error rate <5%
### Moderate Load Test (50 Users)
Test under moderate concurrent load:
```bash
cd backend/tests/load
k6 run test_api_load_moderate.js
```
**Duration:** 17 minutes (5m ramp-up, 10m sustained, 2m ramp-down)
**Users:** 50 concurrent
**Thresholds:** p(95)<800ms, error rate <10%
### High Load Test (100 Users)
Test under high concurrent load:
```bash
cd backend/tests/load
k6 run test_api_load_high.js
```
**Duration:** 28 minutes (10m ramp-up, 15m sustained, 3m ramp-down)
**Users:** 100 concurrent
**Thresholds:** p(95)<1200ms, error rate <15%
### Web UI Load Test (20 Users)
Test realistic web UI user flows:
```bash
cd backend/tests/load
k6 run test_web_ui_load.js
```
**Duration:** 9 minutes (3m ramp-up, 5m sustained, 1m ramp-down)
**Users:** 20 concurrent
**Thresholds:** p(95)<1000ms, error rate <10%
## Environment Variables
Configure the API URL:
```bash
# Default: http://localhost:8000
export API_URL="http://localhost:8000"
# Run with custom API URL
API_URL="http://staging.example.com" k6 run test_api_load_baseline.js
```
## Interpreting Results
### Key Metrics
**Requests Per Second (RPS):**
- Measure of throughput
- Higher is better (indicates capacity)
- Target: Maintain RPS as user count increases
**Response Time Percentiles:**
- **P50 (Median)**: 50% of requests complete faster than this
- **P95**: 95% of requests complete faster than this (SLA target)
- **P99**: 99% of requests complete faster than this (tail latency)
**Failure Rate:**
- Percentage of failed requests (non-2xx status codes)
- Target: <5% for baseline, <15% for high load
- Common failures: 500 (server error), 503 (service unavailable)
**Checks:**
- Custom validation checks (e.g., "login successful", "agent execution started")
- Pass rate indicates percentage of checks that passed
- Target: >90% for baseline, >85% for high load
### Example Output
```
Baseline Load Test Summary
========================
Total Requests: 1234
Failed Requests: 45
Failure Rate: 3.65%
Response Times:
P50: 180ms
P95: 420ms
P99: 780ms
Checks:
Passed: 1150
Failed: 84
Pass Rate: 93.19%
running (06.0s), 000/10 VUs, 1234 complete and 0 interrupted iterations
✓ /api/auth/login [ 96% ]
✓ has status 200
✓ received token
✓ /api/v1/agents/execute [ 91% ]
✓ agent execution started
```
### Performance Indicators
**Good Performance:**
- P95 response time meets thresholds
- Failure rate below target
- RPS scales linearly with user count
- No response time spikes as user count increases
**Performance Issues:**
- P95 response time increases with user count (bottleneck)
- Failure rate exceeds target (capacity limit)
- RPS plateaus or decreases (system overload)
- Response time spikes during test (resource exhaustion)
## CI/CD Integration
### GitHub Actions Workflow
```yaml
name: Load Tests (k6)
on:
schedule:
# Run daily at 2 AM UTC
- cron: '0 2 * * *'
pull_request:
paths:
- 'backend/core/**'
- 'backend/api/**'
jobs:
load-test:
name: Run Load Tests
runs-on: ubuntu-large
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install k6
run: |
curl https://github.com/grafana/k6/releases/download/v0.51.0/k6-v0.51.0-linux-amd64.tar.gz -L | tar xvz
sudo mv k6-v0.51.0-linux-amd64/k6 /usr/local/bin/
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install dependencies
run: |
cd backend
pip install -r requirements.txt
- name: Start application
run: |
cd backend
python -m uvicorn main:app --host 0.0.0.0 --port 8000 &
sleep 10
- name: Run baseline load test
run: |
cd backend/tests/load
k6 run test_api_load_baseline.js --duration 2m --vus 10
- name: Upload load test results
uses: actions/upload-artifact@v4
if: always()
with:
name: k6-load-test-results
path: backend/tests/load/reports/
```
### Quick Smoke Test for CI
For faster CI feedback, run a 1-minute smoke test:
```bash
k6 run test_api_load_baseline.js --duration 1m --vus 5
```
## Test Scenarios
### test_api_load_baseline.js (10 Users)
**Scenarios:**
- 60% Authentication flow (login)
- 40% Agent execution (list + execute)
**Purpose:** Establish baseline performance metrics
### test_api_load_moderate.js (50 Users)
**Scenarios:**
- 50% Authentication (login, logout)
- 30% Agent execution (GET agents, POST execute)
- 20% Canvas operations (GET canvas, POST present)
**Purpose:** Validate system performance under moderate load
### test_api_load_high.js (100 Users)
**Scenarios:**
- 40% Authentication
- 35% Agent execution
- 15% Canvas operations
- 10% Workflow execution
**Purpose:** Identify system breaking point and capacity limits
### test_web_ui_load.js (20 Users)
**User Flow:**
1. GET / (load homepage)
2. POST /api/auth/login (authenticate)
3. GET /dashboard (load dashboard)
4. GET /api/v1/agents (list agents)
5. POST /api/v1/agents/execute (execute agent)
6. GET /api/v1/canvas/{id} (view canvas)
7. POST /api/v1/canvas/present (present canvas)
8. GET /api/v1/workflows (list workflows, optional)
9. POST /api/auth/logout (logout, optional)
**Purpose:** Simulate realistic web UI user behavior
## Troubleshooting
### k6 Not Found
**Symptom:** `k6: command not found`
**Solution:**
```bash
# macOS
brew install k6
# Linux
curl https://github.com/grafana/k6/releases/download/v0.51.0/k6-v0.51.0-linux-amd64.tar.gz -L | tar xvz
sudo mv k6-v0.51.0-linux-amd64/k6 /usr/local/bin/
```
### Server Not Running
**Symptom:** Connection refused errors
**Solution:**
```bash
# Check if server is running
curl http://localhost:8000/health/live
# Start server if not running
cd backend
python -m uvicorn main:app --host 0.0.0.0 --port 8000
```
### Authentication Failures
**Symptom:** 401 Unauthorized errors
**Solution:**
- Load tests use `load_test@example.com` with password `test_password_123`
- Ensure test user exists in database
- Check authentication endpoint is working:
```bash
curl -X POST http://localhost:8000/api/auth/login \
-H "Content-Type: application/json" \
-d '{"email": "load_test@example.com", "password": "test_password_123"}'
```
### High Failure Rate
**Symptom:** >15% failure rate with 500 errors
**Possible Causes:**
1. **Database overload**: Reduce concurrent users, increase pool size
2. **Memory pressure**: Check server memory usage, reduce user count
3. **Rate limiting**: Check if API has rate limits configured
4. **External service failures**: Check LLM provider, external APIs
**Debugging:**
```bash
# Check server logs
tail -f logs/atom.log | grep ERROR
# Monitor server resources
htop # or top on macOS
# Check database connections
# For PostgreSQL:
psql -c "SELECT count(*) FROM pg_stat_activity;"
```
### Slow Response Times
**Symptom:** P95 > 2x target thresholds
**Possible Causes:**
1. **Cache misses**: Cold cache, low hit rate
2. **Database queries**: Missing indexes, N+1 queries
3. **Network latency**: Local vs remote database
4. **Resource contention**: CPU, memory, disk I/O
**Debugging:**
```bash
# Check cache hit rate
curl http://localhost:8000/api/agent-governance/cache-stats
# Profile database queries
# Enable query logging in SQLAlchemy
export SQLALCHEMY_ECHO=true
# Run with profiling
python -m cProfile -o profile.stats -m uvicorn main:app
```
## Best Practices
1. **Warm up the cache**: Run for 1-2 minutes before collecting metrics
2. **Start small**: Begin with 10 users, scale up gradually
3. **Monitor resources**: Watch CPU, memory, database connections during test
4. **Use realistic data**: Test with production-like data volumes
5. **Run multiple times**: Performance can vary due to system load
6. **Compare to baseline**: Track performance over time to detect regressions
7. **Test in staging**: Never run load tests in production without limits
8. **Automate in CI**: Run smoke tests on every PR, full tests nightly
## Next Steps
After running load tests:
1. Review HTML report for detailed metrics (if using Locust)
2. Compare P95 times to target thresholds
3. Identify bottlenecks (database, cache, network)
4. Optimize slow endpoints
5. Re-run load tests to validate improvements
6. Update baseline metrics if performance improved
## References
- **k6 Documentation**: https://k6.io/docs/
- **k6 Examples**: https://k6.io/docs/examples/
- **Locust Load Tests**: `README.md` (Locust-based tests)
- **Phase 208 Benchmarks**: `.planning/phases/208-integration-performance-testing/208-07-PERFORMANCE-METRICS.md`
- **Monitoring Setup**: `backend/docs/MONITORING_SETUP.md`
## Comparison: k6 vs Locust
| Feature | k6 | Locust |
|---------|----|----|
| Language | JavaScript | Python |
| Learning Curve | Low (JS familiarity) | Low (Python familiarity) |
| CI/CD Integration | Excellent (native CLI) | Good (requires web UI or headless mode) |
| Interactive Web UI | No | Yes (built-in) |
| Distributed Load | k6 Cloud (paid) | Built-in (master/worker) |
| Thresholds | Built-in | Manual checks |
| Best For | CI/CD, automation | Interactive testing, distributed load |
**Recommendation:** Use k6 for CI/CD automation and Locust for interactive testing/distributed load.