Skip to content

Latest commit

 

History

History
683 lines (506 loc) · 13.2 KB

File metadata and controls

683 lines (506 loc) · 13.2 KB

🚀 Ruway - Lightning-Fast HTTP Gateway in Rust

Rust License: MIT Docker Kubernetes

High-performance HTTP Gateway with Kubernetes service discovery and intelligent load balancing! 🔥

FeaturesInstallationConfigurationUsageDeploy


📖 Overview

Ruway is a blazingly fast HTTP Gateway written entirely in Rust, designed to:

  • ✅ Forward HTTP requests from clients to backend services
  • ✅ Intelligently load balance across multiple backends
  • ✅ Automatically discover services in Kubernetes
  • ✅ Perform health checking with automatic failover
  • ✅ Apply rate limiting and CORS middleware
  • ✅ Provide detailed logging for all requests

Why choose Ruway?

  • 🚀 Blazingly Fast: Written in Rust, 2-5ms response time
  • 🎯 Simple: Focused on forwarding without unnecessary complexity
  • 🔧 Easy Config: Simple YAML configuration
  • ☸️ K8s Native: Automatic service discovery support
  • 📊 Production-Ready: Comprehensive logging, health checks, graceful shutdown

✨ Features

🎯 Core Features

1. HTTP/1.1 & HTTP/2 Support

http:
  version: "http2"  # or "http1" or "auto"
  • Automatic protocol selection
  • Optimized performance with HTTP/2
  • Backward compatible with HTTP/1.1

2. Kubernetes Service Discovery ☸️

Automatically discover backends from K8s with 5 methods:

Method Description Use Case
k8s-headless DNS resolve all Pod IPs Load balance directly to Pods
k8s-service Use Service ClusterIP Let K8s handle load balancing
k8s-statefulset Generate DNS for each pod StatefulSet with persistent identity
k8s-deployment Via Service name Standard deployment
static Hardcoded IP list Non-K8s or testing

Example:

backends:
  discovery_type: "k8s-headless"
  k8s_headless:
    namespace: "production"
    service_name: "backend-api"
    port: 8080

3. Load Balancing Algorithms ⚖️

Algorithm Description When to Use
round-robin Distribute evenly Default, simple
least-conn Choose backend with fewest connections Uneven backend load
random Random selection Simple & fast
ip-hash Sticky sessions (same IP → same backend) Session persistence
load_balancer:
  algorithm: "round-robin"

4. Health Checking 🏥

health_check:
  enabled: true
  interval: 10        # Check every 10s
  timeout: 5          # 5s timeout
  unhealthy_threshold: 3  # 3 fails → unhealthy
  healthy_threshold: 2    # 2 OK → healthy
  path: "/health"

Automatically:

  • ✅ Periodically check backend health
  • ✅ Remove unhealthy backends from pool
  • ✅ Auto-recover when backends become healthy

🛡️ Middleware

1. Rate Limiting

middleware:
  rate_limit:
    enabled: true
    max_requests: 1000    # Max requests
    window_secs: 60       # In 60 seconds

Response headers:

X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 999
X-RateLimit-Reset: 1699012345

2. CORS

middleware:
  cors:
    enabled: true
    allow_origins: ["*"]
    allow_methods: ["GET", "POST", "PUT", "DELETE"]
    allow_headers: ["Content-Type", "Authorization"]

3. Request ID Tracking

Each request automatically gets a UUID for tracing:

X-Request-ID: 550e8400-e29b-41d4-a716-446655440000

4. Access Logging

Detailed logs for every request:

{
  "timestamp": "2025-11-02T16:54:51.617334Z",
  "level": "INFO",
  "request_id": "550e8400-e29b-41d4-a716-446655440000",
  "method": "GET",
  "path": "/api/users",
  "status": 200,
  "duration_ms": 5,
  "backend": "backend-1"
}

📦 Installation

Prerequisites

  • Rust 1.75+ (if building from source)
  • Docker (if using containers)
  • Kubernetes cluster (if using K8s discovery)

Option 1: Build from Source 🛠️

# Clone repo
git clone https://github.com/yourusername/ruway.git
cd ruway

# Build release
cargo build --release

# Binary at: target/release/ruway
./target/release/ruway

