Bird
Raised Fist0

Client-Server Architecture and Why It Is the Foundation of Every System

HLDmediumInterview freq: high
Choose your preparation mode4 modes available
🎯
Client-Server Architecture and Why It Is the Foundation of Every System
45 min · senior
senior

You are designing the core client-server communication system for a startup with 50 million daily active users (DAU). The system must support real-time messaging with end-to-end encryption, guarantee offline message delivery, and maintain a P99 latency under 200ms. The system should scale horizontally and handle peak loads gracefully while ensuring data consistency and fault tolerance.

  • End-to-end encryption mandatory for all client-server communication
  • Offline message delivery with guaranteed eventual consistency
  • P99 latency under 200ms for message send and receive
  • Support 50 million DAU with peak concurrency of 10 million active connections
  • Horizontal scalability with zero downtime deployments
📋
Guided Steps
1/5
Step 1
Choosing the Communication Protocol
Which communication protocol will you use between client and server to meet low latency and scalability requirements?
💡 Hint
Consider protocols that support persistent connections and multiplexing to reduce overhead.
Use HTTP/2 with gRPC for client-server communication - supports multiplexed streams over a single connection, reducing latency and resource usage compared to HTTP/1.1.
Mid: Names HTTP/2 or gRPC. Senior: Explains multiplexing benefits, connection reuse, and how it reduces P99 latency under 200ms at scale.
⚠️Common Wrong Answer
Using HTTP/1.1 with polling - causes excessive connection overhead and high latency, collapsing under 10M concurrent connections.
Step 2
Message Delivery and Offline Support
How will you design the system to guarantee offline message delivery and eventual consistency?
💡 Hint
Think about durable storage and message queues that preserve order and support replay.
Use Apache Kafka with conversation_id as partition key - ensures ordered, durable message storage and replay for offline clients syncing missed messages.
Mid: Names Kafka for message queue. Senior: Explains partitioning by conversation_id to maintain order and enable efficient cursor-based sync.
⚠️Common Wrong Answer
Using Redis Pub/Sub for message delivery - lacks persistence and message replay, causing message loss for offline clients.
Step 3
Ensuring End-to-End Encryption
How will you implement end-to-end encryption while maintaining server-side message routing and offline delivery?
💡 Hint
Consider client-side encryption keys and how the server handles encrypted payloads without decrypting content.
Implement client-side encryption with keys managed by clients; server routes opaque encrypted blobs without decrypting, enabling secure offline storage and delivery.
Mid: Mentions TLS for transport security. Senior: Explains client-side encryption for end-to-end security and server's role as a blind router for encrypted messages.
⚠️Common Wrong Answer
Relying only on TLS - server can decrypt messages, violating end-to-end encryption requirement.
Step 4
Scaling and Load Balancing
How will you scale the system horizontally to handle 10 million concurrent connections and maintain P99 latency under 200ms?
💡 Hint
Consider stateless servers, connection multiplexing, and load balancing strategies that minimize latency spikes.
Use Envoy proxy for L7 load balancing with sticky sessions based on user_id, combined with Kubernetes autoscaling of stateless gRPC servers to handle connection load.
Mid: Names Envoy or NGINX load balancer. Senior: Explains sticky sessions to maintain connection affinity and autoscaling to handle peak concurrency without latency degradation.
⚠️Common Wrong Answer
Using DNS round-robin without session affinity - causes connection drops and increased latency due to state loss.
Step 5
API Design for Core Client Operations
Design three core API endpoints for sending messages, syncing offline messages, and acknowledging receipt. What are their request/response structures?
💡 Hint
Think about idempotency, cursor-based sync, and acknowledgement semantics for reliable delivery.
Define SendMessage(gRPC) with encrypted payload and message_id; SyncMessages(cursor) returning ordered encrypted messages; AckMessage(message_id) confirming delivery for exactly-once semantics.
Mid: Provides basic API signatures. Senior: Details idempotency keys, cursor-based pagination for sync, and acknowledgement to support exactly-once delivery guarantees.
⚠️Common Wrong Answer
Designing SendMessage without idempotency or SyncMessages without cursor - leads to duplicate messages or inefficient full syncs.
🔌
API Design Challenge
Sketch 3 core API endpoints for the client-server system that enable sending messages, syncing offline messages, and acknowledging message receipt.
  • How does the client send a message securely to the server?
  • How does the client sync messages missed while offline?
  • How does the client acknowledge receipt to ensure delivery guarantees?
