Skip to content
SparkTime, home
System Design From Zero to Interview-Ready
Lessons
1 · System Design Foundations
2 · APIs and Communication
3 · Capacity Estimation
4 · Core Building Blocks
5 · Databases
6 · Distributed Systems
7 · Reliability and Operations
8 · Architecture and Security
9 · Interview Method and Foundation Case Studies
10 · Real-World Case Studies
11 · Large-Scale Case Studies
12 · Interview Readiness
Lesson 41 of 45

Lesson 41 · Large-Scale Case Studies

Design a Ride-Hailing System: Location, Matching and Real-Time Updates

Design the core of a ride-hailing app: ingesting hundreds of thousands of driver location updates per second, a geospatial index of available drivers, matching riders to drivers with offers and timeouts, never assigning one driver twice, a trip state machine, live tracking for riders, city-based partitioning, payments, failures, privacy and fraud.

On this page

Key takeaways

  • The hot write path is driver locations: hundreds of thousands of small updates per second that need to be current, not durable, so keep the latest position in memory and stream the history elsewhere.
  • Find nearby drivers with a geospatial index that buckets positions into cells (grid, geohash, H3 or S2) and searches the pickup cell and its neighbours.
  • Match by sending an offer to the best candidate with a short timeout, and reserve the driver with a conditional update so one driver can never be assigned to two riders.
  • Model trips as a state machine with conditional transitions, and push live locations to the rider over a persistent connection.
  • Partition everything by city or region, because matching is local, and protect location data as sensitive personal information.

A rider in Bengaluru opens the app and taps "Book". Within a few seconds, the app must find drivers who are close by right now, pick a good one, ask that driver, wait for an answer, try someone else if the driver declines, and then show the rider a car moving towards them on a map, updated every few seconds. Meanwhile half a million other drivers across the country are reporting their positions every four seconds, and a concert has just ended near the stadium, so two thousand people are booking from the same few streets.

Ride-hailing is a favourite SDE-2 question because it combines a very high-rate write stream (locations), a specialised index (geospatial), a correctness problem under contention (assigning drivers), and real-time updates. The design here is generic: it does not describe how any particular company builds its systems.

What you will learn

#
  • How to estimate location ingestion, matching and live-tracking load.
  • Why the latest location belongs in memory and the history in a stream.
  • Geospatial indexing with grids, geohash, H3 and S2, with a runnable example.
  • Matching with offers, timeouts and fallbacks.
  • How to prevent assigning one driver to two riders.
  • Trip state machines, live tracking, payments and partitioning by city.
  • Failures, privacy and fraud.

1. The problem

#

Riders request a ride from a pickup point to a drop point. The system finds nearby available drivers, offers the ride to a driver, and on acceptance creates a trip. The rider sees the driver's position live until pickup and during the trip. At the end, the fare is charged.

2. Clarify the requirements

#

Question

Assumed answer

Impact

Scale and geography?

Many cities in India; up to 500,000 drivers online at peak

Partition by city

How often do drivers report location?

Every 4 seconds while online

Write rate

How is a driver chosen?

Best estimated time to pickup, among available drivers of the right vehicle type

Geospatial search plus ETA

How does a driver accept?

An offer appears on the driver's app; they have about 15 seconds to accept

Offers with timeouts

Ride types?

Several (bike, auto-rickshaw, car); shared rides out of scope

Filters

Pricing?

Fare estimate before booking; surge pricing mentioned briefly

Pricing service

Payments?

Through the payment platform (article 39) at trip end

Saga after trip

Live tracking?

Rider sees the driver every few seconds

Real-time push

Functional requirements: drivers go online, report location and receive offers; riders get fare estimates, request rides, see the assigned driver live; trips move through states to completion; fares are charged.

Non-functional requirements

Quality

Target

Match time

p95 under 10 seconds from request to driver assigned (where drivers exist)

Correctness

A driver is never assigned two concurrent trips; a ride request creates at most one trip

Location freshness

Matching uses locations at most about 10 seconds old

Availability

99.95%; problems in one city do not affect others

Privacy

Precise locations visible only to the matched counterpart, and retained only as long as needed

3. Assumptions and scale estimation

