This demo showcases usage-based rate limiting for AI workloads, allowing you to control token consumption per user and model. It builds on top of the 01-getting-started demo environment.
This demo demonstrates:
- Token-based rate limiting for LLM requests
- Per-user and per-model limits with different token quotas
- Automatic token tracking from LLM responses
- Rate limit enforcement with 429 status codes when limits are exceeded
kubectlconfigured to access your clustertask(Taskfile) installedjqfor JSON pretty-printing
cd demos/02-usage-based-rate-limiting
task setupThis will:
- Ensure the basic environment from 01-getting-started is running
- Deploy the BackendTrafficPolicy for rate limiting
- Replace the AIGatewayRoute with enhanced token tracking
- Enable support for additional models (gpt-4, gpt-3.5-turbo)
task port-forwardtask test-limits-exceededThis sends rapid requests to test rate limiting. Expected behavior:
- First few requests succeed (200 OK)
- Eventually triggers rate limit (429 status expected, but currently showing all 200s)
- Each successful request shows 6 input tokens + 6 output tokens = 12 total tokens
task metricsThis captures real-time metrics showing:
- Token Usage: qwen3 model consumed 120 tokens (60 input + 60 output) across 10 requests
- Rate Limit Status: Shows requests allowed vs blocked per model
- Extracted Values: Current consumption vs configured limits
task logsCheck gateway logs for rate limiting events and debugging.
The configuration tracks three types of tokens:
- Input tokens: Tokens from the user's prompt
- Output tokens: Tokens generated by the model
- Total tokens: Combined input and output tokens
llmRequestCosts:
- metadataKey: llm_input_token
type: InputToken
- metadataKey: llm_output_token
type: OutputToken
- metadataKey: llm_total_token
type: TotalTokenDifferent models have different token limits per hour:
- gpt-4: 1,000 tokens/hour per user
- gpt-3.5-turbo: 100 tokens/hour per user
- qwen3: 50 tokens/hour per user
Rate limits are applied per user using the x-user-id header:
curl -H "x-user-id: alice" -H "x-ai-eg-model: gpt-4" ...Alice using qwen3 (50 tokens/hour limit):
curl -H "Content-Type: application/json" \
-H "x-user-id: alice" \
-d '{
"model": "qwen3",
"messages": [{"role": "user", "content": "Hello from Alice!"}]
}' \
http://localhost:8080/v1/chat/completionsBob using gpt-3.5-turbo (100 tokens/hour limit):
curl -H "Content-Type: application/json" \
-H "x-user-id: bob" \
-d '{
"model": "gpt-3.5-turbo",
"messages": [{"role": "user", "content": "Hello from Bob!"}]
}' \
http://localhost:8080/v1/chat/completionsNote: The x-ai-eg-model header is not needed when the model is specified in the request body.
# Send multiple requests to test rate limiting
task test-limits-exceededThis task sends 10 rapid requests to test rate limiting. Based on the configuration:
- qwen3: 50 tokens/hour limit
- Each request: ~12 tokens (6 input + 6 output)
- 10 requests: 120 tokens total (240% of limit)
To actually trigger 429 errors, you would need to either:
- Send more requests (>5 requests to exceed 50 tokens)
- Use a different user that has already consumed tokens
- Adjust the rate limit to a lower value for testing
Core Demo Tasks:
task setup- Deploy rate limiting configurationtask port-forward- Start port forwarding to access gatewaytask test-limits-exceeded- Send rapid requests to test rate limitingtask metrics- Capture raw token usage and rate limiting metricstask logs- Show rate limit related logs
Additional Testing:
task test-rate-limits- Run all rate limiting teststask test-user-alice- Test limits for user Alice (qwen3 and gpt-4)task test-user-bob- Test limits for user Bob (gpt-3.5-turbo)task test-streaming- Test streaming with rate limits
Configuration & Cleanup:
task status- View rate limiting configurationtask cleanup- Remove rate limiting configuration
To collect GenAI metrics (token usage, latency, etc.) and rate limiting stats, use the automated metrics task:
Raw Metrics Analysis:
task metricsThis provides:
- Token usage metrics from port 1064 (GenAI metrics endpoint)
- Rate limiting stats from port 19000 (Envoy admin endpoint)
- Extracted values with current token consumption vs limits
- Raw Prometheus metrics for integration with monitoring systems
Sample Output:
=== GenAI Metrics (port 1064) ===
--- Token Usage ---
gen_ai_client_token_usage_token_sum{gen_ai_request_model="qwen3",gen_ai_token_type="total"} 95
gen_ai_client_token_usage_token_count{gen_ai_request_model="qwen3",gen_ai_token_type="total"} 8
=== Rate Limiting Metrics (port 19000) ===
--- Rate Limit Decisions ---
cluster.httproute/default/llm-d-inference-sim-route/rule/0.ratelimit.ok: 8
cluster.httproute/default/llm-d-inference-sim-route/rule/0.ratelimit.over_limit: 1
=== Extracted Values ===
qwen3: input=47 output=48 total=95 count=8 (limit=50/hour)
rule/0 (qwen3): ok=8 over_limit=1
Manual Metrics Collection (advanced):
# Get the Envoy pod name
ENVOY_POD=$(kubectl get pods -n envoy-gateway-system --selector=gateway.envoyproxy.io/owning-gateway-name=envoy-ai-gateway -o jsonpath='{.items[0].metadata.name}')
# Port-forward to metrics endpoints
kubectl port-forward -n envoy-gateway-system $ENVOY_POD 1064:1064 & # GenAI metrics
kubectl port-forward -n envoy-gateway-system $ENVOY_POD 19000:19000 & # Envoy admin
# Collect specific metrics
curl -s http://localhost:1064/metrics | grep gen_ai_client_token_usage
curl -s http://localhost:19000/stats | grep ratelimitToken Consumption (from task metrics):
=== GenAI Metrics (port 1064) ===
--- Token Usage ---
gen_ai_client_token_usage_token_sum{gen_ai_request_model="qwen3",gen_ai_token_type="input"} 60
gen_ai_client_token_usage_token_sum{gen_ai_request_model="qwen3",gen_ai_token_type="output"} 60
gen_ai_client_token_usage_token_sum{gen_ai_request_model="qwen3",gen_ai_token_type="total"} 120
gen_ai_client_token_usage_token_count{gen_ai_request_model="qwen3",gen_ai_token_type="total"} 10
=== Extracted Values ===
qwen3: input=60 output=60 total=120 count=10 (limit=50/hour)
Rate Limiting Behavior:
- 10 requests sent to qwen3 model
- Each request consumed 12 tokens (6 input + 6 output)
- Total consumption: 120 tokens out of 50/hour limit (60% utilized)
- All requests returned 200 OK (rate limit not yet triggered)
Note: To trigger 429 rate limit errors, you would need to:
- Send more requests to exceed the 50 token/hour limit
- Or adjust the rate limit configuration to a lower threshold
-
Route Enhancement: Demo 02 replaces the AIGatewayRoute from demo 01:
- Adds
llmRequestCostsconfiguration for token tracking - Extends support to additional models while preserving the original qwen3 route
- Adds
-
Request Processing: When a request arrives, the gateway extracts:
- User ID from
x-user-idheader - Model from
x-ai-eg-modelheader
- User ID from
-
Token Tracking: The AI Gateway automatically:
- Extracts token usage from LLM responses
- Updates the user's token consumption
-
Rate Limit Check: Before processing:
- Checks if the user has remaining tokens
- Rejects requests that would exceed limits
-
Response:
- Successful requests are processed normally
- Rate-limited requests receive 429 status
┌─────────────┐ ┌─────────────────┐ ┌──────────────────┐
│ Client │────▶│ Envoy AI │────▶│ LLM Backend │
│ (w/ user-id)│ │ Gateway │ │ │
└─────────────┘ └─────────────────┘ └──────────────────┘
│
▼
┌─────────────────┐
│ Rate Limiter │
│ (Token-based) │
└─────────────────┘
- Ensure you're including the
x-user-idheader - Check that the model name in
x-ai-eg-modelmatches configuration - Verify the BackendTrafficPolicy is applied:
task status
- The rate limiter may have residual state from previous tests
- Wait a few minutes or use a different user ID
- The LLM-D simulator returns mock token counts
- With real LLM backends, token counts will be accurate
You can implement custom token cost calculations using CEL expressions:
llmRequestCosts:
- metadataKey: custom_cost
celExpression: "has(llm_input_token) ? llm_input_token * 2 : 0"Modify the rate limit time window:
limit:
requests: 1000
unit: Minute # or Hour, DayTo remove the rate limiting configuration:
task cleanupThis will:
- Remove the BackendTrafficPolicy
- Revert the AIGatewayRoute to its original demo 01 configuration
- Preserve the base environment from 01-getting-started
- Implement different rate limits for different user tiers
- Add token cost calculations based on model pricing
- Configure rate limiting with Redis for distributed deployments
- Combine with authentication for production use