StreamHub started as one server. Today it runs through GeoDNS, a CDN, API gateway, stateless services, Redis, Postgres with read replicas, Kafka, and S3. This article maps the toolbox and shows where each piece fits.
The complete toolbox
Cloud building blocks toolbox
NETWORKRoute 53DNS + GeoDNS
NETWORKCloudFrontCDN edge
NETWORKAWS ALBL7 balance
NETWORKAPI Gatewayauth + throttle
COMPUTEAmazon EKScontainer fleet
DATABASEElastiCacheRedis cache
DATABASERDS / Aurorarelational
DATABASEDynamoDBkey-value
INTEGRATIONMSK / SQSasync events
STORAGEAmazon S3object store
ANALYTICSOpenSearchfull-text
OPSCloudWatchmetrics · logs
SECURITYAWS WAFedge security
SECURITYCognitoidentity
COMPUTELambdaserverless
INTEGRATIONSNS / SESnotify
| Block | Purpose | StreamHub usage |
|---|---|---|
| DNS / GeoDNS | Resolve hostname; route to nearest region | streamhub.com → US/EU/APAC clusters |
| CDN | Cache static and edge-cacheable content at PoPs | Video segments, thumbnails, JS bundles |
| Load balancer | Distribute traffic across app servers | ALB across EKS pods |
| API gateway | Auth, rate limiting, routing, TLS termination | Kong at edge; JWT validation |
| Cache (Redis) | Sub-ms reads for hot data | Stream metadata, sessions, rate limits |
| Database | Durable source of truth | Postgres primary + read replicas |
| Message queue | Async decoupling and spike absorption | Kafka events, RabbitMQ jobs |
| Object store | Blob storage for files and media | S3 for VOD, clips, profile images |
| Search index | Full-text and autocomplete queries | Elasticsearch for stream discovery |
DNS / GeoDNS
PurposeResolve hostname; route to nearest regionStreamHub usagestreamhub.com → US/EU/APAC clustersCDN
PurposeCache static and edge-cacheable content at PoPsStreamHub usageVideo segments, thumbnails, JS bundlesLoad balancer
PurposeDistribute traffic across app serversStreamHub usageALB across EKS podsAPI gateway
PurposeAuth, rate limiting, routing, TLS terminationStreamHub usageKong at edge; JWT validationCache (Redis)
PurposeSub-ms reads for hot dataStreamHub usageStream metadata, sessions, rate limitsDatabase
PurposeDurable source of truthStreamHub usagePostgres primary + read replicasMessage queue
PurposeAsync decoupling and spike absorptionStreamHub usageKafka events, RabbitMQ jobsObject store
PurposeBlob storage for files and mediaStreamHub usageS3 for VOD, clips, profile imagesSearch index
PurposeFull-text and autocomplete queriesStreamHub usageElasticsearch for stream discovery
How blocks connect
StreamHub production architecture (AWS)
Typical request path
- User resolves
streamhub.comvia DNS → GeoDNS routes to nearest region. - Static assets served from CDN edge; cache miss fetches from origin once.
- API requests hit load balancer → gateway (auth + rate limit) → app service.
- App reads Redis cache → Postgres on miss → publishes events to Kafka on writes.
- Media uploads go directly to S3 via presigned URLs; transcode workers pull from queue.
Growth stages
Stage 1EC2 + Postgres on one box
Stage 2RDS + separate EC2 app
Stage 3ALB + ASG + ElastiCache Redis
Stage 4CloudFront + S3 media origin
Stage 5MSK Kafka + EKS worker fleet
Stage 6Sharded RDS + multi-region EKS
| Aspect | Stage 1–2 (0–100K users) | Stage 5–6 (10M+ users) |
|---|---|---|
| Compute | Single server → LB + app fleet | Multi-region K8s with HPA |
| Data | Single Postgres | Sharded DB + read replicas + Redis cluster |
| Media | Local disk | S3 + CDN + transcoding pipeline |
| Async | None → simple queue | Kafka + worker fleets + event-driven fan-out |
| Ops | Manual deploys | Observability stack, SLOs, multi-region failover |
Compute
Stage 1–2 (0–100K users)Single server → LB + app fleetStage 5–6 (10M+ users)Multi-region K8s with HPAData
Stage 1–2 (0–100K users)Single PostgresStage 5–6 (10M+ users)Sharded DB + read replicas + Redis clusterMedia
Stage 1–2 (0–100K users)Local diskStage 5–6 (10M+ users)S3 + CDN + transcoding pipelineAsync
Stage 1–2 (0–100K users)None → simple queueStage 5–6 (10M+ users)Kafka + worker fleets + event-driven fan-outOps
Stage 1–2 (0–100K users)Manual deploysStage 5–6 (10M+ users)Observability stack, SLOs, multi-region failover
Choosing blocks for a new feature
Decision prompts
- Read-heavy? Add cache (Redis) and/or CDN before scaling DB replicas.
- Write spikes? Add queue to decouple; never synchronous fan-out to N services.
- Large files? Object store + CDN; never store blobs in Postgres.
- Real-time? WebSocket service + Redis pub/sub for cross-pod message relay.
- Search? Dedicated search index (Elasticsearch); don't query Postgres with LIKE.
- Global users? Multi-region with GeoDNS; accept eventual consistency or CRDTs.
Cross-cutting concerns
| Concern | Block(s) | Notes |
|---|---|---|
| Authentication | API gateway + OAuth2/OIDC | Validate JWT at edge; propagate user context |
| Rate limiting | Gateway middleware + Redis | Token bucket per user tier |
| Observability | OpenTelemetry → metrics/logs/traces | Instrument every block, not just app code |
| Idempotency | Redis or DB key store | Required wherever queues or retries exist |
| Consistency | DB transactions + outbox + cache invalidation | Pick CP or AP per entity type |
Authentication
Block(s)API gateway + OAuth2/OIDCNotesValidate JWT at edge; propagate user contextRate limiting
Block(s)Gateway middleware + RedisNotesToken bucket per user tierObservability
Block(s)OpenTelemetry → metrics/logs/tracesNotesInstrument every block, not just app codeIdempotency
Block(s)Redis or DB key storeNotesRequired wherever queues or retries existConsistency
Block(s)DB transactions + outbox + cache invalidationNotesPick CP or AP per entity type
Quick recall
Everything you need if you only revisit this box.
- Every product design combines subsets of DNS, CDN, LB, gateway, cache, DB, queue, object store.
- Add blocks when a specific bottleneck appears — don't over-engineer stage 1.
- Read path: DNS → CDN → LB → gateway → cache → DB.
- Write path: API → DB + cache invalidation + queue for async side effects.
- StreamHub journey: single server → LB → cache → CDN → queue → sharded DB → multi-region.
- Cross-cutting: auth at gateway, rate limits in Redis, observability everywhere.
Test yourself
Answer these before moving on — recall is what makes it stick.