util

package module
v0.1.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 19, 2024 License: MIT Imports: 2 Imported by: 0

README ¶

Terraster - Uncomplicated Load Balancer/Reverse Proxy

Project Status: Early Stages 🚧

This project is currently in its early development stages. While the core functionality is in place and working as intended, further improvements and features are actively being developed. Expect updates as the project evolves.

A high-performance, feature-rich Layer 7 (L7) load balancer with a robust and user-friendly admin API.

Features

  • Multiple load balancing algorithms

    • Round Robin
    • Weighted Round Robin
    • Least Connections
    • Weighted Least Connections
    • Response Time Based
    • IP Hash
    • Consistent Hashing
    • Adaptive Load Balancing
  • Advanced Features

    • WebSocket Support
    • SSL/TLS with automatic certificate management
    • Connection pooling
    • Circuit breaker
    • Rate limiting
    • Compression
  • Monitoring

    • Health checking
  • Administration

    • Dynamic configuration via Admin API
    • Graceful shutdown

Quick Start

  1. Build Terraster:
go build -o terraster cmd/main.go
  1. Create a configuration file or use provided in repo (config.yaml):
port: 443
admin_port: 4433

services:
  - name: backend-api # service name
    host: internal-api1.local.com # service listener hostname
    port: 8455 # service listener port
    tls: # service tls configuration
      cert_file: "/path/to/api-cert.pem"
      key_file: "/path/to/api-key.pem"
    health_check: # service health check configuration - will be used by each location
      type: "http"
      path: "/"
      interval: "5s"
      timeout: "3s"
      thresholds:
        healthy: 2
        unhealthy: 3
    locations:
      - path: "/api/" # served path suffix so "https://internal-api1.local.com/api/"
        lb_policy: round-robin # load balancing policy
        http_redirect: true # http to https redirect
        redirect: "/" # redirect e.q. from "/" to "/api/"
        backends:
          - url: http://internal-api1.local.com:8455
            weight: 5
            max_connections: 1000
            health_check: # or have separate health check for each backend and override service health check
              type: "http"
              path: "/api_health"
              interval: "4s"
              timeout: "3s"
              thresholds:
                healthy: 1
                unhealthy: 2
          - url: http://internal-api2.local.com:8455
            weight: 3
            max_connections: 800

  - name: frontend
    host: frontend.local.com
    locations:
      - path: "/"
        lb_policy: least_connections
        http_redirect: false
        rewrite: "/frontend/" # rewrite e.q. from "/" to "/frontend/" in the backend service
        backends:
          - url: http://frontend-1.local.com:3000
            weight: 5
            max_connections: 1000

          - url: http://frontend-2.local.com:3000
            weight: 3
            max_connections: 800

# global health check will be used by every service that don't have health_check configuration
health_check:
  interval: 10s
  timeout: 2s
  path: /health

# api authentication
auth:
  jwt_secret: mySecretKey
  db_path: ./auth.db
  password_expiry_days: 7
  password_history_size: 5

admin_api:
  rate_limit:
    requests_per_second: 10
    burst: 20

rate_limit: # global rate limit for each service if not defined in the service
  requests_per_second: 100
  burst: 150

connection_pool:
  max_idle: 100
  max_open: 1000
  idle_timeout: 90s
  1. Run the load balancer:
./terraster --config config.yaml

Configuration Examples

Basic Configuration
port: 8080
algorithm: round-robin
backends:
  - url: http://localhost:8081
  - url: http://localhost:8082
Advanced Configuration
port: 8080
admin_port: 8081
algorithm: adaptive

tls:
  enabled: true
  domains:
    - example.com
  cert_dir: /etc/certs
  auto_cert: true

rate_limit:
  requests_per_second: 1000
  burst: 50

circuit_breaker:
  threshold: 5
  timeout: 60s

connection_pool:
  max_idle: 100
  max_open: 1000
  idle_timeout: 90s

cors:
  allowed_origins:
    - https://example.com
  allowed_methods:
    - GET
    - POST
  allowed_headers:
    - Content-Type
  max_age: 3600

