惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
T
Troy Hunt's Blog
Hacker News - Newest:
Hacker News - Newest: "LLM"
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
H
Hacker News: Front Page
C
CERT Recently Published Vulnerability Notes
E
Exploit-DB.com RSS Feed
T
Tenable Blog
T
Threat Research - Cisco Blogs
W
WeLiveSecurity
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
L
LINUX DO - 热门话题
Google Online Security Blog
Google Online Security Blog
Help Net Security
Help Net Security
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Attack and Defense Labs
Attack and Defense Labs
S
Security Archives - TechRepublic
T
The Exploit Database - CXSecurity.com
Simon Willison's Weblog
Simon Willison's Weblog
Know Your Adversary
Know Your Adversary
Security Latest
Security Latest
Recent Commits to openclaw:main
Recent Commits to openclaw:main
S
Schneier on Security
N
News | PayPal Newsroom
Application and Cybersecurity Blog
Application and Cybersecurity Blog
P
Proofpoint News Feed
Forbes - Security
Forbes - Security
SecWiki News
SecWiki News
Cyberwarzone
Cyberwarzone
PCI Perspectives
PCI Perspectives
Hacker News: Ask HN
Hacker News: Ask HN
博客园 - Franky
腾讯CDC
大猫的无限游戏
大猫的无限游戏
J
Java Code Geeks
Schneier on Security
Schneier on Security
量子位
C
Cisco Blogs
The Cloudflare Blog
博客园_首页
小众软件
小众软件
V
V2EX
博客园 - 三生石上(FineUI控件)
C
Cybersecurity and Infrastructure Security Agency CISA
Hugging Face - Blog
Hugging Face - Blog
罗磊的独立博客
博客园 - 叶小钗
Latest news
Latest news
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
H
Heimdal Security Blog

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python) The Hidden Cost of AI Systems Nobody Talks About. undefined vs undeclared, and how typeof behaves Switching from file-based jobs to NATS/Kafka in Rust without changing code io_uring Adventures: Rust Servers That Love Syscalls Why Agentic AI is Killing the Traditional Database The POUR principles of web accessibility for developers and designers Quantum Neural Network 3D — A Deep Dive into Interactive WebGL Visualization How To Install Caveman In Codex On macOS And Windows Automation Pipeline Reliability: Why Your Workflow Breaks When Nobody Is Watching I Built an 'Open World' AI Coding Agent — It Works From ANY Folder From Freelancing to Product: A Tech Service Company's SaaS Transformation China's AI Giants: Adding Tencent Hunyuan & ByteDance Doubao to AI University (74 Providers) On the Vibe Coders and Their Lies clerk: Auto-Summarize Your Claude Code Sessions AI Weekly — 2026/04/10–04/17 | The Model Lockdown Is Here, but the Toolchain Is the Real Battleground AI 週報 — 2026/04/10–2026/04/17 模型封鎖潮來了,但工具鏈才是真戰場 Maybe this is how Open-Source apps are born... 🚀 Fine-Tune LLMs with LoRA and QLoRA: 2026 Guide tRPC v11 + Next.js App Router: End-to-End Type Safety Without the Boilerplate ShadCN UI in 2026: Why I Stopped Installing Component Libraries and Started Owning My Components SaaS Billing in React Server Components: Stripe + Supabase Without a Single `useEffect` Join our DEV Weekend Challenge — $1,000 in Prizes Across TEN winners! Submissions Due April 20 at 6:59 AM UTC. Implementing FSRS Spaced Repetition in Flutter + Supabase — Adding Memory Science to an AI Learning App "I Texted My Localhost From the Train — Claude Code Fixed the Bug Before I Got Home" I Built a Sales Prep AI and It Went Deeper Than Expected Design to Code #2: One JSON, Eleven Outputs Solving the 100M-Row Problem: A Summary Table Pattern for High-Volume Push Notification Logs Flutter Web With Wasm: What Actually Changes For Developers I Built 50 Royalty-Free Soundtracks for My Side Project in a Weekend Using AI Music Generation The Vibe Coding Security Checklist: 7 Things to Check Before You Ship Stop Letting Googlebot Guess Fix Your React App's SEO Right Desconstruindo o Streaming do LinkedIn: Como Criar um Engine de Extração de Vídeo de Alta Performance com HLS e FFmpeg (EDA Part-1) EDA (Exploratory Data Analysis) Explained With Real Life — Why Looking at Your Data Is the Most Important Step in Machine Learning Brand Relationship Management at Scale: Our 4-Touch Outreach System for 200+ Brands Why String.fromEnvironment() Might Return an Empty String in Dart JGuardrails 1.0.0 — Hardening Java LLM Apps Against Jailbreaks, Toxicity, and Prompt Injection Plan and Schedule a Full Week of Threads Content From One Claude Conversation Coding Cat Oran Ep3, Five Tables Changed Everything Updated: BFF Pattern I'm done watching freelancers get buried by 200 proposals. So I'm building the alternative. This is my first post BFS Algorithm in Java Step by Step Tutorial with Examples Tracking LLM Pricing Monthly: An Open Dataset for 22 AI Models How We Measure Content ROI on a Comparison Site: Revenue Attribution Without Perfect Data Introducing Nova AI Ops: The AI-Native Operating System for SRE Teams I built a free desktop video downloader for Windows — Grabbit How Talkie OCR Helps Vision-Impaired & Dyslexic Users Read the World Around Them VRCFaceTracking安装和iPhone面捕配置教程,有bug Even CrowdStrike Can't See Your Agents The Automation Gold Rush: What n8n Workflows and Claude Are Opening Up for Developers Right Now
[System Design] Ride-Hailing Dispatch Algorithm: How Uber DISCO & Grab DispatchGym Match Drivers
Tuấn Anh · 2026-06-15 · via DEV Community