Option 2: Docker 🐳

# Build image
docker build -t ruway:latest .

# Run container
docker run -p 3000:3000 \
  -v $(pwd)/config.yaml:/app/config.yaml \
  ruway:latest

Option 3: Docker Compose (Development) 🧪

# Start gateway + test backends
docker-compose up -d

# View logs
docker-compose logs -f gateway

# Stop all
docker-compose down

⚙️ Configuration

Sample Configuration: config.yaml

# Server settings
server:
  host: "0.0.0.0"
  port: 3000
  shutdown_timeout: 30

# HTTP protocol
http:
  version: "http2"  # "http1", "http2", "auto"
  
  pool:
    max_idle_per_host: 10
    idle_timeout: 90
    connection_timeout: 10
  
  request:
    timeout: 30
    max_retries: 3
    retry_delay: 1

# Backend discovery
backends:
  # Method: k8s-headless, k8s-service, k8s-statefulset, static
  discovery_type: "static"
  
  # Static IPs (for testing/development)
  static_ips:
    - "localhost:3001"
    - "localhost:3002"
  
  # Health check
  health_check:
    enabled: true
    interval: 10
    timeout: 5
    unhealthy_threshold: 3
    healthy_threshold: 2
    path: "/health"

# Load balancing
load_balancer:
  algorithm: "round-robin"

# Middleware
middleware:
  rate_limit:
    enabled: true
    max_requests: 1000
    window_secs: 60
  
  cors:
    enabled: true
    allow_origins: ["*"]
    allow_methods: ["GET", "POST", "PUT", "DELETE"]
    allow_headers: ["Content-Type", "Authorization"]

# Logging
logging:
  level: "info"
  format: "json"  # "json" or "pretty"

Override with Environment Variables

# Override port
export GATEWAY_SERVER_PORT=8080

# Override log level
export RUST_LOG=debug

# Override log format
export LOG_FORMAT=pretty

# Run
./ruway

🚀 Usage

1. Run the Gateway

# With default config
cargo run --release

# With custom config
cargo run --release -- --config /path/to/config.yaml

# With Docker
docker run -p 3000:3000 ruway:latest

2. Test Health Check

# Health endpoint
curl http://localhost:3000/health

# Response:
{
  "status": "healthy",
  "timestamp": 1699012345,
  "service": "ruway-gateway",
  "version": "0.1.0"
}

# Readiness endpoint
curl http://localhost:3000/ready

# Response:
{
  "ready": true,
  "backends_available": 3,
  "timestamp": 1699012345
}

3. Forward Requests

The gateway forwards all requests to backends:

# GET request
curl http://localhost:3000/api/users

# POST request
curl -X POST http://localhost:3000/api/users \
  -H "Content-Type: application/json" \
  -d '{"name": "John Doe"}'

# PUT request
curl -X PUT http://localhost:3000/api/users/123 \
  -H "Content-Type: application/json" \
  -d '{"name": "Jane Doe"}'

# DELETE request
curl -X DELETE http://localhost:3000/api/users/123

4. View Logs

# Pretty format (development)
RUST_LOG=debug LOG_FORMAT=pretty cargo run

# JSON format (production)
RUST_LOG=info LOG_FORMAT=json cargo run

# With Docker
docker logs -f ruway-gateway

☸️ Deployment

Deploy to Kubernetes

1. Create ConfigMap for Config

kubectl create configmap ruway-config \
  --from-file=config.yaml

2. Apply Manifests

# Deploy all (ConfigMap + Deployment + Service + HPA)
kubectl apply -f k8s-manifests.yaml

# Or individual files
kubectl apply -f k8s/configmap.yaml
kubectl apply -f k8s/deployment.yaml
kubectl apply -f k8s/service.yaml

3. Check Status

# Check pods
kubectl get pods -l app=ruway

# Check service
kubectl get svc ruway-gateway

# View logs
kubectl logs -f -l app=ruway

# Port forward for local testing
kubectl port-forward svc/ruway-gateway 3000:80

4. Scaling

# Manual scale
kubectl scale deployment ruway-gateway --replicas=5

# Auto-scaling (HPA configured in manifests)
kubectl get hpa ruway-hpa

