diff --git a/app/games/scaling-simulator/page.tsx b/app/games/scaling-simulator/page.tsx new file mode 100644 index 00000000..3d33a921 --- /dev/null +++ b/app/games/scaling-simulator/page.tsx @@ -0,0 +1,148 @@ +import type { Metadata } from 'next'; +import { Breadcrumb } from '@/components/breadcrumb'; +import { BreadcrumbSchema } from '@/components/schema-markup'; +import ScalingSimulator from '@/components/games/scaling-simulator'; +import { Twitter, Facebook, Linkedin } from 'lucide-react'; +import { generateGameMetadata } from '@/lib/game-metadata'; +import { getGameById } from '@/lib/games'; + +export async function generateMetadata(): Promise { + return generateGameMetadata('scaling-simulator'); +} + +export default async function ScalingSimulatorPage() { + const game = await getGameById('scaling-simulator'); + const gameTitle = game?.title || 'Horizontal vs Vertical Scaling Simulator'; + + const breadcrumbItems = [ + { label: 'Games', href: '/games' }, + { label: gameTitle, href: '/games/scaling-simulator', isCurrent: true }, + ]; + + const schemaItems = [ + { name: 'Home', url: '/' }, + { name: 'Games', url: '/games' }, + { name: gameTitle, url: '/games/scaling-simulator' }, + ]; + + return ( + <> + + +
+ + +
+

+ Horizontal vs Vertical Scaling Simulator - Learn Scaling Strategies +

+ + + +
+

Understanding Scaling Strategies

+
+
+

What You'll Learn

+
    +
  • Horizontal scaling (scale out) vs vertical scaling (scale up)
  • +
  • When to use each scaling strategy based on workload
  • +
  • Impact on performance, cost, and reliability
  • +
  • Auto-scaling configuration and benefits
  • +
  • Load distribution with horizontal scaling
  • +
  • Budget management and cost optimization
  • +
+
+
+

Scaling Strategies

+
+
+ Vertical Scaling: Increase server + resources (CPU, RAM, disk) - simple but limited +
+
+ Horizontal Scaling: Add more + servers with load balancer - unlimited but complex +
+
+ Auto-Scaling: Automatically + adjust capacity based on demand +
+
+ Hybrid Approach: Combine both + strategies for optimal results +
+
+
+
+ +
+

💡 Real-World Applications

+
    +
  • + • AWS EC2: Use Auto Scaling Groups with ELB for horizontal + scaling +
  • +
  • + • Kubernetes: Horizontal Pod Autoscaler (HPA) for container + workloads +
  • +
  • + • Databases: Read replicas (horizontal) vs larger instances + (vertical) +
  • +
  • + • Serverless: Automatic scaling without managing servers +
  • +
+
+ +
+

🎯 Best Practices

+
    +
  • • Start with vertical scaling for simplicity, then scale horizontally
  • +
  • • Use auto-scaling to handle traffic spikes cost-effectively
  • +
  • • Set appropriate cooldown periods to avoid scaling thrashing
  • +
  • • Monitor key metrics: CPU, memory, response time, error rate
  • +
  • • Design stateless applications for easier horizontal scaling
  • +
+
+
+ + +
+
+ + ); +} diff --git a/components/games/scaling-simulator.tsx b/components/games/scaling-simulator.tsx new file mode 100644 index 00000000..bbae8416 --- /dev/null +++ b/components/games/scaling-simulator.tsx @@ -0,0 +1,1222 @@ +'use client'; + +import React, { useState, useEffect, useCallback, useRef } from 'react'; +import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; +import { Button } from '@/components/ui/button'; +import { Badge } from '@/components/ui/badge'; +import { Slider } from '@/components/ui/slider'; +import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; +import { + Play, + Pause, + RotateCcw, + Server, + Cpu, + HardDrive, + Zap, + DollarSign, + Users, + Activity, + AlertTriangle, + CheckCircle, + TrendingUp, + TrendingDown, + Plus, + Minus, + Settings, + Info, +} from 'lucide-react'; + +// Types +interface ServerInstance { + id: string; + cpuCores: number; + ramGB: number; + diskType: 'HDD' | 'SSD' | 'NVMe'; + networkGbps: number; + currentLoad: number; + requestsHandled: number; + status: 'healthy' | 'overloaded' | 'starting' | 'stopping'; + startTime: number; +} + +interface ScalingConfig { + autoScalingEnabled: boolean; + minInstances: number; + maxInstances: number; + cpuThreshold: number; + scaleUpDelay: number; + scaleDownDelay: number; +} + +interface Metrics { + totalRequests: number; + successfulRequests: number; + failedRequests: number; + avgResponseTime: number; + currentRPS: number; + uptime: number; +} + +interface Scenario { + id: string; + name: string; + description: string; + difficulty: 'Easy' | 'Medium' | 'Hard' | 'Expert'; + trafficPattern: (time: number) => number; + budget: number; + targetResponseTime: number; + duration: number; +} + +// Pricing (monthly cost approximations) +const PRICING = { + cpu: { 2: 15, 4: 30, 8: 60, 16: 120 }, + ram: { 4: 10, 8: 20, 16: 40, 32: 80, 64: 160 }, + disk: { HDD: 5, SSD: 15, NVMe: 30 }, + network: { 1: 0, 10: 25 }, + loadBalancer: 25, + autoScaling: 10, +}; + +// Scenarios +const SCENARIOS: Scenario[] = [ + { + id: 'gradual', + name: 'Gradual Growth', + description: 'Linear traffic increase from 100 to 500 users/sec', + difficulty: 'Easy', + trafficPattern: (time) => Math.min(100 + time * 2, 500), + budget: 200, + targetResponseTime: 200, + duration: 200, + }, + { + id: 'spike', + name: 'Sudden Spike', + description: 'Traffic jumps from 100 to 1000 users/sec instantly', + difficulty: 'Medium', + trafficPattern: (time) => (time < 30 ? 100 : 1000), + budget: 300, + targetResponseTime: 200, + duration: 150, + }, + { + id: 'variable', + name: 'Variable Load', + description: 'Unpredictable traffic: 50 → 500 → 100 → 800', + difficulty: 'Hard', + trafficPattern: (time) => { + const phase = Math.floor(time / 40) % 4; + const patterns = [50, 500, 100, 800]; + return patterns[phase]; + }, + budget: 350, + targetResponseTime: 200, + duration: 200, + }, + { + id: 'blackfriday', + name: 'Black Friday', + description: 'Massive spike: 100 → 5000 users/sec with budget constraints', + difficulty: 'Expert', + trafficPattern: (time) => { + if (time < 20) return 100; + if (time < 40) return 100 + (time - 20) * 245; + return 5000; + }, + budget: 500, + targetResponseTime: 300, + duration: 180, + }, +]; + +// Helper functions +const calculateServerCapacity = (server: ServerInstance): number => { + const cpuFactor = server.cpuCores * 50; + const ramFactor = server.ramGB * 10; + const diskFactor = server.diskType === 'NVMe' ? 1.5 : server.diskType === 'SSD' ? 1.2 : 1; + return Math.floor(cpuFactor + ramFactor) * diskFactor; +}; + +const calculateServerCost = (server: ServerInstance): number => { + const cpuCost = PRICING.cpu[server.cpuCores as keyof typeof PRICING.cpu] || 15; + const ramCost = PRICING.ram[server.ramGB as keyof typeof PRICING.ram] || 10; + const diskCost = PRICING.disk[server.diskType]; + const networkCost = PRICING.network[server.networkGbps as keyof typeof PRICING.network] || 0; + return cpuCost + ramCost + diskCost + networkCost; +}; + +const calculateResponseTime = (load: number): number => { + if (load < 0.5) return 50 + load * 100; + if (load < 0.8) return 100 + (load - 0.5) * 200; + if (load < 1) return 160 + (load - 0.8) * 500; + return 260 + (load - 1) * 1000; +}; + +export default function ScalingSimulator() { + // State + const [scenario, setScenario] = useState(SCENARIOS[0]); + const [isRunning, setIsRunning] = useState(false); + const [time, setTime] = useState(0); + const [speed, setSpeed] = useState(1); + const [servers, setServers] = useState([]); + const [hasLoadBalancer, setHasLoadBalancer] = useState(false); + const [scalingConfig, setScalingConfig] = useState({ + autoScalingEnabled: false, + minInstances: 1, + maxInstances: 10, + cpuThreshold: 70, + scaleUpDelay: 5, + scaleDownDelay: 300, + }); + const [metrics, setMetrics] = useState({ + totalRequests: 0, + successfulRequests: 0, + failedRequests: 0, + avgResponseTime: 0, + currentRPS: 0, + uptime: 100, + }); + const [budget, setBudget] = useState(0); + const [trafficHistory, setTrafficHistory] = useState([]); + const [responseTimeHistory, setResponseTimeHistory] = useState([]); + const [showEducation, setShowEducation] = useState(false); + const [activeTab, setActiveTab] = useState('vertical'); + const [gameResult, setGameResult] = useState<'playing' | 'won' | 'lost'>('playing'); + const scaleUpTimer = useRef(null); + const scaleDownTimer = useRef(null); + + // Initialize with one server + useEffect(() => { + if (servers.length === 0) { + addServer(); + } + }, []); + + // Calculate total costs + const totalCost = useCallback(() => { + let cost = servers.reduce((sum, s) => sum + calculateServerCost(s), 0); + if (hasLoadBalancer) cost += PRICING.loadBalancer; + if (scalingConfig.autoScalingEnabled) cost += PRICING.autoScaling; + return cost; + }, [servers, hasLoadBalancer, scalingConfig.autoScalingEnabled]); + + // Add a new server + const addServer = useCallback(() => { + // Limit to maxInstances servers + if (servers.length >= scalingConfig.maxInstances) { + return; + } + const newServer: ServerInstance = { + id: `server-${Date.now()}`, + cpuCores: 2, + ramGB: 4, + diskType: 'SSD', + networkGbps: 1, + currentLoad: 0, + requestsHandled: 0, + status: servers.length === 0 ? 'healthy' : 'starting', + startTime: time, + }; + setServers((prev) => [...prev, newServer]); + + // Server startup time (30 seconds simulation) + if (servers.length > 0) { + setTimeout(() => { + setServers((prev) => + prev.map((s) => (s.id === newServer.id ? { ...s, status: 'healthy' } : s)) + ); + }, 3000 / speed); + } + }, [servers.length, time, speed, scalingConfig.maxInstances]); + + // Remove a server + const removeServer = useCallback( + (serverId: string) => { + if (servers.length <= 1) return; + setServers((prev) => + prev.map((s) => (s.id === serverId ? { ...s, status: 'stopping' } : s)) + ); + setTimeout(() => { + setServers((prev) => prev.filter((s) => s.id !== serverId)); + }, 2000 / speed); + }, + [servers.length, speed] + ); + + // Upgrade server specs + const upgradeServer = useCallback( + (serverId: string, upgrade: Partial) => { + // Vertical scaling requires downtime + setServers((prev) => + prev.map((s) => (s.id === serverId ? { ...s, status: 'stopping' } : s)) + ); + setTimeout(() => { + setServers((prev) => + prev.map((s) => + s.id === serverId ? { ...s, ...upgrade, status: 'starting' } : s + ) + ); + }, 1500 / speed); + setTimeout(() => { + setServers((prev) => + prev.map((s) => (s.id === serverId ? { ...s, status: 'healthy' } : s)) + ); + }, 3000 / speed); + }, + [speed] + ); + + // Game loop + useEffect(() => { + if (!isRunning) return; + + const interval = setInterval(() => { + setTime((t) => { + const newTime = t + 1; + if (newTime >= scenario.duration) { + setIsRunning(false); + // Check win condition + if (metrics.uptime >= 95 && totalCost() <= scenario.budget) { + setGameResult('won'); + } else { + setGameResult('lost'); + } + } + return newTime; + }); + + // Calculate current traffic + const currentTraffic = scenario.trafficPattern(time); + setTrafficHistory((prev) => [...prev.slice(-60), currentTraffic]); + + // Distribute load across healthy servers + const healthyServers = servers.filter((s) => s.status === 'healthy'); + if (healthyServers.length === 0) { + setMetrics((prev) => ({ + ...prev, + failedRequests: prev.failedRequests + currentTraffic, + totalRequests: prev.totalRequests + currentTraffic, + currentRPS: currentTraffic, + uptime: Math.max(0, prev.uptime - 5), + })); + return; + } + + const totalCapacity = healthyServers.reduce( + (sum, s) => sum + calculateServerCapacity(s), + 0 + ); + const overallLoad = currentTraffic / totalCapacity; + + // Calculate what the new server loads will be + const newServerLoads = healthyServers.map((s) => { + const serverCapacity = calculateServerCapacity(s); + return hasLoadBalancer + ? currentTraffic / healthyServers.length / serverCapacity + : currentTraffic / serverCapacity; + }); + const avgLoad = newServerLoads.length > 0 + ? newServerLoads.reduce((sum, load) => sum + load, 0) / newServerLoads.length + : 0; + + // Update server loads in state + setServers((prev) => + prev.map((s) => { + if (s.status !== 'healthy') return s; + const serverCapacity = calculateServerCapacity(s); + const serverLoad = hasLoadBalancer + ? currentTraffic / healthyServers.length / serverCapacity + : currentTraffic / serverCapacity; + return { + ...s, + currentLoad: Math.min(serverLoad, 2), + requestsHandled: s.requestsHandled + Math.floor(currentTraffic / healthyServers.length), + status: serverLoad > 1.5 ? 'overloaded' : 'healthy', + }; + }) + ); + + // Calculate response time and update metrics + const responseTime = calculateResponseTime(avgLoad); + setResponseTimeHistory((prev) => [...prev.slice(-60), responseTime]); + + const failedThisSecond = + overallLoad > 1 ? Math.floor((overallLoad - 1) * currentTraffic) : 0; + const successfulThisSecond = currentTraffic - failedThisSecond; + + setMetrics((prev) => { + const newTotal = prev.totalRequests + currentTraffic; + const newSuccessful = prev.successfulRequests + successfulThisSecond; + const newFailed = prev.failedRequests + failedThisSecond; + return { + totalRequests: newTotal, + successfulRequests: newSuccessful, + failedRequests: newFailed, + avgResponseTime: Math.round( + (prev.avgResponseTime * prev.totalRequests + responseTime * currentTraffic) / + newTotal + ), + currentRPS: currentTraffic, + uptime: newTotal > 0 ? (newSuccessful / newTotal) * 100 : 100, + }; + }); + + // Auto-scaling logic + if (scalingConfig.autoScalingEnabled && hasLoadBalancer) { + const avgCpuUsage = avgLoad * 100; + + // Scale up to meet minimum instances requirement + if (healthyServers.length < scalingConfig.minInstances) { + if (!scaleUpTimer.current) { + scaleUpTimer.current = window.setTimeout(() => { + addServer(); + scaleUpTimer.current = null; + }, (scalingConfig.scaleUpDelay * 1000) / speed); + } + } + // Scale up based on CPU threshold + else if (avgCpuUsage > scalingConfig.cpuThreshold && healthyServers.length < scalingConfig.maxInstances) { + if (!scaleUpTimer.current) { + scaleUpTimer.current = window.setTimeout(() => { + addServer(); + scaleUpTimer.current = null; + }, (scalingConfig.scaleUpDelay * 1000) / speed); + } + } else if (scaleUpTimer.current) { + clearTimeout(scaleUpTimer.current); + scaleUpTimer.current = null; + } + + if ( + avgCpuUsage < scalingConfig.cpuThreshold / 2 && + healthyServers.length > scalingConfig.minInstances + ) { + if (!scaleDownTimer.current) { + scaleDownTimer.current = window.setTimeout(() => { + const serverToRemove = healthyServers[healthyServers.length - 1]; + if (serverToRemove) removeServer(serverToRemove.id); + scaleDownTimer.current = null; + }, (scalingConfig.scaleDownDelay * 1000) / speed); + } + } else if (scaleDownTimer.current) { + clearTimeout(scaleDownTimer.current); + scaleDownTimer.current = null; + } + } + }, 1000 / speed); + + return () => clearInterval(interval); + }, [isRunning, time, scenario, servers, hasLoadBalancer, scalingConfig, speed, addServer, removeServer, metrics, totalCost]); + + // Immediately scale to minInstances when auto-scaling is enabled + useEffect(() => { + if (!scalingConfig.autoScalingEnabled || !hasLoadBalancer) return; + + const healthyServers = servers.filter((s) => s.status === 'healthy' || s.status === 'starting'); + + // Scale up if below minimum + if (healthyServers.length < scalingConfig.minInstances) { + const timer = setTimeout(() => { + addServer(); + }, 500); + return () => clearTimeout(timer); + } + }, [scalingConfig.autoScalingEnabled, scalingConfig.minInstances, hasLoadBalancer, servers, addServer, removeServer]); + + // Reset game + const reset = useCallback(() => { + setIsRunning(false); + setTime(0); + setServers([]); + setHasLoadBalancer(false); + setScalingConfig({ + autoScalingEnabled: false, + minInstances: 1, + maxInstances: 10, + cpuThreshold: 70, + scaleUpDelay: 5, + scaleDownDelay: 300, + }); + setMetrics({ + totalRequests: 0, + successfulRequests: 0, + failedRequests: 0, + avgResponseTime: 0, + currentRPS: 0, + uptime: 100, + }); + setTrafficHistory([]); + setResponseTimeHistory([]); + setGameResult('playing'); + // Add initial server after reset + setTimeout(() => { + setServers([{ + id: `server-${Date.now()}`, + cpuCores: 2, + ramGB: 4, + diskType: 'SSD', + networkGbps: 1, + currentLoad: 0, + requestsHandled: 0, + status: 'healthy', + startTime: 0, + }]); + }, 0); + }, []); + + const currentCost = totalCost(); + const budgetUsed = (currentCost / scenario.budget) * 100; + + return ( +
+ + +
+
+ + + Horizontal vs Vertical Scaling Simulator + +

