gendesign/docs/osrm-routing.md
Light1YT 26f9605c06
All checks were successful
CI / changes (pull_request) Successful in 7s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
feat(devops): self-hosted OSRM routing engine for site-finder (#39)
Stand up an internal-only OSRM container so /analyze can later use real
road/walking distances to POI instead of straight-line ST_Distance. Infra
only — the /analyze integration is a separate follow-up (A2/A3).

- docker-compose.prod.yml: osrm service (osrm/osrm-backend, --algorithm mld,
  mem_limit 1.5g, default network, no public port — backend reaches it at
  http://osrm:5000). TCP /dev/tcp healthcheck (image has no curl). backend does
  NOT depend_on osrm, so a crash-loop before the graph is built won't block deploy.
- scripts/build_osrm.sh: idempotent MLD build/refresh (extract→partition→customize,
  not contract). Defaults to Свердл-clip из Ural-FO via osmium (lighter RAM);
  CLIP=0 zero-clip and EKB_TIGHT=1 / WALK=1 options documented. Monthly-refresh note.
- docs/osrm-routing.md: region/pbf decision, RAM table, VPS run-commands, verify curl.
- .gitignore data/osrm/* (don't commit ~1.5GB build output); .gitkeep holds the dir.

Refs #39
2026-06-27 00:13:41 +05:00

126 lines
6.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# OSRM routing engine (self-hosted) — #39
Self-hosted [OSRM](https://project-osrm.org/) для site-finder `/analyze`: реальные
дорожные / пешие расстояния до POI вместо straight-line `ST_Distance(geography)`.
> **Scope этого PR — INFRA ONLY.** Здесь стоит контейнер + build-скрипт + healthcheck.
> Интеграция в `/analyze` (замена `ST_Distance` на OSRM `route`/`table`) — отдельный
> follow-up (A2 изохроны, A3 per-category routing-decay). Backend пока к osrm НЕ ходит.
## Архитектура
```
backend ──http://osrm:5000──▶ osrm (osrm-routed --algorithm mld)
│ volume ./data/osrm:/data
└─ /data/sverdlovsk.osrm* (MLD-граф, ~ХХХ MB)
```
- Compose service `osrm` в `docker-compose.prod.yml`, сеть `default` (project `gendesign`).
- **Наружу НЕ публикуется** — нет `ports:`. Достижим только из backend по `http://osrm:5000`.
Caddy его не проксирует (routing — internal API, не должен быть публичным).
- `mem_limit: 1.5g`, `restart: unless-stopped`.
- Граф (`/data/*.osrm*`) НЕ в git (`.gitignore``data/osrm/*`). Строится offline на VPS.
## Build / refresh графа
Скрипт: [`scripts/build_osrm.sh`](../scripts/build_osrm.sh). Запускается **вручную**
на VPS (НЕ часть `deploy.yml` — download+build тяжёлые).
```bash
cd /opt/gendesign
bash scripts/build_osrm.sh # car-профиль, Свердл-clip (default)
```
### Источник pbf и решение по региону
Geofabrik **не** публикует Свердловскую область отдельно — есть только
[Уральский ФО](https://download.geofabrik.de/russia/ural-fed-district-latest.osm.pbf)
(≈600 MB). Скрипт по умолчанию (`CLIP=1`) скачивает Ural-FO и **обрезает по bbox
Свердл. обл.** через `osmium extract` → легче граф, меньше RAM в runtime.
| Режим | Команда | pbf | Граф в RAM (warm) | Когда |
|---|---|---|---|---|
| **Свердл-clip** (default) | `bash scripts/build_osrm.sh` | clip из Ural-FO | ~0.81.2 GB | рекоменд., extensibility на обл |
| ЕКБ-tight | `EKB_TIGHT=1 bash scripts/build_osrm.sh` | узкий bbox ЕКБ | ~0.40.6 GB | если RAM на VPS критична |
| Ural-FO zero-clip | `CLIP=0 bash scripts/build_osrm.sh` | весь Ural-FO | ~1.5 GB+ | если нужен запас на соседние регионы |
bbox Свердл (с запасом): `lon 57.2..66.2, lat 56.0..62.0`. ЕКБ-tight: `lon 59.0..62.5, lat 56.2..58.2`.
### Pipeline (MLD, не CH)
`--algorithm mld` в compose требует pipeline **extract → partition → customize**
(скрипт делает это через тот же `osrm/osrm-backend` образ). `osrm-contract`
это CH-алгоритм, он несовместим с `--algorithm mld`, поэтому НЕ используется.
### Walking-профиль (Phase-2, опционально)
Issue хочет оба профиля (car + foot) eventually. Этот PR **car-first**. Пеший граф:
```bash
WALK=1 bash scripts/build_osrm.sh # дополнительно соберёт sverdlovsk-foot.osrm*
```
Для пешего routing нужен второй compose-service (он не добавлен в этом PR, чтобы не
плодить idle-контейнер пока /analyze не интегрирован). Блок для будущего:
```yaml
osrm-walk:
image: osrm/osrm-backend:latest
restart: unless-stopped
command: osrm-routed --algorithm mld --max-table-size 8000 /data/${OSRM_REGION:-sverdlovsk}-foot.osrm
volumes: [./data/osrm:/data]
mem_limit: 1g
healthcheck:
test: ["CMD-SHELL", "timeout 3 bash -c '</dev/tcp/127.0.0.1/5000' || exit 1"]
interval: 30s
timeout: 5s
retries: 5
start_period: 40s
networks: [default]
```
Backend ходил бы к нему по `http://osrm-walk:5000`.
### Monthly refresh
osm.pbf на Geofabrik обновляется ежедневно. Граф освежать ~ежемесячно:
```cron
0 4 1 * * cd /opt/gendesign && bash scripts/build_osrm.sh >> /var/log/osrm-build.log 2>&1 \
&& docker compose -p gendesign -f docker-compose.prod.yml up -d --force-recreate --no-deps osrm
```
Скрипт idempotent: `wget -N` качает только если на сервере новее, граф перестраивается overwrite.
## Развёртывание (что выполняет оркестратор на VPS)
```bash
cd /opt/gendesign
git fetch origin main && git reset --hard origin/main # подтянуть compose + скрипт
# 1. Build графа (~3050 мин, ~600MB download + ~3GB peak RAM на extract)
bash scripts/build_osrm.sh
# 2. Поднять контейнер
docker compose -p gendesign -f docker-compose.prod.yml up -d osrm
# 3. Verify (curl ВНУТРИ образа нет — используем sidecar curl в той же сети)
docker run --rm --network gendesign_default curlimages/curl:8 -fsS \
'http://osrm:5000/route/v1/driving/60.6,56.84;60.65,56.86'
# ожидаем JSON: {"code":"Ok","routes":[{...}], ...}
```
## Healthcheck
Compose-healthcheck — TCP-probe порта 5000 через `bash /dev/tcp` (образ
`osrm/osrm-backend` НЕ содержит curl/wget, HTTP-probe падал бы на missing binary).
Полный route-probe — verify-команда выше (sidecar curl).
## Риски / open
- **RAM на Beget VPS**: +~1 GB warm для Свердл-clip. Перед `up -d osrm` проверить
свободную RAM (`free -h`). Если жмёт — `EKB_TIGHT=1` (~0.40.6 GB) или upgrade plan.
- **Build на VPS медленный** (50+ мин). Альтернатива: собрать локально и `scp`
`data/osrm/*.osrm*` в `/opt/gendesign/data/osrm/`.
- **Размер pbf неточен**: Ural-FO ≈600 MB на скачку; «1.5GB» из issue — оценка по
всему ФО + intermediate-файлы на диске во время build (нужно ~5 GB свободного диска).