Updated Architecture
Architecture after DB deep dive
DB choice, schema, tiered storage, and sharding all change or add to the base architecture.
What changed from base architecture¶
The base architecture had a generic "Database" box. After the DB deep dive, that box becomes concrete.
Changes¶
1. Database — DynamoDB (Cassandra-compatible)
The base had an unnamed database. We now know it is DynamoDB (or Cassandra at self-hosted scale): - Write-heavy workload → LSM tree is the right engine - Messages are immutable → append-only fits perfectly - No complex joins needed → wide-column is sufficient - Auto-sharding at scale → no manual shard management
2. Schema — messages table
messages table:
PK = conversation_id
SK = seq_number (per-conversation sequence, monotonically increasing)
Attributes: message_id, sender_id, content, timestamp, type
The base architecture stored "messages." Now we know the exact key structure that enables efficient chat history pagination.
3. Tiered Storage — S3 for cold messages
Messages older than 30 days move from DynamoDB to S3. The base had a single DB layer. Now there are two:
Hot tier: DynamoDB → messages < 30 days → fast reads, expensive
Cold tier: S3 → messages > 30 days → slow reads, cheap
App server checks DynamoDB first. On miss, falls back to S3.
4. Sharding — conversation_id as partition key
The base had no sharding strategy. DynamoDB partitions automatically by conversation_id (PK). This distributes load across nodes — no single node owns all of Alice's messages. Hot partitions are handled by DynamoDB's adaptive capacity.
Updated architecture diagram¶
flowchart TD
A[Client A] -- WebSocket --> APIGW[API Gateway]
B[Client B] -- WebSocket --> APIGW
APIGW --> LB[Load Balancer]
LB --> WS1[Connection Server 1]
LB --> WS2[Connection Server 2]
LB --> WSN[Connection Server N]
WS1 --> AS[App Server]
WS2 --> AS
WSN --> AS
AS --> DDB[(DynamoDB - Hot Tier)]
AS --> REDIS[(Connection Registry - Redis)]
DDB -- cold data after 30d --> S3[(S3 - Cold Tier)]
REDIS -- lookup --> AS
AS -- route message --> WS2