Sentinel is built on Cloudflare’s Pingora, a battle-tested HTTP proxy framework written in Rust. This page explains what Pingora provides and how Sentinel extends it.
What is Pingora?
Pingora is an open-source proxy framework that Cloudflare uses to handle over 1 trillion requests per day. It provides:
- High-performance async HTTP handling using Tokio
- Connection pooling to upstream servers
- TLS termination with modern cipher suites
- HTTP/1.1 and HTTP/2 support
- Zero-copy buffer management for efficiency
- Graceful shutdown and upgrades
Sentinel uses Pingora as its foundation, adding routing, load balancing, agent coordination, and configuration management on top.
Why Pingora?
| Requirement | Pingora Solution |
|---|---|
| Performance | Handles millions of requests/sec with low latency |
| Safety | Written in Rust with memory safety guarantees |
| Production-proven | Powers Cloudflare’s global edge network |
| Extensibility | Clean trait-based architecture for customization |
| Operational | Built-in graceful restart and upgrade support |
Compared to Alternatives
| Framework | Language | Trade-offs |
|---|---|---|
| Pingora | Rust | Best performance + safety, smaller ecosystem |
| Envoy | C++ | Feature-rich but complex, memory safety concerns |
| HAProxy | C | Mature but harder to extend, no memory safety |
| Nginx | C | Ubiquitous but module development is challenging |
Core Pingora Concepts
Server and Services
Pingora applications start with a Server that manages one or more services:
// Create Pingora server with options
let mut server = new?;
server.bootstrap;
// Create HTTP proxy service
let proxy_service = http_proxy_service;
// Add listeners
proxy_service.add_tcp;
// Register service and run
server.add_service;
server.run_forever;
The server handles:
- Worker process management
- Signal handling (SIGHUP, SIGTERM)
- Graceful restarts and upgrades
- Daemonization
Session
A Session represents a single HTTP request/response cycle. It provides access to:
// Request information
session.req_header // HTTP request headers
session.req_header_mut // Mutable access for modifications
session.client_addr // Client IP address
// Response information
session.response_written // Response after sending
// Body handling
session.read_request_body // Read request body chunks
session.write_response_body // Write response body
HttpPeer
An HttpPeer represents an upstream server connection target:
let peer = new;
// Connection options
peer.options.connection_timeout = Some;
peer.options.read_timeout = Some;
Pingora maintains connection pools to peers for efficiency.
The ProxyHttp Trait
The ProxyHttp trait is the heart of Pingora’s extensibility. Sentinel implements this trait to inject custom logic at each stage of request processing:
Request Context
Each request gets its own context that persists throughout the lifecycle:
How Sentinel Uses Pingora
1. Route Matching (upstream_peer)
When a request arrives, Sentinel matches it to a route and selects an upstream:
Request arrives
│
▼
┌────────────────────┐
│ Parse request info │
│ (method, path, │
│ host, headers) │
└────────┬───────────┘
│
▼
┌────────────────────┐
│ Match against │
│ compiled routes │
└────────┬───────────┘
│
▼
┌────────────────────┐
│ Select peer from │
│ upstream pool │
└────────┬───────────┘
│
▼
Return HttpPeer
2. Request Processing (request_filter)
Before forwarding, Sentinel applies filters and calls agents:
async
Returning Ok(true) short-circuits processing (response already sent).
Returning Ok(false) continues to the upstream.
3. Response Processing (response_filter)
After receiving the upstream response:
async
4. Logging (logging)
After the response is sent to the client:
async
Connection Pooling
Pingora automatically pools connections to upstream servers:
┌─────────────────────────────────────────────────────────┐
│ Sentinel Proxy │
│ ┌───────────────────────────────────────────────────┐ │
│ │ Connection Pool Manager │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌───────────┐ │ │
│ │ │ backend-1 │ │ backend-2 │ │ backend-3 │ │ │
│ │ │ ┌─┐┌─┐┌─┐ │ │ ┌─┐┌─┐┌─┐ │ │ ┌─┐┌─┐ │ │ │
│ │ │ │C││C││C│ │ │ │C││C││C│ │ │ │C││C│ │ │ │
│ │ │ └─┘└─┘└─┘ │ │ └─┘└─┘└─┘ │ │ └─┘└─┘ │ │ │
│ │ └─────────────┘ └─────────────┘ └───────────┘ │ │
│ └───────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
│ │ │
▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐
│ Backend │ │ Backend │ │ Backend │
│ 1 │ │ 2 │ │ 3 │
└─────────┘ └─────────┘ └─────────┘
Benefits:
- Reduced latency - Reuses existing TCP connections
- Lower resource usage - Fewer connections to manage
- Connection limits - Prevents overwhelming backends
Graceful Operations
Hot Restart
Pingora supports zero-downtime restarts:
┌──────────────┐ SIGUSR2 ┌──────────────┐
│ Old Worker │ ───────────────▶ │ New Worker │
│ (draining) │ │ (starting) │
└──────┬───────┘ └──────┬───────┘
│ │
│ Existing connections │ New connections
│ finish gracefully │ accepted
▼ ▼
[exit when done] [fully operational]
Graceful Shutdown
On SIGTERM/SIGINT:
- Stop accepting new connections
- Wait for in-flight requests (with timeout)
- Close connection pools
- Exit cleanly
Sentinel extends this with reload coordination:
Error Handling
Pingora uses a typed error system:
Sentinel maps these to appropriate HTTP responses:
| Error Type | HTTP Status | Response |
|---|---|---|
ConnectTimedout | 504 | Gateway Timeout |
ConnectRefused | 502 | Bad Gateway |
ReadError | 502 | Bad Gateway |
InvalidHTTPHeader | 400 | Bad Request |
Performance Characteristics
Pingora’s architecture enables:
| Metric | Typical Value |
|---|---|
| Requests/sec (per core) | 100,000+ |
| P99 latency overhead | < 1ms |
| Memory per connection | ~10KB |
| Connection reuse rate | > 95% |
Dependencies
Sentinel uses these Pingora crates:
[]
= { = "0.6", = ["proxy", "lb"] }
= "0.6"
= "0.6"
= "0.6"
= "0.6"
= "0.6"
Next Steps
- Architecture Overview - High-level design
- Component Design - Sentinel’s crate structure
- Request Flow - Detailed request lifecycle