This commit is contained in:
Harivansh Rathi 2026-01-06 23:39:11 +05:30
parent 89ce6a9542
commit d35609deb2
16 changed files with 360 additions and 256 deletions

View file

@ -0,0 +1 @@
Tue Jan 6 23:38:01 IST 2026

View file

@ -0,0 +1,7 @@
[2026-01-06 23:38:01] Hook triggered with input: {"session_id":"51726d25-d24f-48e8-bb5d-a775dc434ee4","transcript_path":"/Users/rathi/.claude/projects/-Users-rathi-Documents-GitHub-infra-web/51726d25-d24f-48e8-bb5d-a775dc434ee4.jsonl","cwd":"/Users/rathi/Documents/GitHub/infra-web","hook_event_name":"SessionEnd","reason":"prompt_input_exit"}
[2026-01-06 23:38:01] Transcript: /Users/rathi/.claude/projects/-Users-rathi-Documents-GitHub-infra-web/51726d25-d24f-48e8-bb5d-a775dc434ee4.jsonl
[2026-01-06 23:38:01] Session ID: 51726d25-d24f-48e8-bb5d-a775dc434ee4
[2026-01-06 23:38:01] Project dir: /Users/rathi/Documents/GitHub/infra-web
[2026-01-06 23:38:01] Lock file created
[2026-01-06 23:38:01] Transcript line count: 4
[2026-01-06 23:38:01] Session too short, skipping retrospective

3
README.md Normal file
View file

@ -0,0 +1,3 @@
## System design for distributed systems
This repo was built by claude code and codex for me before a system design interview

View file