Every time you tap "Book Ride," a system makes dozens of decisions in under two seconds: Which driver? What route? What's the real ETA? This article breaks down exactly how the dispatch algorithm works — from the greedy approach that fails at scale, to the bipartite graphs, batched matching, and surge pricing mechanics that power Uber, Lyft, Grab, and Gojek today.


Why a Greedy Dispatch Algorithm Fails (Closest Driver Problem)

The first instinct when designing a matching system is to pair every customer with their nearest driver. However, this Greedy approach causes massive losses at a system-wide scale:

Example: 3 riders (R1, R2, R3) and 3 drivers (D1, D2, D3)

Greedy Matching (closest driver):
  R1 ← D1 (ETA 2 mins)  ✓
  R2 ← D3 (ETA 8 mins)  ← D2 was "taken" by R1, even though D2 is closer to R2
  R3 ← D2 (ETA 10 mins) ← Terrible outcome

  Total ETA: 2 + 8 + 10 = 20 minutes

Optimal Matching (global optimal):
  R1 ← D2 (ETA 3 mins)
  R2 ← D1 (ETA 3 mins)
  R3 ← D3 (ETA 4 mins)

  Total ETA: 3 + 3 + 4 = 10 minutes  ← 50% better!

Uber refers to this problem as Global Optimization — finding an assignment strategy that minimizes the total ETA of the entire system, rather than optimizing just for individual pairs.


Bipartite Graph Matching: The Mathematical Foundation (Lyft)

Before diving into the systems, it helps to understand the mathematical model that all ride-hailing matching engines share at their core.

Lyft formalizes dispatch as a bipartite graph matching problem:

Bipartite Graph:
  Set A (Riders):  { R1, R2, R3, R4 }
  Set B (Drivers): { D1, D2, D3, D4, D5 }

  Edges: every possible Rider ↔ Driver pair
  Edge Weight: cost of that match (e.g., ETA, driver rating, distance)

  Goal: Find a set of edges (a "matching") where:
    - No rider is matched to more than one driver
    - No driver is matched to more than one rider
    - The total cost of all selected edges is minimized

This is known as the Minimum Weight Bipartite Matching problem. The classical algorithm for solving it is the Hungarian Algorithm (also called the Kuhn-Munkres algorithm), which runs in O(n³) time.

Why Batching Matters for Bipartite Matching

The key insight is that you can only find a globally optimal bipartite matching if you have multiple riders and drivers available simultaneously. If you match greedily (one-by-one as requests arrive), you lose the ability to find the global optimum.

This is why all major ride-hailing platforms introduce a batching window:

Batching Strategy:
  1. Collect all ride requests in a 2-5 second window
  2. Build a complete Rider × Driver cost matrix
  3. Run the Hungarian Algorithm on the full batch
  4. Dispatch all assignments simultaneously

Result: System-wide optimal — not just locally optimal for each individual request

Approach Latency Global Optimality Scalability
Pure Greedy Near-zero Poor High
Batched Matching 2-5 seconds Excellent Medium
RL-Adaptive Batching Dynamic Excellent High

Uber DISCO: The Core Dispatch Algorithm Architecture

DISCO (Dispatch Optimization) is Uber's matching system, responsible for pairing millions of ride requests with drivers every day.

Overall Architecture

┌─────────────────┐     ┌─────────────────┐
│  Rider App      │     │  Driver App      │
│  "Book Ride"    │     │  GPS, Status     │
└────────┬────────┘     └────────┬────────┘
         │                       │
         ▼                       ▼
┌─────────────────┐     ┌─────────────────┐
│  Demand Service │     │  Supply Service  │
│  (Ride Requests)│     │  (Driver Pool)   │
└────────┬────────┘     └────────┬────────┘
         │                       │
         └──────────┬────────────┘
                    ▼
         ┌─────────────────────┐
         │    DISCO Engine      │
         │                     │
         │  1. Candidate Filter │ ← S2/H3 Geospatial Query
         │  2. ETA Calculator   │ ← Routing Service + DeepETA
         │  3. Batch Optimizer  │ ← Hungarian Algorithm
         │  4. Dispatch         │ ← RAMEN Push
         └─────────────────────┘

Step 1: Candidate Filtering

When a ride request arrives, DISCO doesn't check every driver. It uses the rider's S2 Cell ID (or H3) to rapidly narrow down the list:

Input:  Rider location → S2 Cell Level 12
Action: Find all neighboring S2 cells (covering circle radius ~3km)
Query:  Redis/Memory → Retrieve list of drivers in those cells

Filters:
  ✓ Status = AVAILABLE (not currently carrying a passenger)
  ✓ Vehicle type matches (Car, Bike, SUV, etc.)
  ✓ Capacity is sufficient (if a group ride)
  ✓ Not blocked by the rider

Output: ~10-30 candidate drivers

S2 vs H3: Choosing the Right Spatial Index

Uber originally used S2 geometry (quad-tree squares) for spatial sharding but later developed H3 (hexagons). The difference matters for how the engine finds candidate drivers:

S2 Geometry (Google) H3 (Uber)
Cell shape Square Hexagon
Neighbor equidistance No (diagonal cells are further) Yes (all 6 neighbors equidistant)
Best for Precise geofencing, hierarchical sharding Proximity search, surge heatmaps
Used by Lyft, early Uber DISCO Modern Uber, Grab

Step 2: ETA Calculation with DeepETA

Straight-line (crow-fly) distance is meaningless in the real world — 500m straight-line might be a 3km drive (due to bridges, intersections, or one-way streets).

Candidate drivers: [D1, D2, D3, D4, D5]
Rider position: R1

Routing Service calculates actual ETA based on:
  - Digitized road network graph
  - Real-time traffic data
  - One-way streets, overpasses, tunnels
  - Rush hours / historical traffic patterns

Results:
  D1: 800m crow-fly → 2.3km road → ETA 4 mins (heavy traffic)
  D2: 1.2km crow-fly → 1.5km road → ETA 3 mins (clear roads)  ← Better!
  D3: 600m crow-fly → 3.8km road → ETA 7 mins (must U-turn)

Uber developed DeepETA — a hybrid deep learning approach that sits on top of the traditional routing engine:

DeepETA Architecture:
  1. Traditional Router → "Naive ETA" (e.g., 4 mins based on road graph)
  2. Deep Neural Network → "Residual Prediction" (e.g., +1.5 min due to
     traffic signal, weather, specific intersection complexity)
  3. Final ETA = Naive ETA + Residual

Input features to the DNN:
  - GPS coordinates (cleaned by Kalman Filter)
  - Time of day, day of week
  - Historical traffic at this location
  - Driver/vehicle attributes
  - Trip type (airport, downtown, etc.)

Kalman Filter role: Raw GPS signals are noisy in urban environments (tall buildings, tunnels). A Kalman Filter smooths the GPS stream before it feeds into DeepETA, ensuring the model learns from accurate positional data rather than jittery raw coordinates.

Step 3: Batched Matching

This is the most crucial and complex step. Instead of processing each request individually, DISCO batches requests within a short time window (a few seconds) and solves the optimal assignment problem for the entire batch.

Batching Window: 2 seconds

Within 2 seconds, the system receives:
  Ride Requests: [R1, R2, R3, R4, R5]
  Available Drivers: [D1, D2, D3, D4, D5, D6, D7]

Build Cost Matrix (ETA between every rider-driver pair):

         D1   D2   D3   D4   D5   D6   D7
  R1  [  3    5    8    2    7    9    4  ]
  R2  [  6    2    4    7    3    5    8  ]
  R3  [  4    7    3    5    6    2    9  ]
  R4  [  8    4    6    3    5    7    2  ]
  R5  [  5    6    2    8    4    3    7  ]

The Problem: Find a 1-to-1 assignment such that the total cost is minimized.
→ Hungarian Algorithm (or Auction Algorithm)

The Hungarian Algorithm

This is a classic algorithm used to solve the Assignment Problem with a time complexity of O(n³):

Input: N×M Cost Matrix (N riders, M drivers, M ≥ N)
Output: Optimal 1-to-1 assignment

Optimal Results:
  R1 ← D4 (ETA 2 mins)
  R2 ← D2 (ETA 2 mins)
  R3 ← D6 (ETA 2 mins)
  R4 ← D7 (ETA 2 mins)
  R5 ← D3 (ETA 2 mins)

  Total ETA: 10 minutes (compared to a Greedy approach which might yield 20+ minutes)


Ringpop — Distributed Coordination

DISCO runs on multiple servers. How do we ensure two different DISCO servers don't attempt to assign the exact same driver to two different riders?

Uber developed Ringpop — a consistent hashing library based on the SWIM (gossip) protocol:

Ringpop Hash Ring:

Server A ────── Server B ────── Server C ────── Server A
   │                │                │
   ▼                ▼                ▼
  Riders &       Riders &         Riders &
  Drivers        Drivers          Drivers
  in Zone 1      in Zone 2        in Zone 3

Each S2 Cell is hashed to a specific DISCO server.
→ All requests and drivers within the same area are processed by the SAME DISCO server.
→ No conflict during assignment.

SWIM Protocol: Every DISCO node periodically "pings" other nodes to check if they are alive. If a node goes down, the ring auto-rebalances — the S2 cells of the dead node are transferred to neighboring nodes in the ring.


Fault Tolerance: State Digest

The problem: If an Uber data center goes down abruptly, will the states of all in-flight trips be lost?

Uber's clever solution: Encrypted State Digest — DISCO periodically pushes the trip state (encrypted) down to be stored directly on the driver's phone.

Normal Flow:
  DISCO Server ◄──── state ────► Driver Phone
  (Source of truth)               (Backup copy)

When a data center crashes:
  1. A new DISCO Server boots up
  2. Driver phones reconnect
  3. DISCO requests driver phones to send back the state digest
  4. DISCO decrypts and restores the state of all in-flight trips
  5. The system continues operating without dropping a single ride


From Heuristics to Machine Learning: Gojek Jaeger

Gojek's evolution from a simple dispatch heuristic to a production ML system is a masterclass in how marketplace complexity forces you to rethink single-objective optimization.

The Problem with a Single ML Model

Gojek's initial approach used a single machine learning model to rank and select drivers. It worked — until it didn't. The model optimized aggressively for its primary metric (say, acceptance rate) and created feedback loops:

Feedback Loop Problem:
  1. Model learns: "Drivers in Zone A accept 90% of the time"
  2. Model always sends orders to Zone A drivers
  3. Zone A drivers get overwhelmed, acceptance rate drops
  4. Zone B drivers are idle, marketplace liquidity drops
  5. Riders in Zone B wait longer → lower satisfaction

A single-objective model cannot balance competing goals without explicit guardrails.

Jaeger: Multi-Objective Allocation

Gojek built Jaeger — a multi-objective allocation framework that simultaneously optimizes for:

Jaeger Optimization Objectives:
  ↓ Minimize pickup ETA          (rider experience)
  ↑ Maximize driver utilization  (driver earnings)
  ↑ Maximize acceptance rate     (marketplace flow)
  ↑ Ensure fairness              (prevent driver starvation)

Architecture:
  [Real-time Features]  ←── GPS, traffic, demand heatmaps
        │
        ▼
  [ML Models]           ←── Acceptance probability, ETA model
        │
        ▼
  [Manual Configs]      ←── Business rules, fairness floors
        │
        ▼
  [Jaeger Aggregator]   ←── Weights & combines all signals
        │
        ▼
  [Driver Score]        ←── Final ranking for dispatch

The Manual Configs layer is intentional: it gives business teams control to override ML decisions in edge cases (market launches, weather events, regulatory requirements) without retraining the entire model.


The Future: Reinforcement Learning & MDP in Dispatching (Grab DispatchGym)

The Hungarian algorithm solves the immediate assignment optimally. But it has a fundamental limitation: it only optimizes for the current batch. It cannot answer questions like:

  • Should I assign a driver now, or wait 30 seconds for a better match?
  • If I send this driver 5km across town, will that leave a coverage gap for the next surge?

This is where Reinforcement Learning (RL) and the Markov Decision Process (MDP) formulation come in.

Dispatch as a Markov Decision Process

An MDP models dispatch as a sequence of decisions where each action affects future states:

MDP Formulation for Dispatch:

State (S):
  - Current positions of all idle drivers
  - Pending ride requests and their locations
  - Time of day, predicted demand heatmap
  - Traffic conditions across all zones

Action (A):
  - Assign Driver D to Rider R
  - Hold Driver D idle (wait for a better request)
  - Reposition Driver D to Zone X (proactive repositioning)

Transition (T):
  - Probability that action A in state S leads to state S'
  - e.g., P(driver ends up in Zone B | assigned to trip starting in Zone A)

Reward (R):
  - Positive: completed trip, short pickup ETA, high acceptance
  - Negative: long idle time, deadhead mileage, rider cancellation

The key difference from greedy matching: the RL agent learns to make decisions that maximize cumulative long-term reward — not just the immediate reward for a single trip.

Grab DispatchGym

Grab built DispatchGym to make RL research accessible for dispatching problems. Its design solves a core challenge: training RL agents in production is dangerous (bad policies lose money and drivers). DispatchGym provides a safe, simulated environment:

DispatchGym Architecture:

┌───────────────────────────────────┐
│         Simulation Layer           │
│  - Replays historical trip data    │
│  - Injects synthetic demand spikes │
│  - Models driver behavior          │
└────────────────┬──────────────────┘
                 │  State observation
                 ▼
┌───────────────────────────────────┐
│         RL Agent (Policy)          │
│  - Gymnasium API compatible        │
│  - Trainable with any RL algo      │
│    (PPO, SAC, DQN...)              │
└────────────────┬──────────────────┘
                 │  Action (dispatch decision)
                 ▼
┌───────────────────────────────────┐
│        Reward Computation          │
│  - Total completed trips           │
│  - Average pickup ETA              │
│  - Driver earnings equity          │
│  - Acceptance rate                 │
└───────────────────────────────────┘

Deployment:
  Reward stabilizes → A/B test in production → Gradual rollout

Multi-Agent RL: When One Agent Isn't Enough

A single RL agent controlling an entire city's fleet hits the curse of dimensionality — the state-action space is too large. The solution is Multi-Agent Reinforcement Learning (MARL):

MARL for Dispatch:
  - Each geographic zone (or each driver) is an independent agent
  - Agents observe their local state (nearby riders, driver density)
  - Agents take local actions (match, hold, reposition)
  - Coordination mechanism ensures global objectives are met

