From 407f6c4faf515e4598fe28003866a45f219cc228 Mon Sep 17 00:00:00 2001 From: Conrad Schulz Date: Sat, 13 Jun 2026 10:12:48 +0000 Subject: [PATCH] fix: satellite-download OOM gefixt (bounded queue), 16 Threads, 2GB Limit --- docker-compose.download.yml | 9 +++++++- docs/ADMIN.md | 2 ++ ...-06-13_tile-raster-architecture_session.md | 16 ++++++++++++-- docs/history/summary/PROJECT_CONTEXT.md | 2 +- scripts/download-satellite.py | 22 ++++++++++++++----- 5 files changed, 42 insertions(+), 9 deletions(-) diff --git a/docker-compose.download.yml b/docker-compose.download.yml index 4313b69..7344473 100644 --- a/docker-compose.download.yml +++ b/docker-compose.download.yml @@ -29,7 +29,14 @@ services: - ./logs:/logs environment: - SAT_MAX_ZOOM=11 - - SAT_THREADS=8 + - SAT_THREADS=16 - PYTHONUNBUFFERED=1 command: ["python3", "-u", "/scripts/download-satellite.py", "/data/satellite.mbtiles"] restart: "no" + deploy: + resources: + limits: + cpus: "4.0" + memory: 2048M + reservations: + memory: 128M diff --git a/docs/ADMIN.md b/docs/ADMIN.md index 9676a88..3297793 100644 --- a/docs/ADMIN.md +++ b/docs/ADMIN.md @@ -66,6 +66,8 @@ curl -s "http://localhost:9983/osm-intl/0/0/0.png" > /tmp/test.png && file /tmp/ Der Download läuft in einem eigenen Container – vollständig unabhängig von SSH-Sessions und VS Code. Resume-fähig: bei Unterbrechung einfach neu starten. +**Ressourcen:** 16 Threads, 2 GB RAM-Limit, 4 CPUs – konfigurierbar in `docker-compose.download.yml`. + ```bash cd /mnt/services-data/rd13_tile_server diff --git a/docs/history/prompts/2026-06-13_tile-raster-architecture_session.md b/docs/history/prompts/2026-06-13_tile-raster-architecture_session.md index 0164d28..a3d2502 100644 --- a/docs/history/prompts/2026-06-13_tile-raster-architecture_session.md +++ b/docs/history/prompts/2026-06-13_tile-raster-architecture_session.md @@ -66,8 +66,20 @@ Lösung: eigenständiger Docker-Container für Downloads. `docker-compose.download.yml` erstellt, Script mit `flush=True` robuster gemacht. Überreste bereinigt: satellite.mbtiles (4 KB stub), satellite.mbtiles-shm/wal, satellite.log. -### Prompt 9 -Erstelle einen eigenen Container nur für den Download, der muss nicht in dem Compose leben. +### Prompt 10 +Starte nochmal alle neu ich habe nochmal etwas mehr Ressourcen bereitgestellt. + +### Antwort 10 +OOM-Ursache identifiziert: Script submittete alle 5,5 Mio Futures gleichzeitig in eine Liste → Memory-Spike beim Aufbau. +Fix: Bounded Queue mit `threading.Semaphore(THREADS * 4)` – max 64 Futures gleichzeitig im Speicher. +Threads auf 16 erhöht, RAM-Limit auf 2 GB. Alte korrupte MBTiles entfernt, neu gestartet. + +Ergebnis: +``` +CPU: 18% RAM: 44 MiB / 2 GiB Threads: 16 +data/satellite.mbtiles wächst von 4KB → 5.4MB → ... +``` +Container läuft stabil ohne OOM. ### Antwort 9 Service aus `docker-compose.yml` entfernt. diff --git a/docs/history/summary/PROJECT_CONTEXT.md b/docs/history/summary/PROJECT_CONTEXT.md index be6e159..0bac89e 100644 --- a/docs/history/summary/PROJECT_CONTEXT.md +++ b/docs/history/summary/PROJECT_CONTEXT.md @@ -1,6 +1,6 @@ # PROJECT_CONTEXT – rd13_tile_server -**Letzte Aktualisierung:** 2026-06-13 – OSM Bright GL Style (128 Layer) aktiv, Satellit-Download-Container bereit, Host-Build-Workflow dokumentiert, alle Overreste bereinigt. +**Letzte Aktualisierung:** 2026-06-13 – Satellit-Download läuft stabil (16 Threads, 2GB RAM-Limit, OOM-Fix). Download-Container eigenständig. --- diff --git a/scripts/download-satellite.py b/scripts/download-satellite.py index 70c3eb4..04912fe 100755 --- a/scripts/download-satellite.py +++ b/scripts/download-satellite.py @@ -86,12 +86,24 @@ def main(): log("[Sat] Resume: bereits heruntergeladene Tiles werden übersprungen") conn = init_db(OUTPUT) t0 = time.time() + n = 0 + # Bounded queue: max THREADS*4 Futures gleichzeitig im Speicher + # verhindert OOM bei 5.5 Mio Tasks + sem = threading.Semaphore(THREADS * 4) + + def submit_tile(ex, z, x, y): + sem.acquire() + fut = ex.submit(do_tile, conn, z, x, y) + fut.add_done_callback(lambda _: sem.release()) + return fut + with ThreadPoolExecutor(max_workers=THREADS) as ex: - submitted = [ex.submit(do_tile, conn, z, x, y) - for z in range(MAX_ZOOM + 1) - for x in range(1 << z) - for y in range(1 << z)] - for n, f in enumerate(as_completed(submitted), 1): + futs = [] + for z in range(MAX_ZOOM + 1): + for x in range(1 << z): + for y in range(1 << z): + futs.append(submit_tile(ex, z, x, y)) + for n, f in enumerate(as_completed(futs), 1): f.result() if n % 1000 == 0 or n == total: dt = time.time() - t0 or 0.001