diff --git a/README.md b/README.md index 9fe4e08..a638adf 100755 --- a/README.md +++ b/README.md @@ -70,7 +70,8 @@ graph TB остановка, продолжение работы и диагностика. Для одного учащегося рекомендуем компьютер с 16 ГБ RAM, не менее 4 CPU и -10 ГБ памяти, доступных Docker, а также от 20 ГБ свободного места перед сборкой. +ориентировочно 8 ГБ памяти для Docker, а также от 20 ГБ свободного места перед сборкой. +Trino ограничен 2 ГиБ памяти контейнера и 1 ГиБ Java heap. Подробности и границы проверки — в [системных требованиях](./START_HERE.md#системные-требования). Краткий запуск из корня репозитория после подготовки по `START_HERE`: diff --git a/START_HERE.md b/START_HERE.md index 9fed560..a9e8514 100644 --- a/START_HERE.md +++ b/START_HERE.md @@ -39,15 +39,21 @@ | Ресурс | Рекомендация | Что проверить | | --- | --- | --- | | Процессор | Не менее 4 CPU, доступных Docker | В Docker Desktop/WSL2 может стоять меньший лимит | -| Память Docker | Не менее 10 ГБ RAM | Это память для контейнеров, а не общий объем памяти компьютера | +| Память Docker | Ориентир — 8 ГБ RAM; 10 ГБ дают дополнительный запас | Это память для среды Docker, а не общий объем памяти компьютера | | Память компьютера | 16 ГБ RAM или больше | Оставь память ОС, браузеру и другим приложениям | | Свободное место | Не менее 20 ГБ перед первой сборкой; 30 ГБ с запасом | На диске Docker и в папке репозитория: образы, кэш сборки, исходные данные и таблицы | -Это рекомендуемый бюджет, а не измеренный минимальный порог. Полный курс на -машине с 8 ГБ RAM не проверен. В Docker Desktop проверь -[лимиты ресурсов](https://docs.docker.com/desktop/settings-and-maintenance/settings/#resources); -для режима WSL2 лимиты задаются у виртуальной машины WSL2. Место внутри диска -Docker и свободное место на диске компьютера — отдельные ограничения. +Это рекомендуемый бюджет для одного активного ноутбука, а не измеренный минимум. +На Windows с WSL2 по умолчанию доступно 50% RAM компьютера: при 16 ГБ это 8 ГБ +для всей WSL2, включая Docker. Лимит можно настроить, это не аппаратное +ограничение. См. [настройки WSL2](https://learn.microsoft.com/en-us/windows/wsl/wsl-config#main-wsl-settings) +и [ресурсы Docker Desktop](https://docs.docker.com/desktop/settings-and-maintenance/settings/#resources). + +Trino ограничен 2 ГиБ памяти контейнера и 1 ГиБ Java heap. Проверка запросов +на данных курса описана в [справочнике](./docs/stack_reference.md#ресурсы-и-проверенная-среда). +Полный курс под общим жестким лимитом Docker 8 ГБ пока не проверен. В WSL2 часть +памяти также нужна самой Linux-среде; закрой другие тяжелые задачи на время урока. +Место внутри диска Docker и свободное место на диске компьютера — отдельные ограничения. С добавлением VS Code образ окружения вырос примерно на 1,2 ГБ относительно Jupyter; базовые слои у них общие. MinIO скачивается готовым, компилировать его @@ -74,7 +80,7 @@ docker compose config --quiet В `docker version` должны быть разделы Client и Server, версия Compose — не ниже 2.17. `docker info` показывает ресурсы, которые видит Docker; память дана -в байтах (10 ГБ — примерно 10 000 000 000 байт). Последняя команда при успехе +в байтах (8 ГиБ — 8 589 934 592 байта). Последняя команда при успехе ничего не печатает. Если Docker не отвечает или конфигурация не читается, исправь эту ошибку до сборки. diff --git a/docker-compose.yml b/docker-compose.yml index 22b7bdd..8e04b70 100755 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -231,6 +231,9 @@ services: image: trinodb/trino:478 container_name: trino hostname: trino + # Heap JVM ограничен отдельно в trino/jvm.config; остальное — запас вне heap. + mem_limit: 2g + memswap_limit: 2g networks: - spark-net depends_on: @@ -245,6 +248,7 @@ services: - "8090:8080" # Web UI Trino volumes: - ./trino/catalog:/etc/trino/catalog:ro + - ./trino/jvm.config:/etc/trino/jvm.config:ro networks: spark-net: diff --git a/docs/stack_reference.md b/docs/stack_reference.md index 84f97cd..b845256 100644 --- a/docs/stack_reference.md +++ b/docs/stack_reference.md @@ -65,9 +65,18 @@ MinIO и PostgreSQL. У каждого worker-а в Compose указаны 2 CPU Проверка 19 октября 2026 года: Linux x86_64, Docker Engine, 6 CPU и около 11,1 ГиБ памяти, видимых Docker. Выполнены первый ноутбук в Chromium и проверка -Spark → Iceberg → Trino. Прогона всех восьми модулей с измерением пиков памяти -и диска не было; минимальный объем RAM не установлен. Docker Desktop и ARM64 -в этой проверке не запускались. +Spark → Iceberg → Trino. Затем Trino проверен с лимитом контейнера 2 ГиБ и heap +1 ГиБ на трех месяцах Taxi: 9 554 778 строк bronze, 9 418 184 строк silver +и 265 зон. Запросы Модуля 6 и дополнительный JOIN со справочником прошли; +агрегаты и JOIN сверены со Spark. Пик памяти контейнера Trino по cgroup составил +около 1,25 ГиБ, событий OOM и перезапусков не было. + +Наблюдавшийся суммарный пик памяти контейнеров без неактивного файлового кэша +составил около 5,44 ГиБ. Это измерение выбранного сценария, а не проверка всей +среды под общим лимитом 8 ГБ: память Docker daemon, ядра и других процессов +Linux/WSL2 в сумму не входит. Прогона всех восьми модулей под таким лимитом +не было. Docker Desktop и ARM64 в этой проверке не запускались. +Методика и результаты сохранены в [отчете проверки](../plans/trino-memory-validation.md). Размеры локально собранных образов на этой машине: Spark — около 3,37 ГБ, Jupyter — 3,72 ГБ, IDE — 4,90 ГБ. Jupyter включает слои Spark, IDE включает слои @@ -107,6 +116,27 @@ docker compose exec ide python3 /opt/src/spark/cluster_smoke.py ### Trino - Web UI: `http://localhost:8090` +- Контейнер ограничен 2 ГиБ RAM (`mem_limit: 2g`). `memswap_limit: 2g` + отключает swap для него: одинаковое значение задает общий предел RAM + swap. +- В [`trino/jvm.config`](../trino/jvm.config) heap Java начинается с 512 МиБ + и может вырасти до 1 ГиБ (`-Xms512M`, `-Xmx1G`). Остальная память контейнера + оставлена для потоков, служебных структур JVM и буферов вне heap. + +Эти ограничения относятся к Trino; у всего Compose-проекта общего лимита +памяти нет. Если контейнер достигнет жесткого предела, он может быть завершен +системой. Увеличение только heap без изменения бюджета контейнера уменьшает +запас для памяти вне heap. См. [лимиты Compose](https://docs.docker.com/reference/compose-file/services/#mem_limit) +и [настройку JVM Trino](https://trino.io/docs/current/installation/deployment.html#jvm-config). + +После обновления этих файлов примени настройки из терминала хоста: + +```bash +docker compose up -d --no-deps --force-recreate trino +docker compose ps -a trino +``` + +Дождись `healthy`. Эта операция пересоздает только Trino и применяет в том числе +изменения содержимого `jvm.config`; таблицы остаются в MinIO и PostgreSQL. CLI внутри контейнера: @@ -240,6 +270,7 @@ JupyterLab остаётся запасным интерфейсом. Он ред | `docker-compose.yml` | состав сервисов, порты, volumes, init-контейнеры | | `spark/spark-defaults.conf` | Spark master, catalog `lakehouse`, `s3a`, Iceberg extensions | | `trino/catalog/lakehouse.properties` | каталог Trino `lakehouse`, JDBC и S3-доступ | +| `trino/jvm.config` | JVM Trino: heap до 1 ГиБ внутри контейнера с лимитом 2 ГиБ | | `spark/Dockerfile` | образ Spark с Iceberg, S3A и Python-зависимостями | | `jupyter/Dockerfile` | образ JupyterLab на базе Spark | | `ide/Dockerfile` | code-server и расширения на базе образа Jupyter | diff --git a/plans/trino-memory-validation.md b/plans/trino-memory-validation.md new file mode 100644 index 0000000..afff659 --- /dev/null +++ b/plans/trino-memory-validation.md @@ -0,0 +1,107 @@ +# Проверка лимита памяти Trino + +Дата: 19 октября 2026 года. Это отчет о проверке; актуальная конфигурация +находится в `docker-compose.yml` и `trino/jvm.config`, требования для учащегося — +в `START_HERE.md`. + +## Что проверяли + +Trino 478 в контейнере с пределом 2 ГиБ RAM, без swap, с Java heap от 512 МиБ +до 1 ГиБ. JVM сама подбирает размер регионов G1; вместо настройки образа +`G1HeapRegionSize=32M` для большого heap получен регион 1 МиБ. + +Среда: Linux x86_64, Docker Engine, cgroup v2, 6 CPU и 11,14 ГиБ памяти, +видимых Docker. Остальные сервисы стенда работали одновременно. Общего лимита +8 ГБ для проекта или виртуальной машины в этом прогоне не было. + +Исходные файлы основного маршрута курса: + +| Файл | Размер, байт | +| --- | ---: | +| `yellow_tripdata_2024-01.parquet` | 49 961 641 | +| `yellow_tripdata_2024-02.parquet` | 50 349 284 | +| `yellow_tripdata_2024-03.parquet` | 60 078 280 | +| `taxi_zone_lookup.csv` | 12 331 | + +Файлы взяты из уже скачанного учебного набора, без выборки или сокращения. + +## Сценарий + +1. Перед изменением проверены отсутствие активных Spark-приложений и запросов + Trino, чтение существующей таблицы `lakehouse.default.spark_trino_smoke`. +2. Пересоздан только Trino. Запуск до `SERVER STARTED` занял около 25 секунд, + healthcheck прошел. +3. Созданы отдельная временная схема `trino_memory_` и собственный префикс + `validation/trino_memory_/raw/` в MinIO. Таблицы курса не перезаписывались. +4. Spark подготовил bronze и справочник по SQL Модуля 4; фильтры, нормализации, + два JOIN со справочником и silver выполнены кодом Модуля 5. Проверки качества + этого модуля также прошли. Получены 9 554 778 строк bronze, 9 418 184 строк + silver и 265 строк справочника. +5. Через Python-клиент Trino выполнены 11 запросов из Модуля 6: просмотр схем, + таблиц и колонок, выборки, подсчет строк, общие метрики, агрегаты по районам + и топ-10 зон. Имена таблиц заменены на временные; SQL сохранен. +6. Дополнительно дважды выполнен JOIN всей bronze со справочником зон и + группировкой по району: + + ```sql + SELECT z.Borough, count(*) AS trips, avg(b.fare_amount) AS avg_fare + FROM b + LEFT JOIN z ON b.PULocationID = z.LocationID + GROUP BY z.Borough + ORDER BY trips DESC; + ``` + +7. Подсчет строк, общие метрики, агрегаты по районам, топ зон, чтение созданной + Spark таблицы итогов и оба JOIN сверены с результатами Spark. Для чисел с + плавающей точкой использован допуск `1e-8`. Ошибки Python-клиента Trino + пробрасывались наружу, без обработчика исключений из ноутбука. +8. Повторно прочитана прежняя smoke-таблица: результат `1 / from_spark` сохранен. + Всего завершились успешно 14 запросов. Временные таблицы удалены с `PURGE`, + затем удалены временная схема и собственный raw-префикс. После `PURGE` + отдельно удалены восемь пустых маркеров каталогов в собственном warehouse-префиксе. + Проверено отсутствие временных объектов; исходные Parquet/CSV на хосте сохранены. + +## Измерения + +| Показатель | Результат | +| --- | ---: | +| Лимит контейнера (`memory.max`) | 2 147 483 648 байт | +| Лимит swap (`memory.swap.max`) | 0 | +| Фактический `MaxHeapSize` через `jcmd 1 VM.flags` | 1 073 741 824 байта | +| Пик контейнера Trino (`memory.peak`) | 1 340 874 752 байта, около 1,25 ГиБ | +| События `oom`, `oom_kill`, `max` в `memory.events` | 0 | +| Перезапуски Trino | 0 | +| Пик суммы `memory.current` восьми контейнеров | около 5,89 ГиБ | +| Пик той же суммы за вычетом `inactive_file` | около 5,44 ГиБ | + +Суммарная память снималась раз в секунду, получено 165 отсчетов во время +подготовки таблиц, запросов и очистки. Пик Trino взят из счетчика cgroup, +который учитывает и запуск контейнера. Вычитание `inactive_file` приближает +сумму к показателю памяти в `docker stats`; файловый кэш показан отдельно. + +Агрегаты по silver обработали 9 418 184 строки каждый, что подтверждено +статистикой запросов Trino. `count(*)` по bronze использовал метаданные Iceberg; +проверкой чтения bronze служил также JOIN со справочником. + +## Границы вывода + +Бюджет Trino 2 ГиБ / heap 1 ГиБ достаточен для проверенных запросов на основном +наборе курса при одном учащемся. Измерение не подтверждает работу всех восьми +модулей под общим жестким лимитом 8 ГБ. В сумму контейнеров не входят Docker +daemon, ядро и другие процессы Linux/WSL2. Docker Desktop, Windows, ARM64, +параллельные занятия и расширенный набор Taxi за 12 месяцев не проверялись. + +Для повторной проверки подними стенд с этой конфигурацией и пройди модули 3–6 +на трех месяцах Taxi, добавив JOIN выше. Временная схема нужна, если важно +сохранить существующие учебные таблицы. Примененный лимит можно проверить +с хоста: + +```bash +docker inspect --format '{{.HostConfig.Memory}} {{.HostConfig.MemorySwap}}' trino +docker compose exec trino jcmd 1 VM.flags +docker compose exec trino cat /sys/fs/cgroup/memory.peak +docker compose exec trino cat /sys/fs/cgroup/memory.events +``` + +Последние два пути относятся к cgroup v2; счетчики накапливаются с запуска +контейнера. Числа нового прогона могут отличаться. diff --git a/trino/jvm.config b/trino/jvm.config new file mode 100644 index 0000000..d92a48d --- /dev/null +++ b/trino/jvm.config @@ -0,0 +1,17 @@ +# Параметры образа trinodb/trino:478 с бюджетом памяти для локального курса. +-server +-agentpath:/usr/lib/trino/bin/libjvmkill.so +-Xms512M +-Xmx1G +# Размер регионов G1 выбирает JVM с учетом небольшого heap. +-XX:+ExplicitGCInvokesConcurrent +-XX:+HeapDumpOnOutOfMemoryError +-XX:+ExitOnOutOfMemoryError +-XX:-OmitStackTraceInFastThrow +-XX:ReservedCodeCacheSize=256M +-XX:PerMethodRecompilationCutoff=10000 +-XX:PerBytecodeRecompilationCutoff=10000 +-Djdk.attach.allowAttachSelf=true +-Djdk.nio.maxCachedBufferSize=2000000 +-Dfile.encoding=UTF-8 +-XX:+EnableDynamicAgentLoading