+ Learn scaling strategies by managing traffic under real-world conditions +

+
+ +
+
+ + {/* Educational Panel */} + {showEducation && ( +
+
+

+ + Vertical Scaling (Scale Up) +

+
    +
  • ✓ Increase resources on existing server
  • +
  • ✓ Simple, no architecture changes
  • +
  • ✓ No data sync issues
  • +
  • ✗ Hard limits (biggest machine)
  • +
  • ✗ Single point of failure
  • +
  • ✗ Downtime during upgrades
  • +
+
+
+

+ + Horizontal Scaling (Scale Out) +

+
    +
  • ✓ Add more servers
  • +
  • ✓ Nearly unlimited scaling
  • +
  • ✓ No single point of failure
  • +
  • ✓ Zero-downtime scaling
  • +
  • ✗ Requires load balancer
  • +
  • ✗ More complex architecture
  • +
+
+
+ )} + + {/* Scenario Selection */} +
+
+ Scenario: +
+ {SCENARIOS.map((s) => ( + + ))} +
+
+
+ + {/* Controls */} +
+ + +
+ Speed: + {[1, 2, 5, 10].map((s) => ( + + ))} +
+
+
+ Time: + + {time}s / {scenario.duration}s + +
+
+
+ + {/* Game Result */} + {gameResult !== 'playing' && ( +
+
+ {gameResult === 'won' ? ( + + ) : ( + + )} + + {gameResult === 'won' ? 'Success!' : 'Challenge Failed'} + +
+

+ {gameResult === 'won' + ? `You maintained ${metrics.uptime.toFixed(1)}% uptime within budget ($${currentCost}/$${scenario.budget})` + : `Uptime: ${metrics.uptime.toFixed(1)}% (target: 95%) | Cost: $${currentCost}/$${scenario.budget}`} +

+
+ )} + + {/* Main Dashboard */} +
+
+
+ + Current Traffic +
+
{metrics.currentRPS} req/s
+
+
+
+ + Avg Response Time +
+
scenario.targetResponseTime + ? 'text-red-500' + : 'text-green-500' + }`} + > + {metrics.avgResponseTime}ms +
+
+ Target: {'<'}{scenario.targetResponseTime}ms +
+
+
+
+ + Uptime +
+
+ {metrics.uptime.toFixed(1)}% +
+
Target: {'>'}95%
+
+
+
+ + Monthly Cost +
+
scenario.budget ? 'text-red-500' : 'text-green-500' + }`} + > + ${currentCost} +
+
Budget: ${scenario.budget}
+
+
+ + {/* Budget Bar */} +
+
+ Budget Usage + 100 ? 'text-red-500' : ''} + > + ${currentCost} / ${scenario.budget} + +
+
+
100 + ? 'bg-red-500' + : budgetUsed > 80 + ? 'bg-yellow-500' + : 'bg-green-500' + }`} + style={{ width: `${Math.min(budgetUsed, 100)}%` }} + /> +
+
+ + {/* Scaling Controls */} + + + Vertical Scaling + Horizontal Scaling + Auto-Scaling + + + +

+ Upgrade individual server specs. Note: Upgrades require ~30s downtime. +

+ + {/* Pricing Reference */} +
+

+ + Pricing Reference (Monthly) +

+
+
+
+ CPU Cores +
+
+
2 cores$15
+
4 cores$30
+
8 cores$60
+
16 cores$120
+
+
+
+
+ RAM +
+
+
4 GB$10
+
8 GB$20
+
16 GB$40
+
32 GB$80
+
64 GB$160
+
+
+
+
+ Disk Type +
+
+
HDD$5
+
SSD$15
+
NVMe$30
+
+
+
+
+ Network +
+
+
1 Gbps$0
+
10 Gbps$25
+
+
+
+
+ + {servers.map((server, index) => ( +
+
+
+ + Server {index + 1} + + {server.status} + +
+ + ${calculateServerCost(server)}/mo + +
+ + {/* Load Bar */} +
+
+ Load + {Math.round(server.currentLoad * 100)}% +
+
+
1 + ? 'bg-red-500' + : server.currentLoad > 0.8 + ? 'bg-yellow-500' + : 'bg-green-500' + }`} + style={{ width: `${Math.min(server.currentLoad * 100, 100)}%` }} + /> +
+
+ + {/* Upgrade Options */} +
+
+ +
+ + {server.cpuCores} + +
+
+
+ +
+ + {server.ramGB} + +
+
+
+ +
+ {(['HDD', 'SSD', 'NVMe'] as const).map((disk) => ( + + ))} +
+
+
+ +
+ {calculateServerCapacity(server)} req/s +
+
+
+
+ ))} + + + +
+