security:
  hsts: true
  hsts_max_age: 31536000
  frame_options: DENY
  content_type_options: true
  xss_protection: true

API Examples

Admin API
  1. Get Backend Status:
curl http://localhost:8081/api/backends \
    -H "Authorization: Bearer eyJhbGciOiJIUzI1..." \
    -H "Content-Type: application/json"
  1. Add Backend to service:
curl -X POST http://localhost:8081/api/backends?service_name=backend-api \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1..." \
  -d '{
    "url": "http://newbackend:8080",
    "weight": 5
  }'

Benchmarking Tool

// tools/benchmark/main.go
package main

import (
	"flag"
	"fmt"
	"net/http"
	"sync"
	"time"
)

func main() {
	url := flag.String("url", "http://localhost:8080", "URL to benchmark")
	concurrency := flag.Int("c", 10, "Number of concurrent requests")
	requests := flag.Int("n", 1000, "Total number of requests")
	duration := flag.Duration("d", 0, "Duration of the test")
	flag.Parse()

	results := make(chan time.Duration, *requests)
	errors := make(chan error, *requests)
	var wg sync.WaitGroup

	start := time.Now()
	client := &http.Client{
		Timeout: time.Second * 10,
	}

	if *duration > 0 {
		timer := time.NewTimer(*duration)
		go func() {
			<-timer.C
			fmt.Println("Duration reached, stopping...")
			*requests = 0
		}()
	}

	// Start workers
	for i := 0; i < *concurrency; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			for i := 0; i < *requests / *concurrency; i++ {
				requestStart := time.Now()
				resp, err := client.Get(*url)
				if err != nil {
					errors <- err
					continue
				}
				resp.Body.Close()
				results <- time.Since(requestStart)
			}
		}()
	}

	// Wait for completion
	wg.Wait()
	close(results)
	close(errors)

	// Process results
	var total time.Duration
	var count int
	var min, max time.Duration
	errCount := 0

	for d := range results {
		if min == 0 || d < min {
			min = d
		}
		if d > max {
			max = d
		}
		total += d
		count++
	}

	for range errors {
		errCount++
	}

	// Print results
	fmt.Printf("\nBenchmark Results:\n")
	fmt.Printf("URL: %s\n", *url)
	fmt.Printf("Concurrency Level: %d\n", *concurrency)
	fmt.Printf("Time taken: %v\n", time.Since(start))
	fmt.Printf("Complete requests: %d\n", count)
	fmt.Printf("Failed requests: %d\n", errCount)
	fmt.Printf("Requests per second: %.2f\n", float64(count)/time.Since(start).Seconds())
	fmt.Printf("Mean latency: %v\n", total/time.Duration(count))
	fmt.Printf("Min latency: %v\n", min)
	fmt.Printf("Max latency: %v\n", max)
}

Docker Deployment

# Dockerfile
FROM golang:1.21-alpine AS builder

WORKDIR /app
COPY . .
RUN go mod download
RUN go build -o terraster cmd/main.go

FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /app/terraster .
COPY config.yaml .

EXPOSE 8080 8081 9090
CMD ["./terraster", "--config", "config.yaml"]
# docker-compose.yml
version: '3.8'

services:
  terraster:
    build: .
    ports:
      - "8080:8080"
      - "8081:8081"
      - "9090:9090"
    volumes:
      - ./config.yaml:/root/config.yaml
      - ./certs:/etc/certs
    restart: unless-stopped

License

MIT License

Documentation ¶

Index ¶

Constants ¶

View Source
const (
	RetryKey contextKey = iota
	BackendKey
)

Variables ¶

This section is empty.

Functions ¶

func GetBackendFromContext ¶

func GetBackendFromContext(r *http.Request) string

func GetRetryFromContext ¶

func GetRetryFromContext(r *http.Request) int

func SetBackendInContext ¶

func SetBackendInContext(r *http.Request, backend string) *http.Request

func SetRetryInContext ¶

func SetRetryInContext(r *http.Request) *http.Request

Types ¶

This section is empty.

Directories ¶

Path Synopsis
internal
auth/validation
auth/validation/password.go
auth/validation/password.go
pkg
scripts
database command
tools
benchmark command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL