Skip to content

Performance

This document covers performance optimization techniques and configuration for SLOzy.

Cache Layer

SLOzy uses a two-tier caching system implemented in internal/cache/:

  1. In-memory cache (sync.Map) — Ultra-fast access for frequently queried data
  2. PostgreSQL-backed cache (query_cache table via internal/cache/repository.go) — Persistent cache with compression

Configuration

go
type CacheConfig struct {
    DefaultTTL            time.Duration // Default entry time-to-live
    MaxEntries            int           // Maximum cache entries
    CleanupInterval       time.Duration // Expired entry cleanup interval
    EnableMemoryCache     bool          // Enable in-memory caching layer
    EnableCompression     bool          // Compress cached results
    CompressionThreshold  int           // Minimum bytes for compression
    EnableWarmup          bool          // Preload popular entries on startup
    AnalyticsRetention    time.Duration // How long to keep analytics data
}

Cache Statistics

Monitor cache effectiveness via GET /api/v1/cache/statistics. Aim for a hit rate above 85%.

Connection Pooling

PostgreSQL connection pool settings (internal/config/config.go):

SettingDefaultDescription
POSTGRES_MAX_OPEN_CONNS25Maximum concurrent connections
POSTGRES_MAX_IDLE_CONNS10Maximum idle connections in pool
POSTGRES_CONN_MAX_LIFETIME1hMaximum connection lifetime
POSTGRES_CONN_MAX_IDLETIME10mMaximum idle time before closing

The pool is configured in internal/db/connection.go:

go
config.MaxConns = int32(cfg.PostgresMaxOpenConns)
config.MinConns = int32(cfg.PostgresMaxIdleConns)
config.MaxConnLifetime = 1800 * time.Second
config.MaxConnIdleTime = 600 * time.Second
config.HealthCheckPeriod = 1 * time.Minute

Tune these values based on your workload and database capacity.

Query Optimization

  • All queries use parameterized statements to avoid planning overhead
  • Migrations include indexes on frequently queried columns (user_id, organization_id, slo_id, timestamps)
  • The RBAC system uses a check_permission() PostgreSQL function for efficient permission lookups
  • SLO calculations use range queries with indexed time windows

Rate Limiting

Rate limiting uses a token bucket algorithm (internal/middleware/security.go):

go
type RateLimiterConfig struct {
    Enabled     bool
    GlobalRate  int  // requests per minute for all users
    GlobalBurst int  // burst size for global limiter
    PerIPRate   int  // requests per minute per IP
    PerIPBurst  int  // burst size per IP
    Whitelist   []string
    Blacklist   []string
}

Default limits: 1000 global requests/minute (burst 50), 100 per-IP requests/minute (burst 10).

Build Size Optimization

The frontend uses Vite with React and Ant Design.

Lazy Loaded Routes

Routes are lazy-loaded to reduce initial bundle size. The frontend (frontend/src/) uses React Router for code splitting:

  • Each route loads its component on demand
  • Ant Design components are tree-shaken during build

Production Build

bash
cd frontend && npm run build
# Output in frontend/dist/

The Docker build uses multi-stage builds to minimize the final image size:

dockerfile
FROM golang:1.25.0-alpine AS builder
# ... build stage
FROM alpine:3.19
# ... minimal runtime stage