#
Code
Drivers online at peak: 500,000; one location update every 4 s  -> 125,000 location writes/s at peakRides: 10 million/day -> about 116 requests/s average, about 350/s at peak (factor 3)Fare estimates: about 10 per request -> about 3,500/s at peakActive trips (average 20 minutes, including pickup): 10M x 20 / 1,440 = about 139,000 on average,  about 420,000 at peakLive tracking: each active trip's rider gets an update every 4 s -> about 105,000 pushes/s at peakLocation history: 125,000/s x 100 bytes = 12.5 MB/s -> about 1 TB/day (if kept for every ping)Hot index memory: 500,000 drivers x ~200 bytes (id, position, status, timestamp, cell) = about 100 MB

Conclusions:

  • Location writes (125,000 per second) are the dominant load, but each is tiny and only the latest value matters for matching. The hot index is small enough to keep entirely in memory (about 100 MB nationwide).
  • Ride requests are modest in number but latency-critical and contended in hotspots.
  • History is large and append-only: a stream into time-series or object storage.

4. API design

#

Drivers and riders keep persistent connections (WebSockets, article 05; RFC 6455) through connection gateways like those in the chat design (article 34).

Code
Driver app -> server (over the connection):  LOCATION  { lat, lng, heading, speed, accuracy_m, client_ts }      every 4 s while online  STATUS    { status: "online" | "offline" }Server -> driver app:  OFFER     { offer_id, pickup, drop, fare_estimate, expires_in_s: 15 }Driver app -> server (HTTP, idempotent):  POST /v1/offers/{offerId}/accept      -> 200 { trip_id } | 409 offer expired or taken  POST /v1/offers/{offerId}/decline  POST /v1/trips/{tripId}/arrived | /start | /complete      (state transitions)Rider app (HTTP):  POST /v1/fare-estimates  { pickup, drop, ride_type }      -> { estimate, estimate_id, valid_for_s }  POST /v1/ride-requests   Idempotency-Key: ...  { pickup, drop, ride_type, estimate_id }       -> 201 { request_id, status: "searching" }  POST /v1/ride-requests/{id}/cancelServer -> rider app (over the connection):  MATCHED { trip_id, driver, vehicle, eta }   DRIVER_LOCATION { lat, lng, eta }   TRIP_STATUS { ... }

5. Data model

#
Code
In memory (location service, per city partition):  driver_state: driver_id -> { lat, lng, cell, status (available, offered, on_trip, offline),                               vehicle_type, updated_at }  cell_index:   cell -> set of available driver_ids (by vehicle type)Durable (per city or region shard):  ride_requests (request_id PK, rider_id, pickup, drop, ride_type, status, created_at, idem_key)                UNIQUE (rider_id, idem_key)  offers        (offer_id PK, request_id, driver_id, status (sent, accepted, declined, expired),                 expires_at)  driver_assignment (driver_id PK, current_trip_id, current_offer_id, version)   -- the reservation record  trips         (trip_id PK, request_id UNIQUE, rider_id, driver_id, status, timestamps, fare)Stream and time series:  location events -> stream -> trip tracks (by trip_id) and analytics; retention limited

The UNIQUE (request_id) on trips guarantees one trip per request; the driver_assignment row is where the "one driver, one trip" rule is enforced.

6. Baseline architecture

#
Code
Driver apps --POST location--> API --> UPDATE drivers SET lat, lng (database)Rider request --> API --> SELECT drivers ORDER BY distance(lat, lng, pickup) LIMIT 10 --> assign the first

At 125,000 location updates per second, the database is overwhelmed with writes whose values are stale four seconds later. Distance queries without a spatial index scan every driver. And "assign the first" races: two riders near each other both pick the same nearest driver.

7. What breaks first?

#
  1. Location write volume on a database, for data with a four-second lifetime.
  2. Nearest-driver queries without a spatial index.
  3. Double assignment: concurrent requests choosing the same driver.
  4. Offers: the chosen driver may not respond; the system must move on quickly.
  5. Hotspots: an airport or stadium concentrates demand (and drivers) in a few cells.
  6. Live tracking at about 100,000 pushes per second.

8. Scaling the design

#

Latest location in memory, history in a stream

#

Location updates arrive at gateways and go to the location service, partitioned by city (and, in very large cities, by area). Each partition keeps driver_state and cell_index in memory and updates them on every ping: if the driver moved to a new cell, remove them from the old cell's set and add them to the new one. Nothing is written to a database on this path.

In parallel, location events are published to a stream (partitioned by driver or by city; streams preserve order per partition (Introduction to Kafka)), from which consumers build trip tracks for active trips (for fare calculation and disputes), and analytics. If a location-service node restarts, its state rebuilds within one reporting interval as drivers keep sending updates, or faster from the stream.

Geospatial indexing

#

To find "drivers near this point" quickly, bucket the map into cells and index drivers by cell. Searching then means looking in the pickup cell and its neighbours, not at every driver.

Scheme

Idea

Notes

Simple grid

Fixed-size latitude and longitude squares

Easy; cells shrink towards the poles (irrelevant within India); one size for dense and sparse areas

Geohash

Interleaves latitude and longitude bits into a string; nearby points often share a prefix

Prefix lengths give coarser or finer cells; neighbours across prefix boundaries need care

H3

A hierarchical grid of hexagons

Every hexagon has six equidistant neighbours, which makes ring searches uniform; open-source library (H3 documentation)

S2

Projects the sphere onto a cube and indexes cells with a space-filling curve

Hierarchical cells with good locality; open-source library (S2 Geometry)

Store with geo commands

Let a data store maintain the index

For example Redis GEOSEARCH returns members within a radius or box of a point (GEOSEARCH)

This Java program shows the idea with a simple square grid of about 1 km cells: drivers are bucketed by cell, and a search looks at the pickup cell and its eight neighbours, keeps available drivers and sorts them by great-circle distance. The coordinates are illustrative points in central Bengaluru.

Java
// File: NearbyDrivers.javaimport java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Locale;import java.util.Map;public class NearbyDrivers {    record Driver(String id, double lat, double lng, boolean available) {}    static final double CELL_DEGREES = 0.01;   // about 1.1 km of latitude; a simple square grid    static String cellOf(double lat, double lng) {        return (long) Math.floor(lat / CELL_DEGREES) + ":" + (long) Math.floor(lng / CELL_DEGREES);    }    // Great-circle distance in kilometres (haversine formula).    static double km(double lat1, double lng1, double lat2, double lng2) {        double r = 6371.0;        double dLat = Math.toRadians(lat2 - lat1);        double dLng = Math.toRadians(lng2 - lng1);        double a = Math.sin(dLat / 2) * Math.sin(dLat / 2)                + Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2))                * Math.sin(dLng / 2) * Math.sin(dLng / 2);        return 2 * r * Math.asin(Math.sqrt(a));    }    public static void main(String[] args) {        List<Driver> drivers = List.of(                new Driver("d1", 12.9719, 77.5940, true),                new Driver("d2", 12.9790, 77.5910, true),                new Driver("d3", 12.9650, 77.6050, false),   // on a trip                new Driver("d4", 12.9601, 77.5880, true),                new Driver("d5", 13.0350, 77.5970, true));   // far away        // The index: cell -> drivers currently in it (updated on every location ping).        Map<String, List<Driver>> index = new HashMap<>();        for (Driver d : drivers) {            index.computeIfAbsent(cellOf(d.lat(), d.lng()), c -> new ArrayList<>()).add(d);        }        double pickupLat = 12.9716;        double pickupLng = 77.5946;        long row = (long) Math.floor(pickupLat / CELL_DEGREES);        long col = (long) Math.floor(pickupLng / CELL_DEGREES);        // Look in the pickup cell and its 8 neighbours, keep available drivers, sort by distance.        List<Driver> candidates = new ArrayList<>();        for (long r = row - 1; r <= row + 1; r++) {            for (long c = col - 1; c <= col + 1; c++) {                for (Driver d : index.getOrDefault(r + ":" + c, List.of())) {                    if (d.available()) {                        candidates.add(d);                    }                }            }        }        candidates.sort((a, b) -> Double.compare(km(pickupLat, pickupLng, a.lat(), a.lng()),                                                 km(pickupLat, pickupLng, b.lat(), b.lng())));        System.out.println("cells in index: " + index.size() + ", pickup cell " + cellOf(pickupLat, pickupLng));        for (Driver d : candidates) {            System.out.printf(Locale.US, "%s  %.2f km away%n", d.id(), km(pickupLat, pickupLng, d.lat(), d.lng()));        }    }}
Code
cells in index: 4, pickup cell 1297:7759d1  0.07 km awayd2  0.91 km awayd4  1.47 km away

Driver d3 is close but on a trip, so it is filtered out; d5 is several kilometres away and is never even looked at, because its cell is not a neighbour. Real systems use hierarchical cells (H3 or S2) so they can search in expanding rings (first the immediate neighbourhood, then wider) until they have enough candidates, and use smaller cells in dense city centres.

Matching

#
Code
Ride request (idempotent) -> ride_requests: status searchingMatching service (partition for this city):  1. candidates = available drivers in rings around the pickup, of the right vehicle type (top 20)  2. estimate time to pickup for the closest few with a routing service (road ETA, not straight line)  3. pick the best candidate; RESERVE the driver (below); send OFFER with a 15 s expiry  4. accepted -> create trip; rider gets MATCHED; driver status on_trip     declined or expired -> release the reservation; next candidate (widen the search if needed)  5. after N attempts or T seconds without success -> tell the rider "no drivers available"

Two refinements are common at scale:

  • Batched matching: collect requests for a second or two and solve an assignment across all of them (minimising total pickup time), rather than greedily taking the nearest driver for each request in arrival order. Better overall outcomes in dense areas, at the cost of a small delay.
  • Dispatch to drivers finishing a trip nearby, not only idle drivers.

Never assign one driver twice

#

Two matching workers may choose the same driver for two riders at the same moment. The reservation is a conditional update on the driver's assignment record, the same check-and-act idea as article 14:

SQL
UPDATE driver_assignmentSET current_offer_id = :offer_id, version = version + 1WHERE driver_id = :driver_id AND current_offer_id IS NULL AND current_trip_id IS NULL;-- 1 row: this offer owns the driver. 0 rows: someone else has them; pick another candidate.

The in-memory index marks the driver offered so other searches skip them, but the durable conditional update is the referee: the memory state may be briefly stale on another partition replica; the database row is not.

On accept, a second conditional update turns the offer into a trip, in one transaction: the offer must still be sent and unexpired, the driver's current_offer_id must match, and inserting the trip (with request_id unique) guarantees one trip per request. A late accept after the offer expired gets 409. On decline or expiry, the reservation is cleared (conditionally, only if it still refers to this offer). Offers expire through a timer in the matching service, backed by the scheduler pattern of article 37 so that a crashed matcher cannot leave a driver reserved forever.

Trips and live tracking

#

The trip is a state machine (driver_assigned -> driver_arrived -> on_trip -> completed, or cancelled from early states), with each transition a conditional update, so duplicate or out-of-order requests from flaky apps cannot corrupt it.

During the trip, the driver's location updates also go to the rider: the location service publishes them on the trip's channel, and the rider's gateway forwards them over the open connection (article 34's routing). If the rider's connection drops, the app reconnects and fetches the latest position; nothing is lost because only the latest matters.

Payments and fares

#