Paradigm: Centralized Training, Decentralized Execution (CTDE)
  - During training: agents share global information to learn cooperation
  - During execution: each agent acts on local observations only
  - Result: Scales to city-wide fleets without centralized bottleneck

Academic research on MARL-based dispatch suggests wait time reductions of 25–40% compared to greedy baselines, with significant improvements in driver idle mileage — though real-world results vary by city density and fleet size.


Grab's Fulfilment Platform Architecture

Grab doesn't just run ride-hailing — it runs food, groceries, express delivery, and financial services on the same driver network. Early on, each vertical had its own dispatch engine, causing massive inefficiency.

Grab solved this with the Fulfilment Platform — a unified three-layer architecture:

┌────────────────────────────────────────┐
│         Business Verticals             │
│  GrabCar | GrabFood | GrabMart | ...   │
└───────────────┬────────────────────────┘
                │ Demand signals
                ▼
┌────────────────────────────────────────┐
│         Fulfilment Platform            │
│  - Unified dispatch engine             │
│  - Supply shaping & driver incentives  │
│  - Global optimization across verticals│
└───────────────┬────────────────────────┘
                │ Infrastructure
                ▼
┌────────────────────────────────────────┐
│         Technology Infrastructure      │
│  - DynamoDB (OLTP: live orders)        │
│  - MySQL partitioned (OLAP: analytics) │
│  - 1,000+ microservices on AWS/GCP     │
└────────────────────────────────────────┘

The critical innovation: a driver finishing a GrabFood delivery can be immediately available for a GrabCar ride — the same Fulfilment Platform sees the full picture and can optimize across verticals. This eliminated "dead time" between trips and significantly improved driver earnings.


Key Metrics for the Matching Engine

Metric Meaning Target
P50/P99 Matching Latency Time from request received to dispatch < 2 seconds (P99)
Acceptance Rate % of drivers accepting when offered > 85%
ETA Accuracy Error margin between predicted and actual ETA < 20%
Match Rate % of requests successfully matched > 95%
Total Wait Time Total time a rider waits (rider + driver travel time) Minimize
Driver Idle Mileage Distance driven without a passenger Minimize
Marketplace Liquidity Balance of supply/demand across zones Maintain

FAQ: Dispatch Algorithms

What is a dispatch algorithm?
A dispatch algorithm is a system used by ride-hailing platforms like Uber and Grab to optimally match riders with available drivers. It goes beyond finding the closest driver by using batched matching and global optimization to minimize the total wait time (ETA) for all users.

How does Uber match riders and drivers?
Uber uses a system called DISCO that batches ride requests every 2-5 seconds and applies the Hungarian algorithm for global optimization across the entire batch. This ensures system-wide efficiency, not just locally optimal matches for each individual request.

Why is reinforcement learning used in ride-hailing?
RL models treat dispatching as a Markov Decision Process (MDP), allowing the system to optimize for long-term marketplace liquidity and driver earnings, rather than just immediate wait times. Platforms like Grab use RL via DispatchGym to learn when to hold a driver for a better future match, rather than always assigning immediately.

What is the difference between S2 and H3 in dispatch systems?
S2 (Google) uses square cells and is excellent for precise geofencing and hierarchical sharding. H3 (Uber) uses hexagonal cells, which offer uniform adjacency — all 6 neighbors are equidistant — making proximity searches and surge pricing heatmaps more accurate for real-time matching.

Next, we will look into Surge Pricing — the dynamic pricing system based on real-time supply and demand ratios. Continue reading Part 5 — Surge Pricing: Dynamic Pricing Based on Real-time Supply and Demand.


This post was originally published on my blog at Ride-Hailing Dispatch Algorithm: How Uber DISCO & Grab DispatchGym Match Drivers.

Hi, I'm Lê Tuấn Anh (vesviet) 👋
I am a Senior Go Backend Architect & Distributed Systems Engineer with 17+ years of experience building high-traffic platforms (25M+ requests/month).
If you enjoyed this deep-dive, let's connect on LinkedIn or explore my consulting services at tanhdev.com/hire.