+ Add or remove servers. Requires a load balancer for traffic distribution. +

+
+ +
+
+ + {!hasLoadBalancer && servers.length > 1 && ( +
+ + Without a load balancer, all traffic goes to the first server! +
+ )} + +
+ {servers.map((server, index) => ( +
+
+
+ + Server {index + 1} +
+ {servers.length > 1 && ( + + )} +
+
+
+ Status + + {server.status} + +
+
+ Load + {Math.round(server.currentLoad * 100)}% +
+
+ Requests + {server.requestsHandled.toLocaleString()} +
+
+ Capacity + {calculateServerCapacity(server)} req/s +
+
+
+ ))} + + {servers.length > 1 && ( + + )} +
+
+ + +
+

+ Configure automatic scaling based on CPU threshold. +

+ +
+ + {!hasLoadBalancer && ( +
+ + Auto-scaling requires a load balancer to be enabled first. +
+ )} + + {hasLoadBalancer && ( +
+
+
+ +

+ Scale up when CPU exceeds this threshold +

+
+ + setScalingConfig((prev) => ({ ...prev, cpuThreshold: value })) + } + min={50} + max={90} + step={5} + className="flex-1" + /> + + {scalingConfig.cpuThreshold}% + +
+
+
+ +
+ + setScalingConfig((prev) => ({ ...prev, minInstances: value })) + } + min={1} + max={5} + step={1} + className="flex-1" + /> + + {scalingConfig.minInstances} + +
+
+
+ +
+ + setScalingConfig((prev) => ({ ...prev, maxInstances: value })) + } + min={2} + max={20} + step={1} + className="flex-1" + /> + + {scalingConfig.maxInstances} + +
+
+
+
+