@ -11,25 +11,29 @@
interface Option {
id: string;
name: string;
color: string;
icon: string;
description?: string;
color?: string;
icon?: string;
whenToUse: string[];
whenNotToUse: string[];
realWorldExample?: string;
}
interface Props {
title: string;
title?: string;
subtitle?: string;
options: Option[];
features: ComparisonItem[];
features?: ComparisonItem[];
}
let { title, subtitle = '', options, features }: Props = $props();
let { title = '', subtitle = '', options, features = [] }: Props = $props();
let selectedOption = $state<string | null>(null);
function getIcon(iconName: string) {
return (Icons as Record<string, typeof Icons.Box>)[iconName] || Icons.Box;
type IconComponent = typeof Icons.Box;
function getIcon(iconName?: string): IconComponent {
const iconMap = Icons as unknown as Record<string, IconComponent>;
return (iconName ? iconMap[iconName] : null) ?? Icons.Box;
}
function getCellContent(value: string | boolean) {
@ -44,66 +48,104 @@
<div class="space-y-6">
<!-- Header -->
<div>
<h2 class="section-title">{title}</h2>
{#if subtitle}
<p class="section-subtitle">{subtitle}</p>
{/if}
</div>
{#if title || subtitle}
<div>
{#if title}
<h2 class="section-title">{title}</h2>
{/if}
{#if subtitle}
<p class="section-subtitle">{subtitle}</p>
{/if}
</div>
{/if}
<!-- Comparison Table -->
<div class="overflow-x-auto">
<table class="w-full border-collapse">
<thead>
<tr>
<th class="text-left p-4 bg-surface-900 border-b border-surface-700 text-surface-400 font-medium">
Feature
</th>
{#each options as option}
{@const Icon = getIcon(option.icon)}
<th
class="p-4 bg-surface-900 border-b border-surface-700 text-center cursor-pointer hover:bg-surface-800 transition-colors"
onclick={() => selectedOption = selectedOption === option.id ? null : option.id}
>
<div class="flex flex-col items-center gap-2">
<div
class="w-10 h-10 rounded-lg flex items-center justify-center"
style="background-color: {option.color}20; color: {option.color}"
>
<Icon class="w-6 h-6" />
</div>
<span class="font-medium text-surface-100">{option.name}</span>
</div>
{#if features.length > 0}
<div class="overflow-x-auto">
<table class="w-full border-collapse">
<thead>
<tr>
<th class="text-left p-4 bg-surface-900 border-b border-surface-800 text-surface-400 font-medium">
Feature
</th>
{/each}
</tr>
</thead>
<tbody>
{#each features as feature, i}
<tr class="border-b border-surface-800 hover:bg-surface-900/50">
<td class="p-4">
<div class="font-medium text-surface-200">{feature.feature}</div>
{#if feature.description}
<div class="text-sm text-surface-500 mt-1">{feature.description}</div>
{/if}
</td>
{#each options as option}
{@const cell = getCellContent(feature.values[option.id])}
<td class="p-4 text-center {cell.class}">
{#if cell.type === 'check'}
<Icons.Check class="w-5 h-5 mx-auto" />
{:else if cell.type === 'x'}
<Icons.X class="w-5 h-5 mx-auto" />
{:else}
<span class="text-sm">{cell.value}</span>
{/if}
</td>
{@const Icon = getIcon(option.icon)}
<th
class="p-4 bg-surface-900 border-b border-surface-800 text-center cursor-pointer hover:bg-surface-800 transition-colors"
onclick={() => selectedOption = selectedOption === option.id ? null : option.id}
>
<div class="flex flex-col items-center gap-2">
<div
class="w-10 h-10 rounded-lg flex items-center justify-center border border-surface-700 bg-surface-800"
style={option.color ? `background-color: ${option.color}20; color: ${option.color}` : ''}
>
<Icon class="w-6 h-6" />
</div>
<span class="font-medium text-surface-100">{option.name}</span>
</div>
</th>
{/each}
</tr>
{/each}
</tbody>
</table>
</div>
</thead>
<tbody>
{#each features as feature, i}
<tr class="border-b border-surface-800 hover:bg-surface-900/50">
<td class="p-4">
<div class="font-medium text-surface-200">{feature.feature}</div>
{#if feature.description}
<div class="text-sm text-surface-500 mt-1">{feature.description}</div>
{/if}
</td>
{#each options as option}
{@const cell = getCellContent(feature.values[option.id])}
<td class="p-4 text-center {cell.class}">
{#if cell.type === 'check'}
<Icons.Check class="w-5 h-5 mx-auto" />
{:else if cell.type === 'x'}
<Icons.X class="w-5 h-5 mx-auto" />
{:else}
<span class="text-sm">{cell.value}</span>
{/if}
</td>
{/each}
</tr>
{/each}
</tbody>
</table>
</div>
{:else}
<div class="grid sm:grid-cols-2 gap-4">
{#each options as option}
{@const Icon = getIcon(option.icon)}
{@const active = selectedOption === option.id}
<button
class="text-left p-4 rounded-xl border transition-colors"
class:bg-surface-900={!active}
class:border-surface-800={!active}
class:hover:border-surface-700={!active}
class:bg-surface-800={active}
class:border-surface-700={active}
onclick={() => selectedOption = active ? null : option.id}
>
<div class="flex items-start gap-3">
<div
class="w-10 h-10 rounded-lg flex items-center justify-center border border-surface-700 bg-surface-800"
style={option.color ? `background-color: ${option.color}20; color: ${option.color}` : ''}
>
<Icon class="w-6 h-6" />
</div>
<div class="flex-1">
<div class="font-medium text-surface-100">{option.name}</div>
{#if option.description}
<div class="text-sm text-surface-500 mt-0.5">{option.description}</div>
{/if}
</div>
<Icons.ChevronDown class="w-4 h-4 mt-1 text-surface-500 transition-transform {active ? 'rotate-180' : ''}" />
</div>
</button>
{/each}
</div>
{/if}
<!-- When to Use / When Not to Use Panels -->
{#if selectedOption}

View file

@ -31,9 +31,11 @@
return nodes.find(n => n.id === id);
}
function getIcon(iconName?: string) {
if (!iconName) return Icons.HelpCircle;
return (Icons as Record<string, typeof Icons.Box>)[iconName] || Icons.HelpCircle;
type IconComponent = typeof Icons.Box;
function getIcon(iconName?: string): IconComponent {
const iconMap = Icons as unknown as Record<string, IconComponent>;
return (iconName ? iconMap[iconName] : null) ?? (Icons.HelpCircle as IconComponent);
}
function answer(nodeId: string, isYes: boolean) {

View file

@ -32,9 +32,11 @@
let isPlaying = $state(autoPlay);
let intervalId: ReturnType<typeof setInterval> | null = null;
function getIcon(iconName?: string) {
if (!iconName) return Icons.Circle;
return (Icons as Record<string, typeof Icons.Box>)[iconName] || Icons.Circle;
type IconComponent = typeof Icons.Box;
function getIcon(iconName?: string): IconComponent {
const iconMap = Icons as unknown as Record<string, IconComponent>;
return (iconName ? iconMap[iconName] : null) ?? (Icons.Circle as IconComponent);
}
function nextStep() {
@ -202,6 +204,7 @@
{#each steps as _, i}
<button
onclick={() => goToStep(i)}
aria-label={"Go to step " + (i + 1)}
class="w-2 h-2 rounded-full transition-all duration-200"
class:bg-surface-100={i === currentStep}
class:w-4={i === currentStep}

View file

@ -21,8 +21,11 @@
onclick
}: Props = $props();
function getIcon(iconName: string) {
return (Icons as Record<string, typeof Icons.Box>)[iconName] || Icons.Box;
type IconComponent = typeof Icons.Box;
function getIcon(iconName: string): IconComponent {
const iconMap = Icons as unknown as Record<string, IconComponent>;
return iconMap[iconName] || Icons.Box;
}
const Icon = $derived(getIcon(icon));

View file

@ -4,8 +4,11 @@
import * as Icons from 'lucide-svelte';
import { slide } from 'svelte/transition';
function getIcon(iconName: string) {
return (Icons as Record<string, typeof Icons.Home>)[iconName] || Icons.Circle;
type IconComponent = typeof Icons.Box;
function getIcon(iconName: string): IconComponent {
const iconMap = Icons as unknown as Record<string, IconComponent>;
return iconMap[iconName] || (Icons.Circle as IconComponent);
}
function toggleSection(id: string) {

View file

@ -54,8 +54,11 @@
{ label: 'Which Database?', href: '/decisions/which-database', icon: 'HelpCircle' }
];
function getIcon(iconName: string) {
return (Icons as Record<string, typeof Icons.Box>)[iconName] || Icons.Box;
type IconComponent = typeof Icons.Box;
function getIcon(iconName: string): IconComponent {
const iconMap = Icons as unknown as Record<string, IconComponent>;
return iconMap[iconName] || Icons.Box;
}
</script>

View file

@ -119,6 +119,23 @@
{ step: 5, title: 'Container creation', desc: 'Kubelet tells runtime to start containers' },
{ step: 6, title: 'Running', desc: 'Pod running, kube-proxy sets up networking' }
];
const accent = {
blue: { badge: 'bg-blue-500/20 text-blue-300', dot: 'bg-blue-500', text: 'text-blue-400', panel: 'bg-blue-500/20 border border-blue-500/30' },
purple: { badge: 'bg-purple-500/20 text-purple-300', dot: 'bg-purple-500', text: 'text-purple-400', panel: 'bg-purple-500/20 border border-purple-500/30' },
green: { badge: 'bg-green-500/20 text-green-300', dot: 'bg-green-500', text: 'text-green-400', panel: 'bg-green-500/20 border border-green-500/30' },
orange: { badge: 'bg-orange-500/20 text-orange-300', dot: 'bg-orange-500', text: 'text-orange-400', panel: 'bg-orange-500/20 border border-orange-500/30' },
cyan: { badge: 'bg-cyan-500/20 text-cyan-300', dot: 'bg-cyan-500', text: 'text-cyan-400', panel: 'bg-cyan-500/20 border border-cyan-500/30' },
yellow: { badge: 'bg-yellow-500/20 text-yellow-300', dot: 'bg-yellow-500', text: 'text-yellow-400', panel: 'bg-yellow-500/20 border border-yellow-500/30' },
pink: { badge: 'bg-pink-500/20 text-pink-300', dot: 'bg-pink-500', text: 'text-pink-400', panel: 'bg-pink-500/20 border border-pink-500/30' },
gray: { badge: 'bg-surface-800 text-surface-300 border border-surface-700', dot: 'bg-surface-600', text: 'text-surface-300', panel: 'bg-surface-800/60 border border-surface-800' }
} as const;
type AccentKey = keyof typeof accent;
function getAccent(color: string): (typeof accent)[AccentKey] {
return accent[(color in accent ? color : 'gray') as AccentKey];
}
</script>
<svelte:head>
@ -126,27 +143,27 @@
</svelte:head>
<div class="max-w-6xl mx-auto">
<h1 class="text-3xl font-bold text-white mb-2">Kubernetes Architecture</h1>
<p class="text-gray-400 mb-8">Understanding the control plane, worker nodes, and how they work together</p>
<h1 class="text-3xl font-bold text-surface-100 mb-2">Kubernetes Architecture</h1>
<p class="text-surface-400 mb-8">Understanding the control plane, worker nodes, and how they work together</p>
<!-- Overview Diagram -->
<section class="mb-12">
<div class="bg-gray-800/50 rounded-xl p-6 border border-gray-700">
<div class="card">
<div class="grid md:grid-cols-2 gap-8">
<!-- Control Plane -->
<div class="p-4 rounded-xl bg-blue-500/10 border border-blue-500/30">
<h3 class="text-lg font-semibold text-blue-400 mb-4 text-center">Control Plane</h3>
<p class="text-gray-400 text-sm text-center mb-4">The brain - makes decisions about the cluster</p>
<p class="text-surface-400 text-sm text-center mb-4">The brain - makes decisions about the cluster</p>
<div class="grid grid-cols-2 gap-3">
{#each controlPlaneComponents.slice(0, 4) as component}
<button
class="p-3 rounded-lg bg-gray-800/50 border border-gray-600 hover:border-gray-400 transition-all text-left"
class="p-3 rounded-lg bg-surface-900 border border-surface-800 hover:border-surface-700 transition-colors text-left"
class:border-blue-500={selectedComponent === component.id}
on:click={() => selectedComponent = selectedComponent === component.id ? null : component.id}
>
<div class="text-white font-medium text-sm">{component.name}</div>
<div class="text-gray-500 text-xs mt-1 line-clamp-2">{component.description}</div>
<div class="text-surface-100 font-medium text-sm">{component.name}</div>
<div class="text-surface-500 text-xs mt-1 line-clamp-2">{component.description}</div>
</button>
{/each}
</div>
@ -155,17 +172,17 @@
<!-- Worker Nodes -->
<div class="p-4 rounded-xl bg-green-500/10 border border-green-500/30">
<h3 class="text-lg font-semibold text-green-400 mb-4 text-center">Worker Nodes</h3>
<p class="text-gray-400 text-sm text-center mb-4">The muscle - runs your actual workloads</p>
<p class="text-surface-400 text-sm text-center mb-4">The muscle - runs your actual workloads</p>
<div class="space-y-3">
{#each nodeComponents as component}
<button
class="w-full p-3 rounded-lg bg-gray-800/50 border border-gray-600 hover:border-gray-400 transition-all text-left"
class="w-full p-3 rounded-lg bg-surface-900 border border-surface-800 hover:border-surface-700 transition-colors text-left"
class:border-green-500={selectedComponent === component.id}
on:click={() => selectedComponent = selectedComponent === component.id ? null : component.id}
>
<div class="text-white font-medium text-sm">{component.name}</div>
<div class="text-gray-500 text-xs mt-1">{component.description}</div>
<div class="text-surface-100 font-medium text-sm">{component.name}</div>
<div class="text-surface-500 text-xs mt-1">{component.description}</div>
</button>
{/each}
</div>
@ -177,12 +194,12 @@
{@const allComponents = [...controlPlaneComponents, ...nodeComponents]}
{@const component = allComponents.find(c => c.id === selectedComponent)}
{#if component}
<div class="mt-6 p-4 bg-gray-700/50 rounded-lg border border-gray-600">
<h4 class="text-white font-semibold mb-3">{component.name}</h4>
<div class="mt-6 p-4 bg-surface-800/60 rounded-lg border border-surface-800">
<h4 class="text-surface-100 font-semibold mb-3">{component.name}</h4>
<ul class="grid md:grid-cols-2 gap-2">
{#each component.details as detail}
<li class="flex items-start gap-2 text-gray-300 text-sm">
<span class="text-blue-400 mt-0.5">-</span>
<li class="flex items-start gap-2 text-surface-300 text-sm">
<span class="text-surface-500 mt-0.5">-</span>
{detail}
</li>
{/each}
@ -195,24 +212,24 @@
<!-- Control Plane Deep Dive -->
<section class="mb-12">
<h2 class="text-xl font-semibold text-white mb-4">Control Plane Components</h2>
<h2 class="text-xl font-semibold text-surface-100 mb-4">Control Plane Components</h2>
<div class="space-y-4">
{#each controlPlaneComponents as component}
<div class="bg-gray-800/50 rounded-xl p-6 border border-gray-700">
<div class="card">
<div class="flex items-start justify-between mb-4">
<div>
<h3 class="text-lg font-semibold text-white">{component.name}</h3>
<p class="text-gray-400 text-sm">{component.description}</p>
<h3 class="text-lg font-semibold text-surface-100">{component.name}</h3>
<p class="text-surface-400 text-sm">{component.description}</p>
</div>
<span class="px-3 py-1 rounded-full text-xs font-medium bg-{component.color}-500/20 text-{component.color}-400">
<span class={"px-3 py-1 rounded-full text-xs font-medium " + getAccent(component.color).badge}>
Control Plane
</span>
</div>
<div class="grid md:grid-cols-2 gap-3">
{#each component.details as detail}
<div class="flex items-center gap-2 p-2 bg-gray-700/30 rounded-lg text-sm text-gray-300">
<span class="w-2 h-2 rounded-full bg-{component.color}-500"></span>
<div class="flex items-center gap-2 p-2 bg-surface-800/40 border border-surface-800 rounded-lg text-sm text-surface-300">
<span class={"w-2 h-2 rounded-full " + getAccent(component.color).dot}></span>
{detail}
</div>
{/each}
@ -224,10 +241,10 @@
<!-- Request Flow -->
<section class="mb-12">
<h2 class="text-xl font-semibold text-white mb-4">How a Pod Gets Scheduled</h2>
<p class="text-gray-400 mb-6">Follow the journey from kubectl apply to running pod</p>
<h2 class="text-xl font-semibold text-surface-100 mb-4">How a Pod Gets Scheduled</h2>
<p class="text-surface-400 mb-6">Follow the journey from kubectl apply to running pod</p>
<div class="bg-gray-800/50 rounded-xl p-6 border border-gray-700">
<div class="card">
<div class="relative">
<div class="absolute left-6 top-0 bottom-0 w-0.5 bg-blue-500/30"></div>
<div class="space-y-6">
@ -236,9 +253,9 @@
<div class="absolute left-0 w-12 h-12 rounded-full bg-blue-500/20 border-2 border-blue-500 flex items-center justify-center text-blue-400 font-bold">
{step.step}
</div>
<div class="bg-gray-700/50 rounded-lg p-4">
<div class="text-white font-medium">{step.title}</div>
<div class="text-gray-400 text-sm mt-1">{step.desc}</div>
<div class="bg-surface-800/60 border border-surface-800 rounded-lg p-4">
<div class="text-surface-100 font-medium">{step.title}</div>
<div class="text-surface-400 text-sm mt-1">{step.desc}</div>
</div>
</div>
{/each}
@ -249,18 +266,18 @@
<!-- Pod Lifecycle -->
<section class="mb-12">
<h2 class="text-xl font-semibold text-white mb-4">Pod Lifecycle</h2>
<h2 class="text-xl font-semibold text-surface-100 mb-4">Pod Lifecycle</h2>
<div class="bg-gray-800/50 rounded-xl p-6 border border-gray-700">
<div class="card">
<div class="flex flex-wrap items-center justify-center gap-4">
{#each podLifecycle as phase, i}
<div class="flex items-center">
<div class="p-3 rounded-lg bg-{phase.color}-500/20 border border-{phase.color}-500/30 text-center min-w-[120px]">
<div class="text-{phase.color}-400 font-semibold text-sm">{phase.phase}</div>
<div class="text-gray-500 text-xs mt-1">{phase.desc}</div>
<div class={"p-3 rounded-lg text-center min-w-[120px] " + getAccent(phase.color).panel}>
<div class={getAccent(phase.color).text + " font-semibold text-sm"}>{phase.phase}</div>
<div class="text-surface-500 text-xs mt-1">{phase.desc}</div>
</div>
{#if i < podLifecycle.length - 1}
<div class="mx-2 text-gray-500">-></div>
<div class="mx-2 text-surface-600">-></div>
{/if}
</div>
{/each}
@ -270,68 +287,68 @@
<!-- Key Concepts -->
<section class="mb-12">
<h2 class="text-xl font-semibold text-white mb-4">Key Kubernetes Objects</h2>
<h2 class="text-xl font-semibold text-surface-100 mb-4">Key Kubernetes Objects</h2>
<div class="grid md:grid-cols-2 lg:grid-cols-3 gap-4">
<div class="bg-gray-800/50 rounded-xl p-4 border border-gray-700">
<div class="bg-surface-900 rounded-xl p-4 border border-surface-800">
<div class="text-blue-400 font-semibold mb-2">Pod</div>
<p class="text-gray-400 text-sm">Smallest deployable unit. One or more containers that share network/storage.</p>
<p class="text-surface-400 text-sm">Smallest deployable unit. One or more containers that share network/storage.</p>
</div>
<div class="bg-gray-800/50 rounded-xl p-4 border border-gray-700">
<div class="bg-surface-900 rounded-xl p-4 border border-surface-800">
<div class="text-green-400 font-semibold mb-2">Deployment</div>
<p class="text-gray-400 text-sm">Manages ReplicaSets. Handles rolling updates and rollbacks.</p>
<p class="text-surface-400 text-sm">Manages ReplicaSets. Handles rolling updates and rollbacks.</p>
</div>
<div class="bg-gray-800/50 rounded-xl p-4 border border-gray-700">
<div class="bg-surface-900 rounded-xl p-4 border border-surface-800">
<div class="text-purple-400 font-semibold mb-2">Service</div>
<p class="text-gray-400 text-sm">Stable network endpoint for pods. ClusterIP, NodePort, LoadBalancer.</p>
<p class="text-surface-400 text-sm">Stable network endpoint for pods. ClusterIP, NodePort, LoadBalancer.</p>
</div>
<div class="bg-gray-800/50 rounded-xl p-4 border border-gray-700">
<div class="bg-surface-900 rounded-xl p-4 border border-surface-800">
<div class="text-orange-400 font-semibold mb-2">ConfigMap</div>
<p class="text-gray-400 text-sm">Non-sensitive configuration data. Injected as env vars or files.</p>
<p class="text-surface-400 text-sm">Non-sensitive configuration data. Injected as env vars or files.</p>
</div>
<div class="bg-gray-800/50 rounded-xl p-4 border border-gray-700">
<div class="bg-surface-900 rounded-xl p-4 border border-surface-800">
<div class="text-red-400 font-semibold mb-2">Secret</div>
<p class="text-gray-400 text-sm">Sensitive data like passwords, tokens. Base64 encoded (not encrypted!).</p>
<p class="text-surface-400 text-sm">Sensitive data like passwords, tokens. Base64 encoded (not encrypted!).</p>
</div>
<div class="bg-gray-800/50 rounded-xl p-4 border border-gray-700">
<div class="bg-surface-900 rounded-xl p-4 border border-surface-800">
<div class="text-yellow-400 font-semibold mb-2">Ingress</div>
<p class="text-gray-400 text-sm">HTTP routing rules. Path-based routing to Services.</p>
<p class="text-surface-400 text-sm">HTTP routing rules. Path-based routing to Services.</p>
</div>
<div class="bg-gray-800/50 rounded-xl p-4 border border-gray-700">
<div class="bg-surface-900 rounded-xl p-4 border border-surface-800">
<div class="text-cyan-400 font-semibold mb-2">StatefulSet</div>
<p class="text-gray-400 text-sm">For stateful apps. Stable network identity and persistent storage.</p>
<p class="text-surface-400 text-sm">For stateful apps. Stable network identity and persistent storage.</p>
</div>
<div class="bg-gray-800/50 rounded-xl p-4 border border-gray-700">
<div class="bg-surface-900 rounded-xl p-4 border border-surface-800">
<div class="text-pink-400 font-semibold mb-2">DaemonSet</div>
<p class="text-gray-400 text-sm">Run pod on every node. Used for logging, monitoring agents.</p>
<p class="text-surface-400 text-sm">Run pod on every node. Used for logging, monitoring agents.</p>
</div>
<div class="bg-gray-800/50 rounded-xl p-4 border border-gray-700">
<div class="bg-surface-900 rounded-xl p-4 border border-surface-800">
<div class="text-indigo-400 font-semibold mb-2">HPA</div>
<p class="text-gray-400 text-sm">Horizontal Pod Autoscaler. Scale pods based on CPU/memory/custom metrics.</p>
<p class="text-surface-400 text-sm">Horizontal Pod Autoscaler. Scale pods based on CPU/memory/custom metrics.</p>
</div>
</div>
</section>
<!-- Networking -->
<section class="mb-12">
<h2 class="text-xl font-semibold text-white mb-4">Kubernetes Networking Model</h2>
<h2 class="text-xl font-semibold text-surface-100 mb-4">Kubernetes Networking Model</h2>
<div class="bg-gray-800/50 rounded-xl p-6 border border-gray-700">
<div class="card">
<div class="grid md:grid-cols-3 gap-6">
<div class="p-4 bg-blue-500/10 rounded-lg border border-blue-500/30">
<h4 class="text-blue-400 font-semibold mb-2">Pod-to-Pod</h4>
<p class="text-gray-400 text-sm mb-2">Every pod gets a unique IP. Pods can communicate directly without NAT.</p>
<div class="text-xs text-gray-500">Implemented by CNI plugin (Calico, Cilium, etc.)</div>
<p class="text-surface-400 text-sm mb-2">Every pod gets a unique IP. Pods can communicate directly without NAT.</p>
<div class="text-xs text-surface-500">Implemented by CNI plugin (Calico, Cilium, etc.)</div>
</div>
<div class="p-4 bg-green-500/10 rounded-lg border border-green-500/30">
<h4 class="text-green-400 font-semibold mb-2">Pod-to-Service</h4>
<p class="text-gray-400 text-sm mb-2">Services provide stable virtual IPs (ClusterIP). kube-proxy routes to pods.</p>
<div class="text-xs text-gray-500">Uses iptables or IPVS rules</div>
<p class="text-surface-400 text-sm mb-2">Services provide stable virtual IPs (ClusterIP). kube-proxy routes to pods.</p>
<div class="text-xs text-surface-500">Uses iptables or IPVS rules</div>
</div>
<div class="p-4 bg-purple-500/10 rounded-lg border border-purple-500/30">
<h4 class="text-purple-400 font-semibold mb-2">External-to-Service</h4>
<p class="text-gray-400 text-sm mb-2">NodePort, LoadBalancer, or Ingress expose services externally.</p>
<div class="text-xs text-gray-500">Ingress for HTTP, LoadBalancer for TCP/UDP</div>
<p class="text-surface-400 text-sm mb-2">NodePort, LoadBalancer, or Ingress expose services externally.</p>
<div class="text-xs text-surface-500">Ingress for HTTP, LoadBalancer for TCP/UDP</div>
</div>
</div>
</div>
@ -339,54 +356,54 @@
<!-- Common Patterns -->
<section>
<h2 class="text-xl font-semibold text-white mb-4">Production Best Practices</h2>
<h2 class="text-xl font-semibold text-surface-100 mb-4">Production Best Practices</h2>
<div class="grid md:grid-cols-2 gap-6">
<div class="bg-gray-800/50 rounded-xl p-6 border border-gray-700">
<div class="card">
<h4 class="text-green-400 font-medium mb-3">DO</h4>
<ul class="space-y-2">
<li class="flex items-start gap-2 text-gray-300 text-sm">
<li class="flex items-start gap-2 text-surface-300 text-sm">
<span class="text-green-400">+</span>
Set resource requests and limits on all pods
</li>
<li class="flex items-start gap-2 text-gray-300 text-sm">
<li class="flex items-start gap-2 text-surface-300 text-sm">
<span class="text-green-400">+</span>
Use liveness and readiness probes
</li>
<li class="flex items-start gap-2 text-gray-300 text-sm">
<li class="flex items-start gap-2 text-surface-300 text-sm">
<span class="text-green-400">+</span>
Run multiple replicas with anti-affinity
</li>
<li class="flex items-start gap-2 text-gray-300 text-sm">
<li class="flex items-start gap-2 text-surface-300 text-sm">
<span class="text-green-400">+</span>
Use namespaces for isolation
</li>
<li class="flex items-start gap-2 text-gray-300 text-sm">
<li class="flex items-start gap-2 text-surface-300 text-sm">
<span class="text-green-400">+</span>
Backup etcd regularly
</li>
</ul>
</div>
<div class="bg-gray-800/50 rounded-xl p-6 border border-gray-700">
<div class="card">
<h4 class="text-red-400 font-medium mb-3">DON'T</h4>
<ul class="space-y-2">
<li class="flex items-start gap-2 text-gray-300 text-sm">
<li class="flex items-start gap-2 text-surface-300 text-sm">
<span class="text-red-400">-</span>
Run workloads on control plane nodes
</li>
<li class="flex items-start gap-2 text-gray-300 text-sm">
<li class="flex items-start gap-2 text-surface-300 text-sm">
<span class="text-red-400">-</span>
Use :latest image tags in production
</li>
<li class="flex items-start gap-2 text-gray-300 text-sm">
<li class="flex items-start gap-2 text-surface-300 text-sm">
<span class="text-red-400">-</span>
Store secrets in ConfigMaps
</li>
<li class="flex items-start gap-2 text-gray-300 text-sm">
<li class="flex items-start gap-2 text-surface-300 text-sm">
<span class="text-red-400">-</span>
Skip pod disruption budgets
</li>
<li class="flex items-start gap-2 text-gray-300 text-sm">
<li class="flex items-start gap-2 text-surface-300 text-sm">
<span class="text-red-400">-</span>
Ignore resource quotas in multi-tenant clusters
</li>

View file

@ -53,40 +53,46 @@
title: 'Lambda Cold Start Flow',
steps: [
{
id: 'cold-start-1',
title: 'Invocation Request',
content: 'API Gateway triggers Lambda function',
description: 'API Gateway triggers Lambda function',
details: 'A request arrives but no warm execution environment is available.',
tips: ['Cold starts affect ~1% of requests', 'More common during traffic spikes']
tip: 'Cold starts affect ~1% of requests. More common during traffic spikes.'
},
{
id: 'cold-start-2',
title: 'Container Provisioning',
content: 'Lambda allocates compute resources',
description: 'Lambda allocates compute resources',
details: 'AWS provisions a micro-VM with the configured memory. More memory = more CPU.',
tips: ['Memory range: 128MB - 10GB', 'CPU scales proportionally with memory']
tip: 'Memory range: 128MB - 10GB. CPU scales proportionally with memory.'
},
{
id: 'cold-start-3',
title: 'Runtime Initialization',
content: 'Load Python/Node.js/Java runtime',
description: 'Load Python/Node.js/Java runtime',
details: 'The language runtime is loaded and initialized in the container.',
tips: ['Python/Node.js: ~100-200ms', 'Java: ~500ms-1s (JVM startup)']
tip: 'Python/Node.js: ~100-200ms. Java: ~500ms-1s (JVM startup).'
},
{
id: 'cold-start-4',
title: 'Function Code Loading',
content: 'Download and extract deployment package',
description: 'Download and extract deployment package',
details: 'Your code is downloaded from S3 and extracted. Larger packages take longer.',
tips: ['Keep deployment package small', 'Use Lambda Layers for shared code']
tip: 'Keep deployment package small. Use Lambda Layers for shared code.'
},
{
id: 'cold-start-5',
title: 'Static Initialization',
content: 'Run code outside handler (global scope)',
description: 'Run code outside handler (global scope)',
details: 'Code at module level runs once per container. Initialize DB connections here.',
tips: ['Initialize SDK clients outside handler', 'This code runs once per container lifecycle']
tip: 'Initialize SDK clients outside handler. This code runs once per container lifecycle.'
},
{
id: 'cold-start-6',
title: 'Handler Execution',
content: 'Your function code runs',
description: 'Your function code runs',
details: 'Finally, your handler function executes. Container is now "warm".',
tips: ['Subsequent invocations skip steps 1-5', 'Warm container reused for ~15 minutes']
tip: 'Subsequent invocations skip steps 1-5. Warm container reused for ~15 minutes.'
}
]
};

View file

@ -159,40 +159,46 @@
title: 'Cache-Aside Pattern Flow',
steps: [
{
id: 'cache-aside-1',
title: 'Application Requests Data',
content: 'User requests user profile for user_id=123',
description: 'User requests user profile for user_id=123',
details: 'The application receives a request that needs data from the database.',
tips: ['Common entry point: API endpoint, service method']
tip: 'Common entry point: API endpoint, service method.'
},
{
id: 'cache-aside-2',
title: 'Check Cache First',
content: 'GET user:123 from Redis',
description: 'GET user:123 from Redis',
details: 'Application checks if the data exists in cache before hitting the database.',
tips: ['Use consistent key naming: entity:id', 'Handle cache connection failures gracefully']
tip: 'Use consistent key naming: entity:id. Handle cache connection failures gracefully.'
},
{
id: 'cache-aside-3',
title: 'Cache Hit - Return Immediately',
content: 'Data found! Return cached user profile',
description: 'Data found! Return cached user profile',
details: 'If data is in cache, return it immediately. This is the fast path.',
tips: ['Typical cache hit latency: < 1ms', 'Log cache hits for monitoring']
tip: 'Typical cache hit latency: < 1ms. Log cache hits for monitoring.'
},
{
id: 'cache-aside-4',
title: 'Cache Miss - Query Database',
content: 'SELECT * FROM users WHERE id = 123',
description: 'SELECT * FROM users WHERE id = 123',
details: 'If cache miss, query the primary database for the data.',
tips: ['This is the slow path', 'Consider query optimization']
tip: 'This is the slow path. Consider query optimization.'
},
{
id: 'cache-aside-5',
title: 'Store in Cache',
content: 'SET user:123 with TTL 3600 seconds',
description: 'SET user:123 with TTL 3600 seconds',
details: 'After getting data from DB, store it in cache for future requests.',
tips: ['Always set a TTL to prevent stale data', 'Consider cache size limits']
tip: 'Always set a TTL to prevent stale data. Consider cache size limits.'
},
{
id: 'cache-aside-6',
title: 'Return Data to Caller',
content: 'Return user profile to client',
description: 'Return user profile to client',
details: 'Finally return the data. Next request will hit the cache.',
tips: ['Monitor cache hit rate', 'Aim for > 90% hit rate']
tip: 'Monitor cache hit rate. Aim for > 90% hit rate.'
}
]
};

View file

@ -306,30 +306,30 @@
<div class="space-y-3">
<h4 class="text-sm font-medium text-surface-400 uppercase tracking-wide">By Use Case</h4>
{#each [
{ case: 'E-commerce orders', db: 'PostgreSQL', color: 'blue' },
{ case: 'User profiles', db: 'MongoDB', color: 'green' },
{ case: 'Session caching', db: 'Redis', color: 'red' },
{ case: 'IoT sensor data', db: 'TimescaleDB', color: 'purple' },
{ case: 'Social graph', db: 'Neo4j', color: 'pink' }
{ case: 'E-commerce orders', db: 'PostgreSQL' },
{ case: 'User profiles', db: 'MongoDB' },
{ case: 'Session caching', db: 'Redis' },
{ case: 'IoT sensor data', db: 'TimescaleDB' },
{ case: 'Social graph', db: 'Neo4j' }
] as item}
<div class="flex items-center justify-between p-2 bg-surface-800 rounded-lg">
<span class="text-sm text-surface-300">{item.case}</span>
<span class="text-sm font-medium text-{item.color}-400">{item.db}</span>
<span class="text-sm font-medium text-surface-200">{item.db}</span>
</div>
{/each}
</div>
<div class="space-y-3">
<h4 class="text-sm font-medium text-surface-400 uppercase tracking-wide">By Data Type</h4>
{#each [
{ type: 'Relational', db: 'PostgreSQL/MySQL', color: 'blue' },
{ type: 'Documents', db: 'MongoDB/Firestore', color: 'green' },
{ type: 'Key-Value', db: 'Redis/DynamoDB', color: 'yellow' },
{ type: 'Time-Series', db: 'TimescaleDB/InfluxDB', color: 'purple' },
{ type: 'Graph', db: 'Neo4j/Neptune', color: 'pink' }
{ type: 'Relational', db: 'PostgreSQL/MySQL' },
{ type: 'Documents', db: 'MongoDB/Firestore' },
{ type: 'Key-Value', db: 'Redis/DynamoDB' },
{ type: 'Time-Series', db: 'TimescaleDB/InfluxDB' },
{ type: 'Graph', db: 'Neo4j/Neptune' }
] as item}
<div class="flex items-center justify-between p-2 bg-surface-800 rounded-lg">
<span class="text-sm text-surface-300">{item.type}</span>
<span class="text-sm font-medium text-{item.color}-400">{item.db}</span>
<span class="text-sm font-medium text-surface-200">{item.db}</span>
</div>
{/each}
</div>

View file

@ -43,6 +43,7 @@
description: 'NOT possible in distributed systems',
explanation: 'In a distributed system, network partitions are inevitable. When a partition occurs, you must choose between C and A.',
examples: ['Single-node databases (PostgreSQL, MySQL on one server)', 'Not achievable in distributed systems'],
useCase: '',
color: '#94A3B8',
viable: false
},
@ -110,7 +111,9 @@
<g
class="cursor-pointer"
onclick={() => selectCombination('CA')}
onmouseenter={() => {}}
role="button"
tabindex="0"
onkeydown={(e) => (e.key === 'Enter' || e.key === ' ') && selectCombination('CA')}
>
<line x1={vertices.C.x} y1={vertices.C.y} x2={vertices.A.x} y2={vertices.A.y}
stroke={selectedChoice === 'CA' ? '#94A3B8' : 'transparent'}
@ -132,6 +135,9 @@
<g
class="cursor-pointer"
onclick={() => selectCombination('CP')}
role="button"
tabindex="0"
onkeydown={(e) => (e.key === 'Enter' || e.key === ' ') && selectCombination('CP')}
>
<line x1={vertices.C.x} y1={vertices.C.y} x2={vertices.P.x} y2={vertices.P.y}
stroke={selectedChoice === 'CP' ? '#8B5CF6' : 'transparent'}
@ -148,6 +154,9 @@
<g
class="cursor-pointer"
onclick={() => selectCombination('AP')}
role="button"
tabindex="0"
onkeydown={(e) => (e.key === 'Enter' || e.key === ' ') && selectCombination('AP')}
>
<line x1={vertices.A.x} y1={vertices.A.y} x2={vertices.P.x} y2={vertices.P.y}
stroke={selectedChoice === 'AP' ? '#EC4899' : 'transparent'}
@ -164,6 +173,7 @@
{#each Object.entries(vertices) as [key, vertex]}
<g
class="cursor-pointer"
role="presentation"
onmouseenter={() => hoveredVertex = key as 'C' | 'A' | 'P'}
onmouseleave={() => hoveredVertex = null}
>
@ -200,6 +210,7 @@
{#each Object.entries(vertices) as [key, vertex]}
<div
class="p-4 rounded-lg border transition-all duration-200"
role="presentation"
class:bg-surface-800={hoveredVertex !== key}
class:border-surface-700={hoveredVertex !== key}
style:background-color={hoveredVertex === key ? `${vertex.color}20` : undefined}

View file

@ -254,28 +254,25 @@
{
name: 'Cloudflare',
icon: 'Cloud',
color: 'orange',
pros: ['Free tier', 'Fast propagation', 'DDoS protection'],
bestFor: 'Most websites'
},
{
name: 'Route 53',
icon: 'Compass',
color: 'yellow',
pros: ['AWS integration', 'Health checks', 'Geo-routing'],
bestFor: 'AWS infrastructure'
},
{
name: 'Cloud DNS',
icon: 'Cloud',
color: 'blue',
pros: ['GCP integration', '100% SLA', 'Global anycast'],
bestFor: 'GCP infrastructure'
}
] as provider}
<div class="bg-surface-800 rounded-lg p-4">
<div class="flex items-center gap-2 mb-3">
<Icons.Cloud class="w-5 h-5 text-{provider.color}-400" />
<Icons.Cloud class="w-5 h-5 text-surface-300" />
<span class="font-medium text-surface-200">{provider.name}</span>
</div>
<ul class="space-y-1 mb-3">

View file

@ -83,23 +83,23 @@
</svelte:head>
<div class="max-w-6xl mx-auto">
<h1 class="text-3xl font-bold text-white mb-2">Load Balancing</h1>
<p class="text-gray-400 mb-8">Understanding Layer 4 vs Layer 7 load balancers and when to use each</p>
<h1 class="text-3xl font-bold text-surface-100 mb-2">Load Balancing</h1>
<p class="text-surface-400 mb-8">Understanding Layer 4 vs Layer 7 load balancers and when to use each</p>
<!-- OSI Model Visual -->
<section class="mb-12">
<h2 class="text-xl font-semibold text-white mb-4">OSI Model & Load Balancer Layers</h2>
<p class="text-gray-400 mb-6">Load balancers operate at different OSI layers, determining what information they can see and use for routing decisions.</p>
<h2 class="text-xl font-semibold text-surface-100 mb-4">OSI Model & Load Balancer Layers</h2>
<p class="text-surface-400 mb-6">Load balancers operate at different OSI layers, determining what information they can see and use for routing decisions.</p>
<div class="bg-gray-800/50 rounded-xl p-6 border border-gray-700">
<div class="card">
<div class="grid gap-2">
{#each osiLayers as layer}
<div
class="flex items-center gap-4 p-3 rounded-lg transition-all cursor-pointer
class="flex items-center gap-4 p-3 rounded-lg transition-all cursor-pointer border border-surface-800 bg-surface-900
{layer.num === 7 ? 'bg-blue-500/20 border border-blue-500/50' : ''}
{layer.num === 4 ? 'bg-purple-500/20 border border-purple-500/50' : ''}
{layer.num === 3 ? 'bg-orange-500/20 border border-orange-500/50' : ''}
{layer.num !== 7 && layer.num !== 4 && layer.num !== 3 ? 'bg-gray-700/30' : ''}"
"
on:click={() => {
if (layer.num === 7) selectedLayer = 'l7';
else if (layer.num === 4) selectedLayer = 'l4';
@ -112,12 +112,12 @@
{layer.num === 7 ? 'bg-blue-500 text-white' : ''}
{layer.num === 4 ? 'bg-purple-500 text-white' : ''}
{layer.num === 3 ? 'bg-orange-500 text-white' : ''}
{layer.num !== 7 && layer.num !== 4 && layer.num !== 3 ? 'bg-gray-600 text-gray-300' : ''}">
{layer.num !== 7 && layer.num !== 4 && layer.num !== 3 ? 'bg-surface-800 text-surface-300' : ''}">
{layer.num}
</div>
<div class="flex-1">
<span class="text-white font-medium">{layer.name}</span>
<span class="text-gray-500 ml-2">- {layer.protocols}</span>
<span class="text-surface-100 font-medium">{layer.name}</span>
<span class="text-surface-500 ml-2">- {layer.protocols}</span>
</div>
{#if layer.lb !== '-'}
<span class="px-3 py-1 rounded-full text-sm font-medium
@ -134,15 +134,15 @@
<div class="mt-6 grid grid-cols-3 gap-4 text-center">
<div class="p-3 rounded-lg bg-blue-500/10 border border-blue-500/30">
<div class="text-blue-400 font-semibold">Layer 7 (ALB)</div>
<div class="text-gray-400 text-sm mt-1">Sees HTTP content</div>
<div class="text-surface-400 text-sm mt-1">Sees HTTP content</div>
</div>
<div class="p-3 rounded-lg bg-purple-500/10 border border-purple-500/30">
<div class="text-purple-400 font-semibold">Layer 4 (NLB)</div>
<div class="text-gray-400 text-sm mt-1">Sees IP + Port</div>
<div class="text-surface-400 text-sm mt-1">Sees IP + Port</div>
</div>
<div class="p-3 rounded-lg bg-orange-500/10 border border-orange-500/30">
<div class="text-orange-400 font-semibold">Layer 3 (GLB)</div>
<div class="text-gray-400 text-sm mt-1">Network gateway</div>
<div class="text-surface-400 text-sm mt-1">Network gateway</div>
</div>
</div>
</div>
@ -150,70 +150,70 @@
<!-- How They Work -->
<section class="mb-12">
<h2 class="text-xl font-semibold text-white mb-4">How They Work</h2>
<h2 class="text-xl font-semibold text-surface-100 mb-4">How They Work</h2>
<div class="grid md:grid-cols-2 gap-6">
<!-- L4 -->
<div class="bg-gray-800/50 rounded-xl p-6 border border-purple-500/30">
<div class="card border-purple-500/30">
<h3 class="text-lg font-semibold text-purple-400 mb-4">Layer 4 Load Balancer</h3>
<div class="space-y-4">
<div class="flex items-start gap-3">
<div class="w-6 h-6 rounded-full bg-purple-500/20 flex items-center justify-center text-purple-400 text-sm font-bold">1</div>
<div>
<div class="text-white font-medium">Extract 5-tuple</div>
<div class="text-gray-400 text-sm">Source IP, Source Port, Dest IP, Dest Port, Protocol</div>
<div class="text-surface-100 font-medium">Extract 5-tuple</div>
<div class="text-surface-400 text-sm">Source IP, Source Port, Dest IP, Dest Port, Protocol</div>
</div>
</div>
<div class="flex items-start gap-3">
<div class="w-6 h-6 rounded-full bg-purple-500/20 flex items-center justify-center text-purple-400 text-sm font-bold">2</div>
<div>
<div class="text-white font-medium">Apply hash algorithm</div>
<div class="text-gray-400 text-sm">Deterministic routing based on connection info</div>
<div class="text-surface-100 font-medium">Apply hash algorithm</div>
<div class="text-surface-400 text-sm">Deterministic routing based on connection info</div>
</div>
</div>
<div class="flex items-start gap-3">
<div class="w-6 h-6 rounded-full bg-purple-500/20 flex items-center justify-center text-purple-400 text-sm font-bold">3</div>
<div>
<div class="text-white font-medium">Forward entire connection</div>
<div class="text-gray-400 text-sm">All packets in session go to same backend</div>
<div class="text-surface-100 font-medium">Forward entire connection</div>
<div class="text-surface-400 text-sm">All packets in session go to same backend</div>
</div>
</div>
</div>
<div class="mt-4 p-3 bg-purple-500/10 rounded-lg">
<div class="text-purple-300 text-sm font-medium">Key insight:</div>
<div class="text-gray-400 text-sm">Cannot see inside the packet payload - only network headers</div>
<div class="text-surface-400 text-sm">Cannot see inside the packet payload - only network headers</div>
</div>
</div>
<!-- L7 -->
<div class="bg-gray-800/50 rounded-xl p-6 border border-blue-500/30">
<div class="card border-blue-500/30">
<h3 class="text-lg font-semibold text-blue-400 mb-4">Layer 7 Load Balancer</h3>
<div class="space-y-4">
<div class="flex items-start gap-3">
<div class="w-6 h-6 rounded-full bg-blue-500/20 flex items-center justify-center text-blue-400 text-sm font-bold">1</div>
<div>
<div class="text-white font-medium">Terminate connection</div>
<div class="text-gray-400 text-sm">Client connects to LB, LB connects to backend</div>
<div class="text-surface-100 font-medium">Terminate connection</div>
<div class="text-surface-400 text-sm">Client connects to LB, LB connects to backend</div>
</div>
</div>
<div class="flex items-start gap-3">
<div class="w-6 h-6 rounded-full bg-blue-500/20 flex items-center justify-center text-blue-400 text-sm font-bold">2</div>
<div>
<div class="text-white font-medium">Parse HTTP request</div>
<div class="text-gray-400 text-sm">Read URL path, headers, cookies, body</div>
<div class="text-surface-100 font-medium">Parse HTTP request</div>
<div class="text-surface-400 text-sm">Read URL path, headers, cookies, body</div>
</div>
</div>
<div class="flex items-start gap-3">
<div class="w-6 h-6 rounded-full bg-blue-500/20 flex items-center justify-center text-blue-400 text-sm font-bold">3</div>
<div>
<div class="text-white font-medium">Apply routing rules</div>
<div class="text-gray-400 text-sm">/api/* to API servers, /static/* to CDN</div>
<div class="text-surface-100 font-medium">Apply routing rules</div>
<div class="text-surface-400 text-sm">/api/* to API servers, /static/* to CDN</div>
</div>
</div>
</div>
<div class="mt-4 p-3 bg-blue-500/10 rounded-lg">
<div class="text-blue-300 text-sm font-medium">Key insight:</div>
<div class="text-gray-400 text-sm">Full visibility into application data - can route by content</div>
<div class="text-surface-400 text-sm">Full visibility into application data - can route by content</div>
</div>
</div>
</div>
@ -221,23 +221,23 @@
<!-- Feature Comparison Table -->
<section class="mb-12">
<h2 class="text-xl font-semibold text-white mb-4">Feature Comparison</h2>
<h2 class="text-xl font-semibold text-surface-100 mb-4">Feature Comparison</h2>
<div class="bg-gray-800/50 rounded-xl border border-gray-700 overflow-hidden">
<div class="bg-surface-900 rounded-xl border border-surface-800 overflow-hidden">
<table class="w-full">
<thead>
<tr class="border-b border-gray-700">
<th class="text-left p-4 text-gray-400 font-medium">Feature</th>
<tr class="border-b border-surface-800">
<th class="text-left p-4 text-surface-400 font-medium">Feature</th>
<th class="text-left p-4 text-purple-400 font-medium">Layer 4 (NLB)</th>
<th class="text-left p-4 text-blue-400 font-medium">Layer 7 (ALB)</th>
</tr>
</thead>
<tbody>
{#each features as feature, i}
<tr class="border-b border-gray-700/50 {i % 2 === 0 ? 'bg-gray-800/30' : ''}">
<td class="p-4 text-white font-medium">{feature.name}</td>
<td class="p-4 text-gray-300">{feature.l4}</td>
<td class="p-4 text-gray-300">{feature.l7}</td>
<tr class="border-b border-surface-800 {i % 2 === 0 ? 'bg-surface-950/40' : ''}">
<td class="p-4 text-surface-100 font-medium">{feature.name}</td>
<td class="p-4 text-surface-300">{feature.l4}</td>
<td class="p-4 text-surface-300">{feature.l7}</td>
</tr>
{/each}
</tbody>
@ -247,28 +247,28 @@
<!-- When to Use -->
<section class="mb-12">
<h2 class="text-xl font-semibold text-white mb-4">When to Use Each</h2>
<h2 class="text-xl font-semibold text-surface-100 mb-4">When to Use Each</h2>
<ComparisonTable options={comparisonOptions} />
</section>
<!-- AWS Services -->
<section class="mb-12">
<h2 class="text-xl font-semibold text-white mb-4">AWS Load Balancer Types</h2>
<h2 class="text-xl font-semibold text-surface-100 mb-4">AWS Load Balancer Types</h2>
<div class="grid md:grid-cols-2 lg:grid-cols-4 gap-4">
{#each awsServices as service}
<div class="bg-gray-800/50 rounded-xl p-4 border border-gray-700 hover:border-gray-500 transition-colors">
<div class="bg-surface-900 rounded-xl p-4 border border-surface-800 hover:border-surface-700 transition-colors">
<div class="flex items-center gap-2 mb-2">
<span class="text-lg font-bold text-white">{service.name}</span>
<span class="text-lg font-bold text-surface-100">{service.name}</span>
<span class="px-2 py-0.5 rounded text-xs font-medium
{service.layer === 'L7' ? 'bg-blue-500/20 text-blue-400' : ''}
{service.layer === 'L4' ? 'bg-purple-500/20 text-purple-400' : ''}
{service.layer === 'L3/L4' ? 'bg-orange-500/20 text-orange-400' : ''}
{service.layer === 'L4/L7' ? 'bg-gray-500/20 text-gray-400' : ''}">
{service.layer === 'L4/L7' ? 'bg-surface-700/40 text-surface-300' : ''}">
{service.layer}
</span>
</div>
<p class="text-gray-400 text-sm">{service.use}</p>
<p class="text-surface-400 text-sm">{service.use}</p>
</div>
{/each}
</div>
@ -276,47 +276,47 @@
<!-- Decision Guide -->
<section class="mb-12">
<h2 class="text-xl font-semibold text-white mb-4">Quick Decision Guide</h2>
<h2 class="text-xl font-semibold text-surface-100 mb-4">Quick Decision Guide</h2>
<div class="bg-gray-800/50 rounded-xl p-6 border border-gray-700">
<div class="card">
<div class="space-y-4">
<div class="flex items-center gap-4 p-4 bg-purple-500/10 rounded-lg border border-purple-500/30">
<div class="text-2xl">1M+</div>
<div>
<div class="text-white font-medium">Need millions of requests/second?</div>
<div class="text-gray-400 text-sm">Use NLB (Layer 4) - designed for extreme performance</div>
<div class="text-surface-100 font-medium">Need millions of requests/second?</div>
<div class="text-surface-400 text-sm">Use NLB (Layer 4) - designed for extreme performance</div>
</div>
</div>
<div class="flex items-center gap-4 p-4 bg-blue-500/10 rounded-lg border border-blue-500/30">
<div class="text-2xl">/api</div>
<div>
<div class="text-white font-medium">Need path-based routing?</div>
<div class="text-gray-400 text-sm">Use ALB (Layer 7) - can route by URL, headers, cookies</div>
<div class="text-surface-100 font-medium">Need path-based routing?</div>
<div class="text-surface-400 text-sm">Use ALB (Layer 7) - can route by URL, headers, cookies</div>
</div>
</div>
<div class="flex items-center gap-4 p-4 bg-purple-500/10 rounded-lg border border-purple-500/30">
<div class="text-2xl">IP</div>
<div>
<div class="text-white font-medium">Need static IP addresses?</div>
<div class="text-gray-400 text-sm">Use NLB (Layer 4) - provides static IPs per AZ</div>
<div class="text-surface-100 font-medium">Need static IP addresses?</div>
<div class="text-surface-400 text-sm">Use NLB (Layer 4) - provides static IPs per AZ</div>
</div>
</div>
<div class="flex items-center gap-4 p-4 bg-blue-500/10 rounded-lg border border-blue-500/30">
<div class="text-2xl">WAF</div>
<div>
<div class="text-white font-medium">Need WAF or advanced security?</div>
<div class="text-gray-400 text-sm">Use ALB (Layer 7) - integrates with AWS WAF</div>
<div class="text-surface-100 font-medium">Need WAF or advanced security?</div>
<div class="text-surface-400 text-sm">Use ALB (Layer 7) - integrates with AWS WAF</div>
</div>
</div>
<div class="flex items-center gap-4 p-4 bg-gray-700/50 rounded-lg border border-gray-600">
<div class="flex items-center gap-4 p-4 bg-surface-800/60 rounded-lg border border-surface-800">
<div class="text-2xl">DB</div>
<div>
<div class="text-white font-medium">Load balancing databases or non-HTTP?</div>
<div class="text-gray-400 text-sm">Use NLB (Layer 4) - protocol agnostic</div>
<div class="text-surface-100 font-medium">Load balancing databases or non-HTTP?</div>
<div class="text-surface-400 text-sm">Use NLB (Layer 4) - protocol agnostic</div>
</div>
</div>
</div>
@ -325,41 +325,41 @@
<!-- Real World Examples -->
<section>
<h2 class="text-xl font-semibold text-white mb-4">Real World Examples</h2>
<h2 class="text-xl font-semibold text-surface-100 mb-4">Real World Examples</h2>
<div class="grid md:grid-cols-2 gap-6">
<div class="bg-gray-800/50 rounded-xl p-6 border border-gray-700">
<h3 class="text-lg font-semibold text-white mb-3">E-commerce Platform</h3>
<div class="card">
<h3 class="text-lg font-semibold text-surface-100 mb-3">E-commerce Platform</h3>
<div class="space-y-2 text-sm">
<div class="flex items-center gap-2">
<span class="px-2 py-0.5 rounded bg-blue-500/20 text-blue-400">ALB</span>
<span class="text-gray-300">/api/* to API servers</span>
<span class="text-surface-300">/api/* to API servers</span>
</div>
<div class="flex items-center gap-2">
<span class="px-2 py-0.5 rounded bg-blue-500/20 text-blue-400">ALB</span>
<span class="text-gray-300">/static/* to static content servers</span>
<span class="text-surface-300">/static/* to static content servers</span>
</div>
<div class="flex items-center gap-2">
<span class="px-2 py-0.5 rounded bg-blue-500/20 text-blue-400">ALB</span>
<span class="text-gray-300">Sticky sessions for shopping cart</span>
<span class="text-surface-300">Sticky sessions for shopping cart</span>
</div>
</div>
</div>
<div class="bg-gray-800/50 rounded-xl p-6 border border-gray-700">
<h3 class="text-lg font-semibold text-white mb-3">Gaming Server</h3>
<div class="card">
<h3 class="text-lg font-semibold text-surface-100 mb-3">Gaming Server</h3>
<div class="space-y-2 text-sm">
<div class="flex items-center gap-2">
<span class="px-2 py-0.5 rounded bg-purple-500/20 text-purple-400">NLB</span>
<span class="text-gray-300">UDP game traffic (low latency)</span>
<span class="text-surface-300">UDP game traffic (low latency)</span>
</div>
<div class="flex items-center gap-2">
<span class="px-2 py-0.5 rounded bg-purple-500/20 text-purple-400">NLB</span>
<span class="text-gray-300">TCP matchmaking servers</span>
<span class="text-surface-300">TCP matchmaking servers</span>
</div>
<div class="flex items-center gap-2">
<span class="px-2 py-0.5 rounded bg-purple-500/20 text-purple-400">NLB</span>
<span class="text-gray-300">Static IPs for firewall rules</span>
<span class="text-surface-300">Static IPs for firewall rules</span>
</div>
</div>
</div>