gendesign/docs/osrm-routing.md
bot-backend 4fe20a9cbd
All checks were successful
Deploy / changes (push) Successful in 7s
Deploy / build-worker (push) Successful in 46s
Deploy / deploy (push) Successful in 1m18s
Deploy / build-frontend (push) Successful in 31s
Deploy / build-backend (push) Successful in 33s
feat(devops): self-hosted OSRM routing engine for site-finder (#39) (#1929)
2026-06-26 19:18:21 +00: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 свободного диска).