394 lines
8.1 KiB
Markdown
394 lines
8.1 KiB
Markdown
|
|
# Tikker Performance Optimization Guide
|
||
|
|
|
||
|
|
## Performance Benchmarks
|
||
|
|
|
||
|
|
Baseline performance metrics on standard hardware (2CPU, 2GB RAM):
|
||
|
|
|
||
|
|
### API Service (C Tools Integration)
|
||
|
|
- Health Check: ~15ms (p50), <50ms (p99)
|
||
|
|
- Daily Stats: ~80ms (p50), <150ms (p99)
|
||
|
|
- Top Words: ~120ms (p50), <250ms (p99)
|
||
|
|
- Throughput: ~40-60 req/s
|
||
|
|
|
||
|
|
### AI Service
|
||
|
|
- Health Check: ~10ms (p50), <50ms (p99)
|
||
|
|
- Text Analysis: ~2-5s (depends on text length and API availability)
|
||
|
|
- Throughput: ~0.5 req/s (limited by OpenAI API)
|
||
|
|
|
||
|
|
### Visualization Service
|
||
|
|
- Health Check: ~12ms (p50), <50ms (p99)
|
||
|
|
- Bar Chart: ~150ms (p50), <300ms (p99)
|
||
|
|
- Line Chart: ~160ms (p50), <320ms (p99)
|
||
|
|
- Pie Chart: ~140ms (p50), <280ms (p99)
|
||
|
|
- Throughput: ~5-8 req/s
|
||
|
|
|
||
|
|
## Running Benchmarks
|
||
|
|
|
||
|
|
### Quick Benchmark
|
||
|
|
```bash
|
||
|
|
python scripts/benchmark.py
|
||
|
|
```
|
||
|
|
|
||
|
|
### Benchmark Against Remote Server
|
||
|
|
```bash
|
||
|
|
python scripts/benchmark.py http://production-server
|
||
|
|
```
|
||
|
|
|
||
|
|
### Detailed Test Results
|
||
|
|
```bash
|
||
|
|
pytest tests/test_performance.py -v --tb=short
|
||
|
|
```
|
||
|
|
|
||
|
|
## Optimization Strategies
|
||
|
|
|
||
|
|
### 1. Database Optimization
|
||
|
|
|
||
|
|
#### Vacuum Database
|
||
|
|
Regular database maintenance improves query performance.
|
||
|
|
|
||
|
|
```bash
|
||
|
|
docker-compose exec api sqlite3 tikker.db "VACUUM;"
|
||
|
|
```
|
||
|
|
|
||
|
|
Impact: 5-15% query speed improvement
|
||
|
|
|
||
|
|
#### Create Indexes
|
||
|
|
Add indexes for frequently queried columns:
|
||
|
|
|
||
|
|
```sql
|
||
|
|
CREATE INDEX idx_words_frequency ON words(frequency DESC);
|
||
|
|
CREATE INDEX idx_events_timestamp ON events(timestamp);
|
||
|
|
CREATE INDEX idx_events_date ON events(date);
|
||
|
|
```
|
||
|
|
|
||
|
|
Impact: 30-50% improvement for indexed queries
|
||
|
|
|
||
|
|
#### Query Optimization
|
||
|
|
Use EXPLAIN QUERY PLAN to analyze slow queries:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
sqlite3 tikker.db "EXPLAIN QUERY PLAN SELECT * FROM words ORDER BY frequency LIMIT 10;"
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2. Caching Strategies
|
||
|
|
|
||
|
|
#### Redis Caching for Frequent Queries
|
||
|
|
Add Redis for popular word list caching:
|
||
|
|
|
||
|
|
```python
|
||
|
|
import redis
|
||
|
|
cache = redis.Redis(host='localhost', port=6379)
|
||
|
|
|
||
|
|
def get_top_words(limit=10):
|
||
|
|
key = f"top_words:{limit}"
|
||
|
|
cached = cache.get(key)
|
||
|
|
if cached:
|
||
|
|
return json.loads(cached)
|
||
|
|
|
||
|
|
result = query_database(limit)
|
||
|
|
cache.setex(key, 3600, json.dumps(result))
|
||
|
|
return result
|
||
|
|
```
|
||
|
|
|
||
|
|
Impact: 10-100x improvement for cached queries
|
||
|
|
|
||
|
|
#### Add to docker-compose.yml:
|
||
|
|
```yaml
|
||
|
|
redis:
|
||
|
|
image: redis:7-alpine
|
||
|
|
ports:
|
||
|
|
- "6379:6379"
|
||
|
|
volumes:
|
||
|
|
- redis_data:/data
|
||
|
|
```
|
||
|
|
|
||
|
|
### 3. Python Optimization
|
||
|
|
|
||
|
|
#### Enable Optimization
|
||
|
|
```dockerfile
|
||
|
|
ENV PYTHONOPTIMIZE=2
|
||
|
|
ENV PYTHONDONTWRITEBYTECODE=1
|
||
|
|
```
|
||
|
|
|
||
|
|
#### Use Async I/O
|
||
|
|
Current API already uses FastAPI (async), good baseline.
|
||
|
|
|
||
|
|
#### Profile Code
|
||
|
|
Identify bottlenecks:
|
||
|
|
```bash
|
||
|
|
python -m cProfile -s cumtime -m pytest tests/test_services.py
|
||
|
|
```
|
||
|
|
|
||
|
|
### 4. C Tools Optimization
|
||
|
|
|
||
|
|
#### Compile Flags
|
||
|
|
Update Makefile with optimization flags:
|
||
|
|
|
||
|
|
```makefile
|
||
|
|
CFLAGS = -O3 -march=native -Wall -Wextra
|
||
|
|
```
|
||
|
|
|
||
|
|
Impact: 20-40% improvement in execution speed
|
||
|
|
|
||
|
|
#### Binary Stripping
|
||
|
|
Reduce binary size:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
strip build/bin/tikker-*
|
||
|
|
```
|
||
|
|
|
||
|
|
Impact: Faster loading, reduced disk I/O
|
||
|
|
|
||
|
|
### 5. Network Optimization
|
||
|
|
|
||
|
|
#### Connection Pooling
|
||
|
|
Add HTTP connection pooling in wrapper:
|
||
|
|
|
||
|
|
```python
|
||
|
|
from requests.adapters import HTTPAdapter
|
||
|
|
from urllib3.util.retry import Retry
|
||
|
|
|
||
|
|
session = requests.Session()
|
||
|
|
retry_strategy = Retry(
|
||
|
|
total=3,
|
||
|
|
backoff_factor=1,
|
||
|
|
status_forcelist=[429, 500, 502, 503, 504]
|
||
|
|
)
|
||
|
|
adapter = HTTPAdapter(max_retries=retry_strategy)
|
||
|
|
session.mount("http://", adapter)
|
||
|
|
```
|
||
|
|
|
||
|
|
#### Service Co-location
|
||
|
|
Run services on same host to reduce latency:
|
||
|
|
- Typical inter-service latency: ~5-10ms
|
||
|
|
- Same-host latency: <1ms
|
||
|
|
|
||
|
|
### 6. Memory Optimization
|
||
|
|
|
||
|
|
#### Monitor Memory Usage
|
||
|
|
```bash
|
||
|
|
docker stats
|
||
|
|
|
||
|
|
# Or detailed analysis
|
||
|
|
docker-compose exec api ps aux
|
||
|
|
```
|
||
|
|
|
||
|
|
#### Reduce Buffer Sizes
|
||
|
|
In c_tools_wrapper.py:
|
||
|
|
```python
|
||
|
|
# Limit concurrent subprocess calls
|
||
|
|
from concurrent.futures import ThreadPoolExecutor
|
||
|
|
executor = ThreadPoolExecutor(max_workers=4)
|
||
|
|
```
|
||
|
|
|
||
|
|
#### Garbage Collection Tuning
|
||
|
|
```python
|
||
|
|
import gc
|
||
|
|
gc.set_threshold(10000)
|
||
|
|
```
|
||
|
|
|
||
|
|
### 7. Container Resource Limits
|
||
|
|
|
||
|
|
Update docker-compose.yml:
|
||
|
|
|
||
|
|
```yaml
|
||
|
|
services:
|
||
|
|
api:
|
||
|
|
deploy:
|
||
|
|
resources:
|
||
|
|
limits:
|
||
|
|
cpus: '2'
|
||
|
|
memory: 2G
|
||
|
|
reservations:
|
||
|
|
cpus: '1'
|
||
|
|
memory: 1G
|
||
|
|
```
|
||
|
|
|
||
|
|
### 8. Load Balancing
|
||
|
|
|
||
|
|
For production deployments with multiple instances:
|
||
|
|
|
||
|
|
```yaml
|
||
|
|
nginx:
|
||
|
|
image: nginx:latest
|
||
|
|
ports:
|
||
|
|
- "8000:8000"
|
||
|
|
volumes:
|
||
|
|
- ./nginx.conf:/etc/nginx/nginx.conf:ro
|
||
|
|
depends_on:
|
||
|
|
- api1
|
||
|
|
- api2
|
||
|
|
- api3
|
||
|
|
```
|
||
|
|
|
||
|
|
nginx.conf:
|
||
|
|
```nginx
|
||
|
|
upstream api {
|
||
|
|
server api1:8000;
|
||
|
|
server api2:8000;
|
||
|
|
server api3:8000;
|
||
|
|
}
|
||
|
|
|
||
|
|
server {
|
||
|
|
listen 8000;
|
||
|
|
location / {
|
||
|
|
proxy_pass http://api;
|
||
|
|
proxy_connect_timeout 5s;
|
||
|
|
proxy_read_timeout 10s;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## Performance Tuning Checklist
|
||
|
|
|
||
|
|
- [ ] Database vacuumed and indexed
|
||
|
|
- [ ] Python optimization flags enabled
|
||
|
|
- [ ] C compilation optimizations applied
|
||
|
|
- [ ] Connection pooling configured
|
||
|
|
- [ ] Caching strategy implemented
|
||
|
|
- [ ] Memory limits set appropriately
|
||
|
|
- [ ] Load balancing configured (if needed)
|
||
|
|
- [ ] Monitoring and logging enabled
|
||
|
|
- [ ] Benchmarks show acceptable latency
|
||
|
|
- [ ] Throughput meets SLA requirements
|
||
|
|
|
||
|
|
## Monitoring Performance
|
||
|
|
|
||
|
|
### Key Metrics to Track
|
||
|
|
|
||
|
|
1. **Latency (p50, p95, p99)**
|
||
|
|
- Target: p50 <100ms, p99 <500ms
|
||
|
|
|
||
|
|
2. **Throughput (req/s)**
|
||
|
|
- Target: >20 req/s per service
|
||
|
|
|
||
|
|
3. **Error Rate**
|
||
|
|
- Target: <0.1%
|
||
|
|
|
||
|
|
4. **Resource Usage**
|
||
|
|
- CPU: <80% sustained
|
||
|
|
- Memory: <80% allocated
|
||
|
|
- Disk: <90% capacity
|
||
|
|
|
||
|
|
### Prometheus Metrics
|
||
|
|
|
||
|
|
Add to FastAPI apps:
|
||
|
|
|
||
|
|
```python
|
||
|
|
from prometheus_client import Counter, Histogram, generate_latest
|
||
|
|
|
||
|
|
request_count = Counter('api_requests_total', 'Total requests')
|
||
|
|
request_duration = Histogram('api_request_duration_seconds', 'Request duration')
|
||
|
|
|
||
|
|
@app.middleware("http")
|
||
|
|
async def add_metrics(request, call_next):
|
||
|
|
start = time.time()
|
||
|
|
response = await call_next(request)
|
||
|
|
duration = time.time() - start
|
||
|
|
|
||
|
|
request_count.inc()
|
||
|
|
request_duration.observe(duration)
|
||
|
|
return response
|
||
|
|
|
||
|
|
@app.get("/metrics")
|
||
|
|
def metrics():
|
||
|
|
return generate_latest()
|
||
|
|
```
|
||
|
|
|
||
|
|
## Troubleshooting Performance Issues
|
||
|
|
|
||
|
|
### High CPU Usage
|
||
|
|
1. Profile code: `python -m cProfile`
|
||
|
|
2. Check for infinite loops in C tools
|
||
|
|
3. Reduce concurrent operations
|
||
|
|
|
||
|
|
### High Memory Usage
|
||
|
|
1. Monitor with `docker stats`
|
||
|
|
2. Check for memory leaks in C code
|
||
|
|
3. Implement garbage collection tuning
|
||
|
|
4. Use connection pooling
|
||
|
|
|
||
|
|
### Slow Queries
|
||
|
|
1. Run EXPLAIN QUERY PLAN
|
||
|
|
2. Add missing indexes
|
||
|
|
3. Verify statistics are current
|
||
|
|
4. Consider query rewriting
|
||
|
|
|
||
|
|
### Network Latency
|
||
|
|
1. Check service co-location
|
||
|
|
2. Verify DNS resolution
|
||
|
|
3. Monitor with `tcpdump`
|
||
|
|
4. Consider service mesh (istio)
|
||
|
|
|
||
|
|
### Database Lock Issues
|
||
|
|
1. Check for long-running transactions
|
||
|
|
2. Verify concurrent access limits
|
||
|
|
3. Consider read replicas
|
||
|
|
4. Increase timeout values
|
||
|
|
|
||
|
|
## Advanced Optimization
|
||
|
|
|
||
|
|
### Async Database Access
|
||
|
|
Consider async SQLite driver for true async I/O:
|
||
|
|
|
||
|
|
```python
|
||
|
|
from aiosqlite import connect
|
||
|
|
|
||
|
|
async def get_stats():
|
||
|
|
async with connect('tikker.db') as db:
|
||
|
|
cursor = await db.execute('SELECT * FROM events')
|
||
|
|
return await cursor.fetchall()
|
||
|
|
```
|
||
|
|
|
||
|
|
### Compiled C Extensions
|
||
|
|
Convert performance-critical Python code to C extensions:
|
||
|
|
|
||
|
|
```c
|
||
|
|
// stats.c
|
||
|
|
PyObject* get_daily_stats(PyObject* self, PyObject* args) {
|
||
|
|
// High-performance C implementation
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### Graph Query Optimization
|
||
|
|
For complex analyses, consider graph database:
|
||
|
|
|
||
|
|
```
|
||
|
|
Events → Words → Patterns
|
||
|
|
Analysis becomes graph traversal instead of SQL joins
|
||
|
|
```
|
||
|
|
|
||
|
|
## SLA Targets
|
||
|
|
|
||
|
|
Recommended SLA targets for Tikker:
|
||
|
|
|
||
|
|
| Metric | Target | Priority |
|
||
|
|
|--------|--------|----------|
|
||
|
|
| API Availability | 99.5% | Critical |
|
||
|
|
| Health Check Latency | <50ms | Critical |
|
||
|
|
| Stats Query Latency | <200ms | High |
|
||
|
|
| Word Search Latency | <300ms | High |
|
||
|
|
| Report Generation | <5s | Medium |
|
||
|
|
| AI Analysis | <10s | Low |
|
||
|
|
|
||
|
|
## Performance Testing in CI/CD
|
||
|
|
|
||
|
|
Add performance regression testing:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Run baseline benchmark
|
||
|
|
python scripts/benchmark.py baseline
|
||
|
|
|
||
|
|
# Run benchmark
|
||
|
|
python scripts/benchmark.py current
|
||
|
|
|
||
|
|
# Compare and fail if regression
|
||
|
|
python scripts/compare_benchmarks.py baseline current --fail-if-slower 10%
|
||
|
|
```
|
||
|
|
|
||
|
|
## Further Reading
|
||
|
|
|
||
|
|
- SQLite Performance: https://www.sqlite.org/bestcase.html
|
||
|
|
- FastAPI Performance: https://fastapi.tiangolo.com/
|
||
|
|
- Python Optimization: https://docs.python.org/3/library/profile.html
|