Client-Server Architecture:
Client-server architecture is a model where clients (e.g. App or web browser) Request services (e.g. store, retrieve, modify) and servers provide Response to the request.
The client initiates communication by sending requests to the server over a network. The server processes these requests and returns the appropriate responses or data.
IP Address: Each computer to communicate need IP addresses for publicly deployed servers.
Domain Names: Human friendly name for IP address.
Domain Name System (DNS): Registry of domain names to IP address mapping
Proxy/Reverse Proxy
Proxy server: Middle man between client and internet. It safeguards your IP (hides) and keeps you private. P
Reverse Proxy : Middle man between internet and server. intercepts client requests.
Latency: Round trip time between request to response time for the client
Multipe data centers to reduce latency
HTTP(S): once the connection is made, to communicate http protocol is used. request has header like "GET /files HTTP/1.1 Host: .... " and body, server sends response based on the request. https is for encryption. it does not know what to interpret between the request and response. it passes content and errors as is.
API (Application Programming Interfaces): Server Interfaces (simplify the internal complexity) to the client.
REST use standard HTTP methods (Get, Post, Put, Delete) for clients and servers to communicate in structured way; Stateless, every request is independent. everything is a resource (e.g. users, orders, products). Simple, scalable, easy to cache. Limitation: Return more data at times than client required need.
Read or Retrieve existing data
GET /users/123 HTTP/1.1
Host: praveenkarri.com
Accept: application/json
Create new data
POST /users HTTP/1.1
Host: praveenkarri.com
Content-Type: application/json
Accept: application/json
{
"name": "Praveen",
"email": "test@xyz.abc".
"is_active": true
}
Update existing data
PUT /users/123 HTTP/1.1
Host: praveenkarri.com
Content-Type: application/json
Accept: application/json
{
"name": "Praveen",
"email": "test@xyz.abc".
"is_active": false
}
Delete existing data
DELETE /users/123 HTTP/1.1
Host: praveenkarri.com
Accept: application/json
GRAPHQL (Graph Query Language) lets clients ask for exactly what they need. e.g. Instead of 2 REST api calls for their need (user details and their posts), a client can ask for specific data from 2 APIs. Limitations: More processing, not easy to cache.
REST
GET /users/123
GET /users/123/posts
GRAPHQL
query{
user(id: 123){
id
name
posts {
id
title
createdAt
}
}
}
GRAPHQL Response (json)
{
"user": {
"id":123,
"name": "Praveen",
"email": "test@xyz.abc",
"posts": [
{
"id": 1,
"title": "test test",
"createdAt": "2025-01-01T00:00:00Z"
},
{
"id": 2,
"title": "test test2",
"createdAt": "2025-01-02T00:00:00Z"
}
]
}
}
Databases: dedicated server for storing, retrieving and managing data, secure.
ACID properties:
Atomicity: finish entire operation successfully or rollback to prior state (e.g. lost connection during a transaction ).
Consistency: any change maintain data integrity or rollback (e.g. bank balance is always positive after a transaction)
Isolation: any read or write is not impacted by separate transaction (e.g. 2 transactions hitting same place - either both are aborted or keep in queue so lesser aborts happen).
Durability: successful commits are permanent (e.g. once stored, crashes/outage etc should not impact the completed transaction).
Factors to decide DB: Structure of the data, Query patterns, Scale.
Structured DBs (SQL)
Predefined schema
Need ACID properties. e.g. Payment transactions.
RDBMS: Mysql, Oracle, SQL server, Posgres
Unstructured DBs (NoSQL)
High scalability
High performance
Flexible schema
Key-Value DBs
Document DBs: datatypes (e.g. product different attributes). varied queries. MongoDB, Couch Base.
Graph DBs: Nodes (data entity/object), Edges (relationship/connections). Properties (additional context for nodes, edges). e.g. social network user connections like friends, followers. recommendations based on item connections and user preferences. Logistics network routing/supply chain. Neo4j, Amazon Neptune, nebula graph.
(Wide) Columnar DBs: increasing data (e.g. uber locations), finite queries. Each row can have varied columns in the same table. Cassandra, HBase.
Example Use cases
Caching: Not to hit DB too often, need low latency response. Use Key-Value store (Redis, MemCached, Hazelcast, etcd).
File storage: Images, Videos. Use Blob storage (S3), Content Delivery Network (CDN) for global access for blobs.
Search: Search title, product, etc (reduce cost).
Text search engine: Use Elastic search, Solr - both use Lucene internally.
Fuzzy search (is a technique): wrong spelling (Airport, Airprot) with edit distance:2. Should not be used as primary.
Metrics tracking: Timeseries DB - Always update sequential/appended. Regular updates. Use Influx DB, OpenTSDB.
Analytics: Data Warehouse, Large DB dump, Offline reporting. Use Hadoop.
Scaling
Vertical scaling: As user base grows, requests grow, add more cpu, ram, storage. scaling up. Limitations: cannot upgrade forever, more power more expensive, single point of failure.
Horizonal scaling: More servers sharing the load. distribute the workload. More scalable, fault tolerant. Availability, Reliability (even if 1 server fails, it works).
Load Balancer: Distributes traffic between clients and servers. Healthy servers are used. Algos: Round-Robin, Least connections IP Hashing
Storage scaling: Other than vertical scaling (growing storage size)
Database Indexing: Lookup table with index and pointers to actual data rows in the table. typically on most queries on column keys (primary key, foreign keys) and where conditions. Indexing speeds up reads, slows down writing (to update index).
Replication: Copies across multiple servers. Primary write replica, copied to multiple read replicas. reduces read load (if primary is down, one of the read replica becomes primary write replica).
Sharding (aka Horizontal partitioning): Divide the large DB into smaller DBs (Shards) to distribute the DB and reduce load and sizes. splitting the rows and hence called as horizonal partitioning. e.g. by user id in rows.
Vertical partitioning: Split DB by columns. e.g. User table has profile data, login data, billing info (in multiple columns). Queries become slow if there are too many columns. split user table into multiple tables.
Caching: Optimize the performance of the application by keeping frequently accessed data in cache. use time-to-live (ttl) value for check on outdated data.
Denormalization: reduces number of joins by combining two tables. might have duplicate data. e.g. user and orders tables merged. leads to increased storage and complex updates.
Distributed systems: scaling of servers, DBs and data centers lead to distributed systems.
Fundamental principle: CAP theorem - No distributed system can achieve all below three at the same time.
Consistency
Availability
Partition Tolerance
Choose between Consistency+Partition tolerance or Availability+Partition tolerance.
Real time applications: Live chat applications, online multiplayer games, stock market dashboards. HTTP request response works for static web pages but too slow for real time apps.
Frequent polling: checks every x seconds ( 1-way communication). increases server load. most responses are empty or no new data.
WebSockets: 2-way communication with a persisted TCP connection. no polling required. client or server sends without polling. (e.g. chat)
WebHooks: Receiver registers webhook url with the provider. When an event occurs at provider, the providers sends the http post request to the webhook url with the event details. Reduces unnecessary api calls, saves server resources. e.g. Receiver registers payment api url (payment success/fail, amount, etc) with payment provider. When Receiver's customer pays the amount for an order through the payment provider (event), Payment provider sens the POST request to receiver and receiver can use that info to either place an order or not.
Micro services: Break monoliths into micros services (e.g. orders, payment, shipping, inventory) that work together. independently serve. Direct API calls (synchronous) aren't always efficient.
Message Queues: Asynchronous. Producer sends a message to the queue (temp hold) and Consumer retrieves the message and process it. Decouple services and prevent overload.
Rate limiting: Client can send x requests in a time period. Blocks requests temporarily and sends errors to the clients. e.g. 100 req/min. API gateway can handle this.
Fixed window: # of requests within a window limit (e.g. every 1 hour limit). simple to implement.
Sliding window: # of requests within sliding window (e.g. last 60min). complex to implement.
Token bucket: A bucket has tokens, each request picks up a token. Helps during occasional spikes. complex to implement.
API Gateway: Centralized service to handle below things before routing to micro services API calls. single entry point for the clients, would not expose microservice directly. simplifies API management, improves scalability and security.
Authentication
Rate Limiting
Logging
Monitoring
Request Routing
etc.
Idempotency: Two simiar requests produce the same result. If two payment requests are sent (due to refresh or server failures) with same unique id, if one is already handled then it ignores the duplicate request.