📊
Scoring Rubric
▼ Show
Must Have - 60%
  • Use of HTTP/2 or gRPC for efficient client-server communication
  • Kafka with conversation_id partition key for message ordering and offline delivery
  • Client-side encryption for end-to-end security
  • Load balancing with sticky sessions to maintain connection affinity
Good to Have - 30%
  • Idempotent APIs with cursor-based sync for efficient offline message retrieval
  • Presence detection using Redis TTL to optimize delivery
  • Autoscaling infrastructure to handle peak concurrency
  • Monitoring and tracing to ensure latency SLAs
Bonus - 10%
  • Use of Envoy proxy for advanced L7 routing and observability
  • Designing APIs with exactly-once delivery semantics
HTTP polling at 50M DAU: 50M reconnects/min just to check for messages - collapses under load
Using Redis Pub/Sub for message persistence - leads to message loss for offline clients
Relying solely on TLS without client-side encryption - breaks end-to-end encryption guarantees
DNS round-robin load balancing without session affinity - causes connection drops and latency spikes
Designing APIs without idempotency or cursor-based sync - leads to duplicates and inefficient data transfer
Stateful servers without autoscaling - causes downtime and inability to handle peak loads
✅
Model Answer
▼ Reveal

The system uses HTTP/2 with gRPC for efficient client-server communication, Apache Kafka partitioned by conversation_id for ordered durable messaging, and client-side encryption for end-to-end security. Envoy proxy with sticky sessions and Kubernetes autoscaling ensures horizontal scaling and low latency. The APIs are designed with idempotent SendMessage, cursor-based SyncMessages, and AckMessage for reliable delivery with exactly-once semantics.

  • Use HTTP/2 with gRPC to reduce connection overhead and achieve P99 latency under 200ms
  • Partition Kafka topics by conversation_id to maintain message order and enable efficient offline sync
  • Implement client-side encryption so server routes encrypted blobs without decrypting, preserving end-to-end security
  • Employ Envoy proxy with sticky sessions to maintain connection affinity and reduce latency spikes
  • Autoscale stateless gRPC servers on Kubernetes to handle 10 million concurrent connections
  • Design APIs with idempotency keys for SendMessage, cursor-based pagination for SyncMessages, and acknowledgements for exactly-once delivery
  • Use Redis TTL keys for presence detection to optimize offline message delivery paths
  • Integrate monitoring and distributed tracing to maintain SLA and quickly diagnose latency issues
  • HTTP/2 with gRPC for multiplexed, low-latency client-server communication
  • Apache Kafka with conversation_id partition key for ordered, durable message storage and offline sync
  • Client-side end-to-end encryption with server as blind router to protect message confidentiality
  • Envoy proxy with sticky sessions and Kubernetes autoscaling for horizontal scaling and low latency
  • gRPC APIs with idempotent SendMessage, cursor-based SyncMessages, and AckMessage for reliable delivery
  • TLS for transport security combined with client-side encryption for defense in depth
  • Use of Redis TTL for presence detection to optimize offline delivery paths
  • Monitoring with Prometheus and distributed tracing (Jaeger) to maintain P99 latency SLAs

Practice

(1/5)
1. In the request flow for posting a new answer, at step 5 the Feed Generator consumes messages from Kafka. What happens if the Feed Generator detects a malformed message at this step?
easy
A. The Feed Generator sends the malformed message to a dead-letter queue for later inspection
B. The Feed Generator pauses consumption and retries the malformed message until fixed
C. The Feed Generator discards the message and continues processing the next message
D. The Feed Generator crashes, causing the entire feed update pipeline to stop

