HeliosDB Multi-Tenancy
HeliosDB Multi-Tenancy
A comprehensive multi-tenancy system with logical isolation, resource quotas, and Quality of Service (QoS) tiers for HeliosDB v3.0.
Features
Core Capabilities
- Logical Isolation: Separate database namespaces for each tenant with strict access control
- Resource Quotas: CPU, memory, storage, table, and index limits per tenant
- QoS Tiers: Free, Pro, and Enterprise tiers with different resource allocations
- Fair Scheduling: Weighted fair queuing to prevent starvation
- Usage Tracking: Real-time metering for billing and monitoring
- Rate Limiting: Per-tenant query, write, and bandwidth limits
- Dynamic Tier Management: Upgrade/downgrade tenants on the fly
Isolation Guarantees
- Logical: Separate database namespaces per tenant
- Performance: Resource quotas prevent noisy neighbor problems
- Security: Separate credentials and access control per tenant
- Data: Complete isolation - no cross-tenant data access
Architecture
┌─────────────────────────────────────────────┐│ MultiTenantManager │├─────────────────────────────────────────────┤│ - Tenant Management ││ - Quota Enforcement ││ - Usage Tracking ││ - Scheduling Coordination │└─────────────────────────────────────────────┘ │ ├─────────────┬──────────────┬──────────────┬──────────────┬──────────────┐ │ │ │ │ │ │ ┌─────▼─────┐ ┌────▼────┐ ┌──────▼──────┐ ┌────▼────┐ ┌─────▼──────┐ ┌────▼─────┐ │ Isolation │ │ Quotas │ │ Scheduler │ │ Limits │ │ Accounting │ │ Tier │ │ Manager │ │ Manager │ │ (Fair) │ │ Manager │ │ Manager │ │ Manager │ └───────────┘ └─────────┘ └─────────────┘ └─────────┘ └────────────┘ └──────────┘QoS Tiers
Free Tier
- CPU: 5% max, 0.5% guaranteed
- Memory: 512 MB
- Storage: 1 GB
- Tables: 10 max
- Indexes: 20 max
- Query Timeout: 30 seconds
- Rate Limits: 10 queries/sec, 5 writes/sec, 1 Mbps
Pro Tier
- CPU: 20% max, 2% guaranteed
- Memory: 4 GB
- Storage: 100 GB
- Tables: 100 max
- Indexes: 200 max
- Query Timeout: 300 seconds
- Rate Limits: 100 queries/sec, 50 writes/sec, 10 Mbps
Enterprise Tier
- CPU: 50% max, 5% guaranteed
- Memory: 32 GB
- Storage: 1 TB
- Tables: 1000 max
- Indexes: 2000 max
- Query Timeout: 3600 seconds
- Rate Limits: 1000 queries/sec, 500 writes/sec, 100 Mbps
Usage
Basic Example
use heliosdb_multitenancy::*;
#[tokio::main]async fn main() -> Result<()> { // Create manager let manager = MultiTenantManager::new().await?;
// Create a tenant let config = TenantConfig::new("my_tenant".to_string(), TenantTier::Pro); manager.create_tenant(config).await?;
// Schedule a query let query = Query::new( "my_tenant".to_string(), "SELECT * FROM users".to_string(), 5 ); let handle = manager.schedule_query("my_tenant", query).await?;
// Record usage manager.record_usage("my_tenant", Usage::Query).await?; manager.record_usage("my_tenant", Usage::Cpu { seconds: 10.0 }).await?;
// Get usage metrics let usage = manager.get_usage("my_tenant").await?; println!("CPU used: {} seconds", usage.cpu_seconds); println!("Queries: {}", usage.queries_count);
Ok(())}Tier Management
// Create with Free tierlet config = TenantConfig::new("tenant1".to_string(), TenantTier::Free);manager.create_tenant(config).await?;
// Upgrade to Promanager.update_tier("tenant1", TenantTier::Pro).await?;
// Upgrade to Enterprisemanager.update_tier("tenant1", TenantTier::Enterprise).await?;Custom Quotas
// Assign custom quotas (overrides tier defaults)let custom = ResourceQuotas { max_cpu_percent: 30.0, max_memory_mb: 8192, max_storage_gb: 200, max_tables: 150, max_indexes: 300, query_timeout_secs: 600,};
manager.set_quotas("tenant1", custom).await?;Usage Tracking
// Record different types of usagemanager.record_usage("tenant1", Usage::Cpu { seconds: 100.0 }).await?;manager.record_usage("tenant1", Usage::Memory { mb: 2048, duration_hours: 1.0 }).await?;manager.record_usage("tenant1", Usage::Storage { gb: 50 }).await?;manager.record_usage("tenant1", Usage::Query).await?;manager.record_usage("tenant1", Usage::Write).await?;manager.record_usage("tenant1", Usage::Bandwidth { mb: 500 }).await?;
// Get usage metricslet usage = manager.get_usage("tenant1").await?;
// Calculate costlet pricing = PricingModel::new();let cost = pricing.calculate(&usage);Fair Scheduling
// Queries from higher tier tenants get scheduled first// but lower tier tenants are never starved
let query1 = Query::new("free_tenant".to_string(), "SELECT 1".to_string(), 1);let query2 = Query::new("enterprise_tenant".to_string(), "SELECT 2".to_string(), 10);
manager.schedule_query("free_tenant", query1).await?;manager.schedule_query("enterprise_tenant", query2).await?;
// Enterprise query will be scheduled first due to higher weight// But free tier queries get aging boost to prevent starvationQuota Checking
// Check if tenant is within quotalet within_cpu = manager.check_quota("tenant1", Resource::Cpu).await?;let within_memory = manager.check_quota("tenant1", Resource::Memory).await?;let within_storage = manager.check_quota("tenant1", Resource::Storage).await?;
if !within_cpu { println!("Tenant has exceeded CPU quota");}API Reference
MultiTenantManager
Tenant Management
create_tenant(config: TenantConfig) -> Result<()>delete_tenant(tenant_id: &str) -> Result<()>update_tier(tenant_id: &str, tier: TenantTier) -> Result<()>get_tenant(tenant_id: &str) -> Result<TenantConfig>list_tenants() -> Vec<String>
Quota Management
set_quotas(tenant_id: &str, quotas: ResourceQuotas) -> Result<()>check_quota(tenant_id: &str, resource: Resource) -> Result<bool>
Usage Tracking
record_usage(tenant_id: &str, usage: Usage) -> Result<()>get_usage(tenant_id: &str) -> Result<UsageMetrics>
Scheduling
schedule_query(tenant_id: &str, query: Query) -> Result<QueryHandle>
Types
TenantTier
pub enum TenantTier { Free, Pro, Enterprise,}Resource
pub enum Resource { Cpu, Memory, Storage, Tables, Indexes,}Usage
pub enum Usage { Cpu { seconds: f64 }, Memory { mb: u64, duration_hours: f64 }, Storage { gb: u64 }, Query, Write, Bandwidth { mb: u64 },}Fair Scheduling Algorithm
The scheduler uses Weighted Fair Queuing (WFQ) with anti-starvation:
- Weight Calculation: Each tier has a weight (Free: 1.0, Pro: 5.0, Enterprise: 10.0)
- Priority Boosting: Queries get priority boost based on age (max +5 after 5 minutes)
- Effective Priority:
base_priority × weight + age_boost - Guaranteed CPU: Each tier gets minimum CPU even under contention
This ensures:
- Higher tier tenants get preferential treatment
- Lower tier tenants are never completely starved
- Fairness across all tenants over time
Usage Metrics
The system tracks the following metrics per tenant:
- CPU Seconds: Total CPU time consumed
- Memory MB-Hours: Memory usage over time
- Storage GB: Current storage utilization
- Query Count: Total queries executed
- Write Count: Total write operations
- Bandwidth MB: Total data transferred
Billing Integration
// Define pricing modellet pricing = PricingModel { cpu_per_second: 0.0001, // $0.0001 per CPU second memory_per_mb_hour: 0.00001, // $0.00001 per MB-hour storage_per_gb: 0.10, // $0.10 per GB/month query_per_1000: 0.001, // $0.001 per 1000 queries write_per_1000: 0.002, // $0.002 per 1000 writes bandwidth_per_gb: 0.09, // $0.09 per GB bandwidth};
// Calculate costlet usage = manager.get_usage("tenant1").await?;let cost = pricing.calculate(&usage);Testing
Run unit tests:
cargo testRun integration tests:
cargo test --test integration_testRun with logging:
RUST_LOG=debug cargo testExamples
Run the example:
cargo run --example multi_tenantPerformance
- Tenant Creation: O(1)
- Query Scheduling: O(log n) where n = queue size
- Quota Checking: O(1)
- Usage Recording: O(1)
- Rate Limiting: O(1)
All operations are designed for high concurrency using lock-free data structures where possible.
Thread Safety
All components are thread-safe and can be safely shared across multiple threads:
- Uses
Arcfor shared ownership - Uses
DashMapfor concurrent hash maps - Uses
RwLockfor read-heavy workloads - Uses atomic operations for counters
Error Handling
pub enum MultiTenancyError { TenantNotFound(String), TenantAlreadyExists(String), QuotaExceeded { tenant_id: String, resource: String }, RateLimitExceeded(String), InvalidConfiguration(String), IsolationViolation(String), SchedulingError(String), InternalError(String),}Best Practices
- Always check quotas before allowing resource-intensive operations
- Record usage immediately after operations complete
- Use appropriate tier for each tenant’s needs
- Monitor usage metrics regularly to detect anomalies
- Set custom quotas when standard tiers don’t fit
- Clean up tenants properly using
delete_tenant() - Handle errors appropriately (especially QuotaExceeded)
License
MIT OR Apache-2.0