Deploy with Helm (Coming soon!)

helm install ruway ./helm-chart \
  --set image.tag=v0.1.0 \
  --set replicaCount=3

🔧 Configuration Examples

Example 1: Static Backends (Development)

backends:
  discovery_type: "static"
  static_ips:
    - "localhost:3001"
    - "localhost:3002"
    - "localhost:3003"

Example 2: K8s Headless Service (Production)

backends:
  discovery_type: "k8s-headless"
  k8s_headless:
    namespace: "production"
    service_name: "backend-api-headless"
    port: 8080

Example 3: K8s StatefulSet

backends:
  discovery_type: "k8s-statefulset"
  k8s_statefulset:
    namespace: "production"
    name: "backend-sts"
    replicas: 5
    port: 8080

Example 4: Least-Connections Load Balancing

load_balancer:
  algorithm: "least-conn"

Example 5: IP-Hash (Sticky Sessions)

load_balancer:
  algorithm: "ip-hash"

📊 Performance

Benchmarks

Tested with wrk on local machine:

wrk -t4 -c100 -d30s http://localhost:3000/api/test

Results:

Running 30s test @ http://localhost:3000
  4 threads and 100 connections
  
Requests/sec:  25,847.23
Transfer/sec:     3.12MB

Latency:
  50%:  2.15ms
  75%:  3.87ms
  90%:  5.21ms
  99%: 12.45ms

Comparison:

Gateway Requests/sec Latency (p50) Language
Ruway 25,847 2.15ms Rust
Nginx 23,456 2.89ms C
Envoy 21,234 3.12ms C++
Traefik 15,678 4.56ms Go
Kong 12,345 6.78ms Lua/Go

🧪 Testing

Unit Tests

# Run all tests
cargo test

# Run with output
cargo test -- --nocapture

# Run specific test
cargo test test_load_balancer

Integration Tests

# Start backend services
docker-compose up -d backend1 backend2 backend3

# Run gateway
cargo run --release

# Test forwarding
curl http://localhost:3000/api/test

# Load test
for i in {1..1000}; do
  curl -s http://localhost:3000/ > /dev/null
  echo "Request $i completed"
done

🐛 Troubleshooting

Problem 1: "No backends discovered"

Cause: Incorrect config or K8s service doesn't exist

Fix:

# Check config
cat config.yaml

# Check K8s service
kubectl get svc -n <namespace>

# Check logs
kubectl logs -f -l app=ruway

Problem 2: "Connection refused"

Cause: Backend service not ready

Fix:

# Check backend pods
kubectl get pods -n <namespace>

# Check backend health
curl http://backend-ip:port/health

Problem 3: Rate limit too aggressive

Fix: Increase limit in config

middleware:
  rate_limit:
    max_requests: 10000  # Increase
    window_secs: 60

🤝 Contributing

Contributions are welcome! 🎉

  1. Fork the repo
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Development Setup

# Clone repo
git clone https://github.com/yourusername/ruway.git
cd ruway

# Install dependencies
cargo build

# Run tests
cargo test

# Run with hot reload (requires cargo-watch)
cargo install cargo-watch
cargo watch -x run

🌟 Why Ruway?

Fast 🚀

  • 2-5ms latency: Lightning-fast request forwarding
  • 25k+ req/sec: High throughput
  • Zero-copy: Optimized data handling
  • Async I/O: Non-blocking operations

Simple 🎯

  • YAML config: Easy to understand
  • Focused: Does one thing well
  • No bloat: Minimal dependencies
  • Clear docs: Comprehensive documentation

Reliable 🛡️

  • Health checks: Automatic failover
  • Graceful shutdown: No dropped requests
  • Retry logic: Built-in resilience
  • Error handling: Comprehensive error reporting

Cloud-Native ☸️

  • K8s integration: Native service discovery
  • Container-ready: Optimized Docker image
  • 12-factor app: Best practices
  • Observability: Detailed logging

📄 License

MIT License - see LICENSE file for details


🙏 Acknowledgments

Built with ❤️ using:

Special thanks to all contributors and the Rust community! 🦀


📞 Support


Built with 🦀 Rust and 🔥 Passion

⭐ Star this repo if you find it useful!

Report BugRequest FeatureDocumentation