Solution

  1. Step 1: Understand Feed Generator error handling

    Discarding (A) loses data silently; pausing and retrying (B) blocks the pipeline indefinitely; crashing (D) causes system downtime.
  2. Step 2: Dead-letter queue usage

    Sending malformed messages to a dead-letter queue (C) isolates bad data for manual or automated inspection without blocking the main pipeline.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Dead-letter queue isolates bad messages without blocking processing [check]
Hint: Dead-letter queues isolate bad messages, keep pipeline flowing [check]
Common Mistakes:
2. In the Kafka consumer flow, at step 4 the consumer commits offsets after processing messages. What happens if the consumer crashes before committing the offset?
easy
A. The messages are reprocessed after restart, causing potential duplicates
B. The messages are lost and never reprocessed
C. Kafka automatically commits offsets on behalf of the consumer
D. The consumer group coordinator reassigns partitions immediately

Solution

  1. Step 1: Trace offset commit role at Step 4

    Offset commit marks messages as processed; if not committed, Kafka considers them unprocessed.
  2. Step 2: Understand crash impact

    If consumer crashes before commit, on restart it reprocesses messages from last committed offset, causing duplicates.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Uncommitted offsets cause message reprocessing [check]
Hint: Uncommitted offset -> message replay on restart [OK]
Common Mistakes:
3. If the Booking Service loses connectivity to the Calendar Availability Service during booking confirmation, what is the most likely failure mode experienced by the user?
medium
A. The booking is queued locally and confirmed later without user notification
B. The booking request times out and the user sees an error without confirmation
C. The booking is confirmed but the calendar is not updated, causing double bookings
D. The system automatically retries and confirms booking without user delay

Solution

  1. Step 1: Trace failure impact on booking flow

    Loss of connectivity prevents immediate calendar update, risking inconsistency.
  2. Step 2: Analyze failure handling

    Immediate confirmation without calendar update (A) risks double bookings; timeout with error (B) hurts UX; automatic retry without delay (D) is unrealistic under network failure. Local queuing (C) allows eventual consistency with delayed confirmation.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Local queuing delays confirmation but prevents data loss [check]
Hint: Booking queues locally on calendar service failure, delaying confirmation [check]
Common Mistakes:
4. If the centralized auto-increment ID generator service crashes unexpectedly, what is the immediate failure observed in the system?
medium
A. The system automatically switches to UUID generation without data loss
B. The system falls back to generating IDs based on timestamps, risking collisions
C. New record inserts block indefinitely until the ID generator recovers, causing request timeouts
D. Duplicate IDs are generated causing data corruption

Solution

  1. Step 1: Understand centralized auto-increment role

    It guarantees unique, sequential IDs for new records.
  2. Step 2: Trace failure impact

    If it crashes and restarts without persisting last ID, it may reset counters causing duplicate IDs, leading to data corruption.
  3. Final Answer:

    Option D -> Option D
  4. Quick Check:

    Crash without persistence -> duplicate IDs and corruption [check]
Hint: Centralized ID crash -> duplicate IDs corrupt data [check]
Common Mistakes:
5. At 10x scale, which component in a distributed tracing system is most likely to become the bottleneck first, and why?
hard
A. Trace Collector, because it must synchronously process all incoming spans causing CPU saturation
B. Centralized Trace Storage, because indexing and querying massive trace volumes overwhelms storage I/O
C. Trace Context Propagation headers, because large headers increase network overhead and cause packet loss
D. Instrumentation Library, because injecting trace context adds significant latency per request

Solution

  1. Step 1: Analyze component scaling challenges

    Centralized Trace Storage must index and store exponentially more spans at 10x scale, stressing storage I/O and query performance.
  2. Step 2: Evaluate other components

    Trace Collector is often horizontally scalable and asynchronous, reducing CPU bottleneck risk. Instrumentation overhead is minimal per request. Trace headers increase size but not enough to cause packet loss at scale.
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    Storage I/O overwhelmed first at 10x scale [check]
Hint: Storage I/O chokes first at massive trace volume scale [OK]
Common Mistakes:
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard