Zentinel is organized as a Cargo workspace with four core crates. This page explains each component’s responsibilities and how they interact.
Crate Structure
zentinel/
├── crates/
│ ├── proxy/ # Main proxy binary and library
│ ├── config/ # Configuration parsing and validation
│ ├── agent-protocol/ # Agent communication protocol
│ └── common/ # Shared types and utilities
└── agents/
└── echo/ # Reference agent implementation
Proxy Crate
Package: zentinel-proxy
Binary: zentinel
The main proxy implementation that ties everything together.
Key Modules
| Module | Purpose |
|---|---|
main.rs | CLI entry point, signal handling |
proxy/ | Core proxy logic, Pingora integration |
routing.rs | Route matching and compilation |
upstream/ | Upstream pool management, load balancing |
agents/ | Agent manager and coordination |
static_files/ | Static file serving |
health.rs | Active and passive health checking |
reload/ | Configuration hot reload |
logging.rs | Access, error, and audit logging |
Proxy Module
The ZentinelProxy struct implements Pingora’s ProxyHttp trait:
impl ProxyHttp for ZentinelProxy {
// Select upstream target for request
async fn upstream_peer(&self, session: &mut Session, ctx: &mut Context)
-> Result<Box<HttpPeer>>;
// Process request before forwarding
async fn request_filter(&self, session: &mut Session, ctx: &mut Context)
-> Result<bool>;
// Process response before returning to client
async fn response_filter(&self, session: &mut Session, ctx: &mut Context)
-> Result<()>;
// Log after request completes
async fn logging(&self, session: &mut Session, ctx: &mut Context);
}
Routing Module
Routes are compiled at startup for efficient matching:
pub struct RouteMatcher {
routes: Vec<CompiledRoute>, // Sorted by priority
cache: LruCache<String, RouteId>, // Path cache
}
pub struct CompiledRoute {
id: RouteId,
priority: Priority,
matchers: Vec<CompiledMatcher>,
specificity: u32, // For tie-breaking
}
pub enum CompiledMatcher {
Path(String),
PathPrefix(String),
PathRegex(Regex),
Host(String),
Method(Vec<Method>),
Header { name: String, value: Option<String> },
QueryParam { key: String, value: Option<String> },
}
Upstream Module
Manages backend server pools with multiple load balancing strategies:
pub struct UpstreamPool {
id: UpstreamId,
targets: Vec<Target>,
load_balancer: Box<dyn LoadBalancer>,
health_checker: HealthChecker,
circuit_breaker: CircuitBreaker,
connection_pool: ConnectionPool,
}
pub trait LoadBalancer: Send + Sync {
fn select(&self, targets: &[Target], ctx: &RequestContext) -> Option<&Target>;
}
Load Balancing Algorithms:
| Algorithm | Description | Use Case |
|---|---|---|
round_robin | Sequential rotation | General purpose |
least_connections | Fewest active connections | Variable latency backends |
ip_hash | Hash client IP | Session affinity |
consistent_hash | Consistent hashing | Cache distribution |
p2c | Power of Two Choices | Low latency selection |
adaptive | Adjusts based on response times | Mixed workloads |
Agent Module
Coordinates external agent communication:
pub struct AgentManager {
agents: HashMap<AgentId, Agent>,
pools: HashMap<AgentId, AgentPool>,
circuit_breakers: HashMap<AgentId, CircuitBreaker>,
metrics: AgentMetrics,
}
pub struct Agent {
id: AgentId,
transport: AgentTransport,
timeout: Duration,
failure_mode: FailureMode,
events: Vec<EventType>,
}
Config Crate
Package: zentinel-config
Handles configuration parsing, validation, and hot reload.
Supported Formats
- KDL (primary) - Human-friendly document language
- TOML - Standard configuration format
- YAML - For Kubernetes integration
- JSON - For programmatic generation
Configuration Structure
pub struct Config {
pub server: ServerConfig,
pub listeners: Vec<ListenerConfig>,
pub routes: Vec<RouteConfig>,
pub upstreams: HashMap<String, UpstreamConfig>,
pub filters: HashMap<String, FilterConfig>,
pub agents: Vec<AgentConfig>,
pub waf: Option<WafConfig>,
pub limits: Limits,
pub observability: ObservabilityConfig,
}
Key Types
pub struct RouteConfig {
pub id: String,
pub priority: Priority,
pub matches: Vec<MatchCondition>,
pub upstream: Option<String>,
pub service_type: ServiceType,
pub filters: Vec<String>,
pub policies: RoutePolicies,
}
pub struct UpstreamConfig {
pub targets: Vec<TargetConfig>,
pub load_balancing: LoadBalancingAlgorithm,
pub health_check: Option<HealthCheckConfig>,
pub timeouts: TimeoutConfig,
pub circuit_breaker: Option<CircuitBreakerConfig>,
}
pub struct AgentConfig {
pub id: String,
pub agent_type: AgentType,
pub transport: AgentTransport,
pub events: Vec<EventType>,
pub timeout_ms: u64,
pub failure_mode: FailureMode,
}
Validation
Configuration is validated at multiple levels:
- Schema validation - Structure and types
- Semantic validation - Cross-references (route → upstream)
- Custom validators - Business rules
pub trait ConfigValidator {
fn validate(&self, config: &Config) -> Result<(), Vec<ValidationError>>;
}
Hot Reload
Configuration changes are applied atomically:
pub struct ConfigManager {
config: ArcSwap<Config>,
watcher: FileWatcher,
validators: Vec<Box<dyn ConfigValidator>>,
subscribers: Vec<Sender<ReloadEvent>>,
}
pub enum ReloadEvent {
Applied(Arc<Config>),
Failed(ValidationError),
}
Agent Protocol Crate
Package: zentinel-agent-protocol
Defines the contract between Zentinel and external agents.
Transport Options
| Transport | Format | Use Case |
|---|---|---|
| Unix Socket | JSON | Default, same-host agents |
| gRPC | Protobuf | Cross-host, high-performance |
Protocol Types
pub enum EventType {
RequestHeaders,
RequestBodyChunk,
ResponseHeaders,
ResponseBodyChunk,
RequestComplete,
}
pub struct AgentRequest {
pub event_type: EventType,
pub correlation_id: String,
pub request_id: String,
pub metadata: RequestMetadata,
pub headers: Vec<Header>,
pub body_chunk: Option<Vec<u8>>,
}
pub struct AgentResponse {
pub decision: Decision,
pub header_mutations: HeaderMutations,
pub metadata: HashMap<String, String>,
pub audit: AuditInfo,
}
pub enum Decision {
Allow,
Block { status: u16, body: Option<String> },
Redirect { url: String, status: u16 },
Challenge { challenge_type: String, data: String },
}
Header Mutations
Agents can modify request and response headers:
pub struct HeaderMutations {
pub request: HeaderOps,
pub response: HeaderOps,
}
pub struct HeaderOps {
pub set: HashMap<String, String>, // Replace or create
pub add: HashMap<String, String>, // Append
pub remove: Vec<String>, // Delete
}
Client and Server
// Proxy side - manages agent connections
pub struct AgentPool {
agents: HashMap<String, AgentClientV2>,
config: AgentPoolConfig,
}
// Agent side - receives calls
pub struct UdsAgentServerV2 {
name: String,
socket_path: PathBuf,
handler: Box<dyn AgentHandlerV2>,
}
pub trait AgentHandlerV2: Send + Sync {
fn capabilities(&self) -> AgentCapabilities;
async fn on_request_headers(&self, event: RequestHeadersEvent) -> AgentResponse;
// ... other event handlers
}
Common Crate
Package: zentinel-common
Shared types and utilities used across all crates.
Type-Safe IDs
// Strongly typed identifiers prevent mix-ups
pub struct CorrelationId(String);
pub struct RequestId(String);
pub struct RouteId(String);
pub struct UpstreamId(String);
pub struct AgentId(String);
Error Types
pub enum ZentinelError {
Config(ConfigError),
Routing(RoutingError),
Upstream(UpstreamError),
Agent(AgentError),
Validation(ValidationError),
Io(std::io::Error),
}
pub type ZentinelResult<T> = Result<T, ZentinelError>;
Circuit Breaker
pub struct CircuitBreaker {
state: AtomicState,
failure_threshold: u32,
success_threshold: u32,
timeout: Duration,
failure_count: AtomicU32,
success_count: AtomicU32,
last_failure: AtomicInstant,
}
pub enum CircuitState {
Closed, // Normal operation
Open, // Failing, fast-reject
HalfOpen, // Testing recovery
}
Limits
pub struct Limits {
pub max_header_count: usize,
pub max_header_size_bytes: usize,
pub max_body_size_bytes: usize,
pub max_connections_per_client: usize,
pub max_total_connections: usize,
pub max_in_flight_requests: usize,
}
Observability
pub struct RequestMetrics {
pub route_id: RouteId,
pub method: Method,
pub status_code: u16,
pub latency: Duration,
pub upstream_latency: Option<Duration>,
pub bytes_in: u64,
pub bytes_out: u64,
}
Component Interactions
┌─────────────────────────────────────────────────────────────────┐
│ zentinel-proxy │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────────────────┐│
│ │ Routing │ │Upstream │ │ Agents │ │ Static Files ││
│ └────┬────┘ └────┬────┘ └────┬────┘ └─────────────────────┘│
│ │ │ │ │
└───────┼────────────┼────────────┼───────────────────────────────┘
│ │ │
│ │ │
┌───────▼────────────▼────────────▼───────────────────────────────┐
│ zentinel-config │
│ ┌─────────────┐ ┌──────────────┐ ┌────────────────────────┐ │
│ │ Parsing │ │ Validation │ │ Hot Reload │ │
│ └─────────────┘ └──────────────┘ └────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
│
│
┌───────▼─────────────────────────────────────────────────────────┐
│ zentinel-agent-protocol │
│ ┌─────────────┐ ┌──────────────┐ ┌────────────────────────┐ │
│ │ Client │ │ Types │ │ Server │ │
│ └─────────────┘ └──────────────┘ └────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
│
│
┌───────▼─────────────────────────────────────────────────────────┐
│ zentinel-common │
│ ┌─────────┐ ┌──────────┐ ┌─────────┐ ┌──────────────────┐ │
│ │ Types │ │ Errors │ │ Circuit │ │ Observability │ │
│ │ (IDs) │ │ │ │ Breaker │ │ │ │
│ └─────────┘ └──────────┘ └─────────┘ └──────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
Next Steps
- Architecture Overview - High-level design
- Request Flow - Detailed request lifecycle
- Routing System - How routes are matched