At completed, the fare is computed by the pricing service from the trip's recorded track (distance and time) and the fare rules, then charged through the payment platform (article 39) as the next steps of a small saga: charge the rider, record driver earnings, send receipts (article 27's event design). A failed charge does not undo the trip; it creates an outstanding balance and retry, which is the compensation appropriate to a ride that already happened (Microsoft's Saga guidance describes compensations and pivot steps (Saga pattern)).

Surge pricing (briefly)

#

A stream processor computes demand (requests) and supply (available drivers) per cell per minute; where demand far exceeds supply, the pricing service applies a multiplier to estimates in those cells. Estimates carry an estimate_id and a validity period, so the rider is charged the price they saw.

Partitioning by city

#

Matching is local: a rider in Chennai never needs a driver in Pune. So location partitions, matching workers, offers and trips are partitioned by city (or by region within very large cities). Each city's partition is a unit of capacity and failure: a problem in one city's partition affects only that city. Very busy cities are split further by geography, with care at boundaries (a pickup near a border searches neighbouring partitions).

The evolved architecture

#
Code
Driver apps --WebSocket--> Gateways --> Location service (per city, in memory: driver_state, cell_index)                                         `--> location stream --> trip tracks, analytics, surgeRider apps  --HTTP--> API --> Ride requests (per-city DB) --> Matching service (per city)                                  |-- candidate search (location service)                                  |-- ETA (routing service)                                  |-- reservation + offers (per-city DB, conditional updates)                                  `-- offer timers (scheduler)Offer/trip events --> Gateways --> driver and rider apps (OFFER, MATCHED, DRIVER_LOCATION)Trip completed --> Pricing --> Payment platform --> Earnings, Receipts (events)

9. Failure scenarios and reliability

#

Failure

Effect

Response

Location-service node restarts

City partition briefly has no driver positions

Rebuilt within seconds from new pings (or the stream); matching waits or uses a replica

Matching worker crashes after reserving a driver

Driver stuck as "offered"

Offer expiry clears the reservation; the request is picked up again from searching

Driver accepts as the offer expires

Race between accept and expiry

Conditional updates decide: exactly one outcome wins; the driver sees "offer expired" or gets the trip

Rider double-taps "Book"

Two requests

Idempotency key: one request, one trip

Driver app loses connectivity mid-trip

No location updates

Trip continues; the app buffers locations and uploads them when back; fare uses the best available track

Airport surge

Many requests in a few cells

Batched matching, queueing riders with honest wait estimates, surge pricing to attract drivers

One city's database fails

That city cannot create trips

Per-city failover; other cities unaffected

GPS noise or spoofing

Wrong positions

Plausibility checks (impossible speeds, jumps), device integrity signals

10. Consistency

#
  • Locations: eventually consistent and approximate; a few seconds stale is fine; nothing durable depends on any single ping.
  • Driver assignment: strongly consistent per driver, enforced by conditional updates on one record; at most one active offer and one active trip.
  • Ride request to trip: at most one trip per request (unique constraint), even with retries.
  • Trip state: strongly consistent transitions; apps converge to it.
  • Fares and payments: eventually consistent via the post-trip saga.

11. Security and privacy

#
  • Location privacy: a driver's precise location is shown to a rider only after matching and only during the trip; a rider's pickup location is shared only with the assigned driver. Retain fine-grained location history only as long as needed for trips, safety and disputes, then aggregate or delete. Access by staff is audited.
  • Phone number masking: riders and drivers communicate through proxied numbers or in-app calls, not personal numbers.
  • Fraud: GPS spoofing, fake trips between colluding accounts to earn incentives, promotion abuse. Use device integrity checks, plausibility checks on tracks, and anomaly detection.
  • Authentication and authorisation: drivers authenticate per device; only the assigned driver can transition a trip; only the rider can cancel their request.
  • Safety features (sharing a live trip with contacts, emergency assistance) are product requirements that rely on the same live-tracking channel.

12. Observability

#

Signal

Why

Match time p50 and p95, and match success rate, per city

The core SLO

Offer acceptance rate and timeouts

Driver behaviour; offer design

ETA accuracy (estimated versus actual pickup)

Matching quality

Location ingestion rate and staleness (age of positions used in matching)

Freshness

Cancellations by rider and driver, by reason

Experience and fraud signals

Supply and demand per cell

Surge and operations

Live-tracking push lag

Rider experience

Reservation conflicts

Contention in hotspots

13. Trade-offs

#

Decision

Chosen

Alternative

Why

Latest location

In memory per city, rebuilt from pings

Durable database writes

125,000 writes per second of short-lived data

Spatial index

Hierarchical cells (H3 or S2), ring search

Distance query over all drivers

Constant-size searches regardless of fleet size

Matching

Offers with timeouts; batched in dense areas

Greedy nearest only

Better global outcomes; drivers can decline

Assignment safety

Conditional updates on a driver record

In-memory flags only

Correctness despite races and crashes

Partitioning

By city or region

Global

Matching is local; failures stay local

Fare after trip

Saga with outstanding balances

Block trip completion on payment

The ride has happened; collect later

14. The final interview answer

#

"At peak we have 500,000 online drivers sending locations every four seconds, about 125,000 updates a second, and around 350 ride requests a second, with matching expected in under ten seconds.

Locations go over persistent connections to a location service partitioned by city that keeps only the latest position in memory, indexed by hierarchical cells such as H3; a copy streams to Kafka for trip tracks, analytics and surge pricing. A ride request is idempotent; the city's matching service searches rings of cells around the pickup for available drivers of the right type, ranks a few by road ETA, reserves the best one with a conditional update on its assignment record, and sends an offer that expires in 15 seconds. Accepting turns the offer into a trip in one transaction, with a unique request id, so a driver can never get two trips and a request never creates two. Declines and expiries release the reservation and move to the next candidate; dense areas use batched matching.

The trip is a state machine with conditional transitions; the rider sees the driver's location pushed over their connection. At completion, pricing computes the fare from the track and a saga charges through the payment platform. Everything is partitioned by city, so failures stay local, and precise locations are shared only between matched parties and retained only as long as needed."

Exercises

#

Exercise 1

Location load

#

A city has 60,000 drivers online at peak, each sending a location every 3 seconds, with each update about 150 bytes on the wire. Compute updates per second and ingress bandwidth, and the memory needed for the latest-location index at 250 bytes per driver. Would you keep this in a database, a cache cluster or the location service's memory?

Exercise 2: The double-offer race

#

Two riders 200 metres apart request rides at the same moment. Both matching workers choose driver D. Walk through how the design ensures D receives only one offer, and what the second rider experiences.

Exercise 3: The concert crowd

#

A concert ends and 3,000 ride requests arrive within 10 minutes from four cells around the stadium, where only 400 drivers are nearby. What does the system do, and what would you show riders?

Exercise 4: Choose a cell size

#

Cells that are too small or too large both cause problems. Explain the trade-off, and how a hierarchical index such as H3 helps.

Show solutionHide solution
Code
Updates: 60,000 / 3 s = 20,000 per secondIngress: 20,000 x 150 bytes = 3 MB/s, about 24 MbpsIndex memory: 60,000 x 250 bytes = 15 MB

Fifteen megabytes is trivially small; keep it in the location service's memory for that city (with a standby replica or fast rebuild from pings). A database would add needless write load for data that is stale in seconds. A separate cache cluster is reasonable if several services must query positions directly, but every network hop adds latency to matching; a single in-memory service that answers "drivers near X" is simpler.

Exercise 2

Show solutionHide solution
  1. Both workers compute candidates; D is the best for both.
  2. Worker 1 runs the reservation update (WHERE driver_id = D AND current_offer_id IS NULL AND current_trip_id IS NULL) and changes 1 row: it owns D and sends D an offer.
  3. Worker 2 runs the same update an instant later; it changes 0 rows because current_offer_id is now set. Worker 2 marks D as unavailable in its view and moves to its next candidate, E, and reserves E.
  4. D sees exactly one offer. The second rider is matched with E, typically a few seconds later; if no alternative is nearby, the search widens.

The in-memory index also marks D as offered, which avoids most of these collisions, but the conditional update is what makes correctness independent of timing.

Exercise 3

Show solutionHide solution

Demand (3,000 requests) far exceeds local supply (400 drivers), so not everyone can be matched quickly.

  • Batched matching over a few seconds assigns the 400 drivers to minimise total pickup time and avoid drivers crossing each other through traffic.
  • Widen the search in rings to bring drivers from further away, with honest ETAs.
  • Surge pricing in those cells (if the business uses it) attracts more drivers and reduces marginal demand.
  • Queue riders fairly: show "high demand, you are in line; estimated wait 12 minutes", let them keep or cancel the request, and avoid repeatedly failing requests that tempt users to retry (which adds load).
  • Designated pickup zones near the venue reduce congestion and make matching faster.
  • Protect the system: rate-limit repeated requests per rider; the city partition may need temporary extra matching capacity.

Exercise 4

Show solutionHide solution
  • Too small: a search must examine many cells to find enough drivers (more lookups), drivers change cells constantly (more index updates), and in sparse areas most cells are empty.
  • Too large: each cell holds many drivers, so a search scans many far-away candidates and must compute many distances; "nearby" becomes imprecise in dense centres.

A hierarchical index such as H3 offers several resolutions of nested hexagons. The system can index drivers at a fine resolution, search rings of fine cells first in dense areas, and step up to coarser parent cells (or wider rings) in sparse areas until it has enough candidates. Hexagons also have uniform neighbours (six, all at the same distance), which makes ring searches more even than with squares, whose diagonal neighbours are further away.

Where to go next

#

Sources & further reading

  1. h3geo.org
  2. s2geometry.io
  3. redis.io
  4. rfc-editor.org
  5. learn.microsoft.com
  6. kafka.apache.org
  • Guide · Technology

    Start Here: Your Roadmap from Zero to Job-Ready DSA

  • Guide · Technology

    Heaps and Priority Queues

  • Guide · Career

    A LinkedIn Profile That Gets Recruiter Messages