+ + Current Configuration +

+
+
+ Status + + {scalingConfig.autoScalingEnabled ? 'Active' : 'Disabled'} + +
+
+ Scale Up Trigger + CPU {'>'} {scalingConfig.cpuThreshold}% +
+
+ Scale Down Trigger + CPU {'<'} {scalingConfig.cpuThreshold / 2}% +
+
+ Instance Range + + {scalingConfig.minInstances} - {scalingConfig.maxInstances} + +
+
+ Current Instances + {servers.length} +
+
+
+
+ )} +
+ + + {/* Traffic Visualization */} +
+

Traffic Pattern (Last 60s)

+
+ {trafficHistory.map((traffic, i) => ( +
+ ))} + {trafficHistory.length === 0 && ( +
+ Start simulation to see traffic +
+ )} +
+
+ + {/* Stats Summary */} +
+
+
Total Requests
+
+ {metrics.totalRequests.toLocaleString()} +
+
+
+
Successful
+
+ {metrics.successfulRequests.toLocaleString()} +
+
+
+
Failed
+
+ {metrics.failedRequests.toLocaleString()} +
+
+
+
Active Servers
+
+ {servers.filter((s) => s.status === 'healthy').length} / {servers.length} +
+
+
+ + +
+ ); +} diff --git a/lib/games.ts b/lib/games.ts index c6bc6425..f68b9ae1 100644 --- a/lib/games.ts +++ b/lib/games.ts @@ -21,6 +21,20 @@ export interface Game { * This is the single source of truth for game metadata */ const games: Game[] = [ + { + id: 'scaling-simulator', + title: 'Horizontal vs Vertical Scaling Simulator', + description: + 'Interactive game to learn scaling strategies for web applications. Experiment with horizontal and vertical scaling, see the effects on performance, cost, and reliability with realistic pricing simulation and budget constraints.', + iconName: 'TrendingUp', + badgeText: 'New', + color: 'from-emerald-500 to-teal-600', + href: '/games/scaling-simulator', + tags: ['scaling', 'infrastructure', 'educational', 'interactive', 'cloud', 'auto-scaling'], + isNew: true, + featured: true, + category: 'Infrastructure', + }, { id: 'load-balancer-simulator', title: 'Load Balancer Algorithm Simulator', diff --git a/public/images/games/scaling-simulator-og.png b/public/images/games/scaling-simulator-og.png new file mode 100644 index 00000000..09263001 Binary files /dev/null and b/public/images/games/scaling-simulator-og.png differ diff --git a/public/images/games/scaling-simulator-og.svg b/public/images/games/scaling-simulator-og.svg new file mode 100644 index 00000000..3e9857d1 --- /dev/null +++ b/public/images/games/scaling-simulator-og.svg @@ -0,0 +1,242 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + VERTICAL + + + + + + + + 2 CPU + + + + + + + + + + + + + + + + + + + 16 CPU + + + + + + vs + + + + + + HORIZONTAL + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Real-Time Metrics + + + + Traffic + + + + + 2.5k/s + + + + + CPU + + + + + 72% + + + + + Uptime + + + 95.2% + + + + + Budget + + + $180/$300 + + + + + + + + + + + Interactive Simulator + + + + + + Scaling Simulator + + + Horizontal vs Vertical + + + + + Learn scaling strategies with realistic + + + pricing and budget constraints + + + + + + Auto-Scaling + + + + Real-Time + + + + 4 Scenarios + + + + Budget Game + + + + Load Balancing + + + + + + + + + + + + + + + +