Files
admin/.wiki/concepts/books-vds-memory-optimize-runbook.md

7.2 KiB
Raw Blame History

title, type, tags, related, updated
title type tags related updated
books VDS — оптимизация памяти (mongo wiredTiger / ES heap / CI-остатки) concept
runbook
books
vds
mongo
elasticsearch
oom
memory
backup
admin
concepts/runbooks-index.md
concepts/gitea-project-create-runbook.md
2026-08-28

books VDS — оптимизация памяти (OOM → ECONNREFUSED)

⚙️ СЛУЖЕБНЫЙ РАНБУК — только для администратора проекта .admin. Применять/выполнять шаги может только .admin (оператор проекта admin). Другим проектам/агентам — читать по запросу, не выполнять. Из проекта не выносить: не копировать в другие вики, не пересказывать, не публиковать. Нужен деплой или прод-операция по этому ранбуку — поставить задачу админу (.admin) и написать письмо. Админ выполняет, остальные верифицируют.

Scope

Остановить OOM-цикл на books VDS (89.253.255.133, host4g VPS, CentOS 7), который вызывает [sched:slovo] sync.failed: ECONNREFUSED 172.20.0.5:27017. Причина — дефицит ОЗУ: хост 3.9GB RAM, free ~136MB, swap 100%, OOM-kill mongod (dmesg Out of memory: Kill process (mongod) score ~114). Симптом-задача — «ozon fbs products syncronization» (books-sched, прод slovo).

Артефакты

  • Хост: 89.253.255.133 (books VDS). SSH: ssh -i ~/.ssh/id_ed25519_books_ops root@89.253.255.133.
  • Креды: <из pass books-vds/full-env> (BOOKS_DB_*, BOOKS_MONGO_*, BOOKS_PORTAINER_*).
  • mongo (БД sched): books-job-scheduler-mongo = 172.20.0.5:27017, image mongo:4.2, БД agendaDb (sched-задачи: sched_tasks, sched_schedules, sched_runs). Source-of-truth compose: /usr/docker/books-job-scheduler/docker-compose.yml (files-based, НЕ Portainer-kzntsv).
  • ES: elasticsearch (стек 33, /usr/docker/elasticsearch/docker-compose.yml, ES_JAVA_OPTS=-Xmx256m), bookva-es (Portainer стек 37, endpoint 1; ES_JAVA_OPTS урезан 512m→-Xmx256m).
  • CI-остатки: buildx_buildkit_builder-* (moby/buildkit:buildx-stable-1), удалены.

Диагностика (как понять, что это OOM)

ssh root@89.253.255.133 '
  free -m; dmesg | grep -iE "oom|killed process" | tail;      # free ~136MB, swap 100%, Killed (mongod)
  docker stats --no-stream --format "{{.MemUsage}}\t{{.Name}}" | sort -rh | head;  # кто жрёт
'

Кто жрёт (на 2026-08-28): books-job-scheduler-mongo 715MiB (главный), minio 248+140, elasticsearch 242, bookva-es 223.

Шаги (по порядку эффекта)

1. Урезать books-job-scheduler-mongo wiredTiger (главный фикс, ~+450MB)

cd /usr/docker/books-job-scheduler
cp docker-compose.yml docker-compose.yml.bak
# вставить после "        restart: always" в сервисе books-job-scheduler-mongo:
#   command: ["mongod", "--wiredTigerCacheSizeGB", "0.25"]
docker compose up -d books-job-scheduler-mongo

Verify: docker logs books-job-scheduler-mongo | grep -i "cache_size"cache_size=256M; docker exec books-job-scheduler-mongo mongo --quiet --eval "db.runCommand({ping:1}).ok" = 1.

2. Снести CI-остатки buildx_buildkit_builder-* (сироты от CI)

docker rm -f buildx_buildkit_builder-1ba06752-bf56-4b50-88c5-ce1b48f44a4e0 buildx_buildkit_builder-f61c259c-48e3-4401-b2ca-2404c5cd76070

3. Урезать ES heap (вторично; elasticsearch уже 256m)

bookva-esES_JAVA_OPTS=-Xms512m -Xmx512m-Xms256m -Xmx256m. Сделано: Portainer PUT стека 37 (PUT /api/stacks/37?endpointId=1 с реконструированным compose). Verify: docker logs bookva-es | grep heapheap size [256mb].

Verify / smoke

  • free -m — free растёт, swap падает (mongo cache_size=256M).
  • Нет новых Out of memory: Kill (mongod) в dmesg на следующем окне (~06:06).
  • docker statsbooks-job-scheduler-mongo ≪715MiB.
  • sched-задачи (ozon fbs products syncronization) больше не дают ECONNREFUSED 172.20.0.5:27017.

Rollback

  • mongo: git checkout-возврат command в compose (или cp docker-compose.yml.bak docker-compose.yml) → docker compose up -d books-job-scheduler-mongo.
  • ES: вернуть ES_JAVA_OPTS.

Gotchas

  1. OOM ежедневно ~06:06 — пик в бэкап-окно (mongodump+mariadb-dump+ES snapshot в 06:00 MSK). Урезка снижает, но ХОСТ обделён (3.9GB) — радикальный фикс = апгрейд RAM или Manticore вместо ES.
  2. Книги-стеки — через portainer.kzntsv.site endpoint 1 (= books VDS): GET /api/stacks показывает id 2251 (books/web/api/ntfy/ops-mcp/chrome/proxy/imgproxy/minio/mongo/db/elasticsearch + bookva-*). Часть из них — files-based /usr/docker/*/docker-compose.yml (напр. books-job-scheduler-mongo урезан файлом + docker compose up -d). При правке стека держать Portainer-источник и файл синхронными, не плодить расхождения.
  3. com.docker.compose.project.config_files=/data/compose/22 (label) — старый путь Portainer; /data/compose/* на диске НЕ существует. Реальный источник — /usr/docker/*/docker-compose.yml.
  4. compose-файлы в CRLF (\r\n) — python-патч учитывать line-ending (иначе needle не матчит).
  5. bookva-esPortainer стек 37 (endpoint 1). Доступ есть: BOOKS_PORTAINER_URL + BOOKS_PORTAINER_API_KEY из pass books-vds/full-env. НО GET /api/stacks/:id НЕ отдаёт stackFileContent (в этой версии Portainer), поэтому compose реконструируется из docker inspect и обновляется через PUT стека. Не менять вслепую без этих данных.
  6. mongo warning XFS — предупреждение, не ошибка (данные на ext4).
  7. command массив в compose: command: ["mongod", "--wiredTigerCacheSizeGB", "0.25"] — строку тоже можно, но список надёжнее.

Будущее направление — замена ES → Manticore

ES в стеке книг — источник перегруза (Java JVM). Manticore Search — без Java, легче (сотни MB против 500+MB), быстрее на полнотекстовом поиске. Оправдано, если ES используется для полнотекстового поиска товаров/книг (не анализа/DSL-агрегаций). Тогда урезать оба ES, переписать поиск на Manticore-протокол (SphinxQL/HTTP) и бэкапы. Отдельная задача/ранбук.