A production-ready HTTP traffic splitting library and proxy for canary deployments, A/B tests, and progressive rollouts. Built with Go for high performance and minimal overhead.
- Percentage-based traffic splitting with configurable weights
- Deterministic routing using consistent hashing for sticky sessions
- Multiple matching rules: path, path prefix, headers
- Hot configuration reload without dropping connections
- Prometheus metrics for monitoring and observability
- Library mode for embedding in existing applications
- Standalone proxy mode for infrastructure-level routing
- Zero dependencies (except for YAML parsing and metrics)
go install github.com/traffic-splitter/traffic-splitter/cmd/traffic-splitter@latest
traffic-splitter init > config.yaml
Example configuration:
version: v1
routes:
- name: checkout-redesign
match:
path_prefix: /checkout
upstreams:
- name: checkout-v1
url: https://checkout-v1:8080
weight: 80
- name: checkout-v2
url: https://checkout-v2:8080
weight: 20
traffic-splitter proxy -f config.yaml -p 8080
traffic-splitter test -f config.yaml -r '{"path": "/checkout", "headers": {"X-User-ID": "123"}}'
Gradually roll out new versions with minimal risk:
routes:
- name: api-canary
match:
path_prefix: /api
upstreams:
- name: api-stable
url: https://api-stable:8080
weight: 95
- name: api-canary
url: https://api-canary:8080
weight: 5
Test different implementations with equal traffic distribution:
routes:
- name: homepage-ab-test
match:
path: /
upstreams:
- name: homepage-control
url: https://homepage-a:8080
weight: 50
- name: homepage-variant
url: https://homepage-b:8080
weight: 50
Switch traffic between environments instantly:
routes:
- name: payment-blue-green
match:
path_prefix: /api/payment
upstreams:
- name: payment-blue
url: https://payment-blue:8080
weight: 100
- name: payment-green
url: https://payment-green:8080
weight: 0 # Change to 100 to switch
Embed traffic splitting directly in your Go applications:
package main
import (
"net/http"
"github.com/traffic-splitter/traffic-splitter/pkg/middleware"
)
func main() {
// Load configuration
cfg := loadConfig("config.yaml")
// Create splitter
splitter, _ := middleware.New(cfg)
// Define handlers
control := http.HandlerFunc(controlHandler)
treatment := http.HandlerFunc(treatmentHandler)
// Apply middleware
handler := splitter.Middleware("experiment-name", control, treatment)
http.Handle("/", handler)
http.ListenAndServe(":8080", nil)
}
- Architecture Overview - Detailed system design and components
- Design Document - Design decisions and trade-offs
- Visual Diagrams - System flow and deployment patterns
┌─────────────┐ ┌─────────────┐ ┌──────────────┐
│ Client │────▶│ Traffic │────▶│ Upstream A │
└─────────────┘ │ Splitter │ └──────────────┘
│ │
│ - Router │ ┌──────────────┐
│ - Proxy │────▶│ Upstream B │
│ - Metrics │ └──────────────┘
└─────────────┘
- Request matching: Check path, headers against configured routes
- Hash calculation: Generate consistent hash from X-User-ID, session cookie, or IP
- Weight selection: Map hash to upstream based on weight distribution
- Proxy request: Forward to selected upstream with decision metadata
For detailed architecture diagrams and system design, see the Architecture Documentation.
path
: Exact path matchpath_prefix
: Path prefix matchheader
: Single header matchheaders
: Multiple headers (all must match)
Traffic Splitter ensures consistent routing for the same user by hashing:
X-User-ID
header (if present)- Session cookie (fallback)
- Client IP address (final fallback)
Prometheus metrics available at /metrics
:
traffic_splitter_requests_total{route, upstream}
- Request count per route/upstreamtraffic_splitter_request_duration_seconds{route, upstream}
- Request latencytraffic_splitter_upstream_healthy{upstream}
- Upstream health status
# Validate configuration
traffic-splitter validate -f config.yaml
# Test routing for specific request
traffic-splitter test -f config.yaml -r '{"path": "/api/users", "headers": {"X-User-ID": "123"}}'
# Run as HTTP proxy
traffic-splitter proxy -f config.yaml -p 8080 -m 9090
# Generate sample configuration
traffic-splitter init > config.yaml
- Zero allocations in routing decisions
- Pre-compiled regex patterns
- Connection pooling for upstream requests
- Concurrent request handling
- Benchmarks: ~50k requests/second on modest hardware
See the examples directory for:
# Clone repository
git clone https://github.com/traffic-splitter/traffic-splitter
cd traffic-splitter
# Run tests
go test ./...
# Build binary
go build -o traffic-splitter cmd/traffic-splitter/main.go
# Run locally
./traffic-splitter proxy -f examples/config/simple.yaml
MIT License - see LICENSE file for details.
Contributions welcome! Please read our Contributing Guide first.
- gRPC support
- Request/response modification
- Circuit breaking
- Distributed tracing integration
- WebSocket support
- Dynamic configuration API
Traffic-Splitter is open-source and free to use.
If you'd like to support development, please consider sponsoring:
Other ways to support:
Sponsorships help fund ongoing maintenance, security updates, and new features like gRPC support, circuit breaking, and future intelligent routing.