High-performance, scalable routing and matrix API. Handles 2k-5k+ concurrent users with intelligent load-balancing across 4 backends per profile.
This stack runs four profile groups with load-balanced OSRM backends:
car(4 backends via least-conn load balancing)walk(4 backends via least-conn load balancing)
Single gateway on port 8080 with intelligent request distribution.
| Concurrent Users | CPU/Backend | Memory/Backend | Config |
|---|---|---|---|
| < 100 | 0.5-1 | 1-2G | Minimal |
| 100-500 | 1 | 2G | Recommended |
| 500-2k | 1.5-2 | 3-4G | Current |
| 2k-5k | 2-3 | 4-6G | Default |
| 5k+ | 4+ | 6-8G | Advanced |
See PERFORMANCE_TUNING.md for detailed scaling and load-testing guide.
chmod +x ./scripts/load-test.sh
./scripts/load-test.sh 500 # Test 500 concurrent
./scripts/load-test.sh 2000 60 # Test 2000 concurrent for 60s# 1. Place your OSM PBF file
mkdir -p data/source
cp ~/your-region.osm.pbf data/source/map.osm.pbf
# 2. Start the stack
cp .env.example .env
docker compose up -d
# 3. Test (wait for osrm-prepare to finish ~5-10 min)
curl http://localhost:8080/car/route/v1/driving/7.421,43.729;7.424,43.733This stack runs four profile groups with load-balanced OSRM backends:
car(2 backends, direct primary port5000)walk(2 backends, direct primary port5002)
It also exposes a single gateway on port 8080:
/car/...-> car backend/walk/...-> walk backend
All settings in .env are optional. Defaults work fine for most setups.
# Routing algorithm (change requires dataset rebuild)
OSRM_ALGORITHM=ch # ch or mld
# Request size limits (protect from expensive queries)
OSRM_MAX_TABLE_SIZE=100 # Matrix max coordinates
OSRM_MAX_VIAROUTE_SIZE=500 # Route waypoints limit
OSRM_MAX_MATCHING_SIZE=200 # Trace matching limit
OSRM_MAX_NEAREST_SIZE=100 # Nearest point limit
# Threading (empty = auto-detect from CPU cores)
OSRM_THREADS=
# Rebuilding (set to true after updating map file)
FORCE_REBUILD=falseFor 2k+ concurrent load:
# Per-backend resource limits (supports: 512M, 1G, 2G, 4G, 6G, 8G)
OSRM_MEMORY_LIMIT=4G
OSRM_MEMORY_RESERVE=2G
OSRM_CPU_LIMIT=2
OSRM_CPU_RESERVE=1See PERFORMANCE_TUNING.md for detailed scaling.
# Replace the map file
cp /path/to/new-region.osm.pbf data/source/map.osm.pbf
# Rebuild datasets
FORCE_REBUILD=true docker compose up -d
# Wait for prepare to finish
docker compose logs -f osrm-prepareCustomize speeds and routing behavior with Lua profile files:
profiles/car.luaprofiles/walk.lua
Export defaults from OSRM:
docker compose run --rm --entrypoint sh osrm-prepare -lc 'cp /opt/car.lua /profiles/car.lua && cp /opt/foot.lua /profiles/walk.lua'Edit the Lua files, then rebuild:
FORCE_REBUILD=true docker compose up -dDetails: profiles/README.md
Base URL: http://localhost:8080
# Car
auto='http://localhost:8080/car/route/v1/driving/7.421,43.729;7.424,43.733?overview=false'
curl "$auto"
# Walk
walk='http://localhost:8080/walk/route/v1/walking/7.421,43.729;7.424,43.733?overview=false'
curl "$walk"# Car matrix (duration + distance)
matrix='http://localhost:8080/car/table/v1/driving/7.421,43.729;7.424,43.733;7.418,43.732?annotations=duration,distance'
curl "$matrix"
# Walk matrix
matrix='http://localhost:8080/walk/table/v1/walking/7.421,43.729;7.424,43.733;7.418,43.732?annotations=duration,distance'
curl "$matrix"- Car primary:
http://localhost:5000 - Walk primary:
http://localhost:5002
There is no fixed yes/no answer without a benchmark on your machine and dataset. This setup is tuned for higher concurrency using:
- 2 OSRM backends per profile behind nginx load balancing
- tuned nginx worker + connection settings
- OSRM thread configuration and request-size guardrails
Quick benchmark example for 2k concurrent route users:
docker run --rm --network host grafana/k6 run - <<'EOF'
import http from 'k6/http';
import { check, sleep } from 'k6';
export const options = {
vus: 2000,
duration: '60s',
thresholds: {
http_req_failed: ['rate<0.01'],
http_req_duration: ['p(95)<1200'],
},
};
export default function () {
const url = 'http://localhost:8080/car/route/v1/driving/7.421,43.729;7.424,43.733?overview=false';
const res = http.get(url, { timeout: '30s' });
check(res, { 'status is 200': (r) => r.status === 200 });
sleep(1);
}
EOFIf p95 latency or error rate is too high, scale further by adding more backend replicas and increasing CPU/RAM.
Rebuild after updating map file:
cp /path/to/new-region.osm.pbf data/source/map.osm.pbf
FORCE_REBUILD=true docker compose up -dStop everything:
docker compose down