MAATRIX / Блог / Никто не знает, что лежит на сервере: инвентаризация данных за вечер

Никто не знает, что лежит на сервере: инвентаризация данных за вечер

MAATRIX

Спросите в команде, что лежит в /data/legacy_export или зачем на сервере база analytics_old, и в половине случаев услышите тишину или неуверенное «наверное, это ещё Сергей делал». Данные на сервере копятся годами: экспорты для разового отчёта, тестовые дампы боевой базы, архивы проекта, который закрыли два года назад, папка с логами интеграции, которую отключили ещё при прошлом админе. Каждый набор в момент создания был кому-то нужен и понятен — а потом человек уволился, задача закрылась, и данные остались лежать без документации и без ответственного. Ниже — как за один вечер пройтись по серверу и составить реальную картину: что там есть, откуда оно взялось и можно ли это трогать.

Откуда берутся «ничьи» данные

Проблема не в разгильдяйстве конкретного человека, а в том, что данные почти никогда не создаются с пометкой «это временно» или «это навсегда». Аналитик выгрузил дамп продакшен-базы к себе на сервер, чтобы погонять запросы без риска для боевой системы — и через месяц забыл про него, потому что задача закрылась. Подрядчик настроил интеграцию, которая складывала вебхуки в отдельную таблицу «на всякий случай, если что-то потеряется» — интеграцию отключили, таблица осталась расти. Кто-то поднял тестовый инстанс Redis с копией сессий, чтобы отладить баг с авторизацией — баг починили, Redis не остановили.

Отдельная категория — данные, пережившие смену персонала. Если в компании нет привычки документировать, зачем создан каждый крупный набор данных, то через год-два единственным источником знания остаётся человеческая память конкретных сотрудников. Уволился инженер — ушла и память. Осталась база, каталог или бакет, у которого физически нет владельца: спросить не у кого, а трогать страшно, потому что а вдруг это всё ещё используется где-то в проде.

Третья причина — асимметрия стоимости хранения и стоимости уборки. Место на диске стоит копейки по сравнению с временем на выяснение, можно ли что-то удалить. Поэтому рациональное локальное решение каждого человека в каждый момент времени — оставить как есть. В сумме за несколько лет это даёт сервер, где реальный рабочий набор данных теряется среди наслоений прошлых задач.

Первый проход: где физически лежат крупные объёмы

Инвентаризация начинается не с вопроса «что это», а с вопроса «где вообще много места». Бессмысленно вручную обходить дерево каталогов — сначала находите крупные объекты, а смысл каждого выясняете отдельно.

Быстрый обзор по разделам диска:

df -h
du -xh --max-depth=1 / 2>/dev/null | sort -rh | head -20

Дальше — по каждому «тяжёлому» каталогу вглубь, пока не дойдёте до конкретных файлов или папок с понятным именем:

du -xh --max-depth=1 /var 2>/dev/null | sort -rh | head -20
du -xh --max-depth=1 /home 2>/dev/null | sort -rh | head -20
du -xh --max-depth=1 /opt 2>/dev/null | sort -rh | head -20
du -xh --max-depth=1 /srv 2>/dev/null | sort -rh | head -20

Если на сервере стоит ncdu — он удобнее голого du, потому что даёт интерактивно проваливаться в дерево и сразу видеть, какая ветка съедает место:

apt install ncdu   # или dnf install ncdu
ncdu -x /

Отдельно ищите крупные одиночные файлы — дампы, архивы, образы — которые могут лежать не в специально отведённом месте, а где попало, потому что кто-то один раз скачал файл на сервер и забыл про него:

find / -xdev -type f -size +200M -exec ls -lh {} \; 2>/dev/null | sort -k5 -rh | head -50

Не забудьте про типичные слепые зоны: /var/lib/docker (образы и volume-ы контейнеров), /var/lib/mysql или /var/lib/postgresql (сами базы, их du покажет как единый блоб — по ним нужен отдельный проход, см. ниже), каталоги бэкапов вроде /backup или /mnt/backups, и домашние каталоги пользователей, где годами копится «я потом разберу».

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Базы данных: отдельный обход, потому что du их не видит

Файловый обход покажет, что каталог /var/lib/postgresql весит 400 ГБ, но не скажет, за счёт каких баз и таблиц. Для СУБД нужен отдельный проход изнутри.

Для PostgreSQL — список баз и их размер:

sudo -u postgres psql -c "\l+"

Крупнейшие таблицы внутри конкретной базы:

SELECT relname AS table_name,
       pg_size_pretty(pg_total_relation_size(relid)) AS total_size
FROM pg_catalog.pg_statio_user_tables
ORDER BY pg_total_relation_size(relid) DESC
LIMIT 20;

Начиная с PostgreSQL 16 в pg_stat_all_tablespg_stat_user_tables) появились колонки last_seq_scan и last_idx_scan — время последнего последовательного и последнего индексного сканирования таблицы. Это не идеальный индикатор «использования» (счётчики сбрасываются при перезапуске сервиса и при некоторых операциях обслуживания), но для быстрой прикидки «трогали ли эту таблицу за последний год» — рабочий инструмент, если у вас достаточно свежая версия:

SELECT relname, last_seq_scan, last_idx_scan, n_live_tup
FROM pg_stat_user_tables
ORDER BY greatest(coalesce(last_seq_scan, '-infinity'), coalesce(last_idx_scan, '-infinity')) ASC;

Для MySQL/MariaDB — размер по базам и таблицам:

SELECT table_schema AS db,
       ROUND(SUM(data_length + index_length) / 1024 / 1024, 1) AS size_mb
FROM information_schema.tables
GROUP BY table_schema
ORDER BY size_mb DESC;

Активность в MySQL напрямую по таблице не отследить так же удобно, как в Postgres 16+, но косвенно помогает performance_schema (если включена) и обычный лог медленных/общих запросов за последние недели — ищите там имена баз и таблиц, которые не встречаются в свежих запросах вообще.

Для MongoDB — размеры баз и коллекций:

mongosh --eval "db.adminCommand('listDatabases')"
mongosh <dbname> --eval "db.getCollectionNames().forEach(c => print(c, db[c].stats().size))"

Для Redis активность видно через INFO keyspace (сколько ключей и с TTL ли они) и redis-cli --bigkeys — если в базе лежат ключи без TTL, которые никто не читает и не пишет по логам за последние недели, это почти наверняка забытый кэш или сессии от давно неактуального сервиса.

Отдельно проверьте дампы самих баз — .sql, .dump, .sql.gz файлы вне системы бэкапов. Их легко узнать по имени: dump_2023.sql, prod_backup_before_migration.sql, test_export.sql.gz. Такие файлы — почти всегда одноразовый артефакт чьей-то задачи, и почти всегда безопасно удаляемый после проверки, что он не единственная копия чего-то важного.

Как понять, действительно ли данные ещё используются

Найти крупный набор данных — половина дела. Вторая половина — понять, живой он или мёртвый, не полагаясь на память людей.

Время доступа к файлам. В теории atime (время последнего чтения файла) должен это показывать:

find /data/suspicious_folder -type f -printf '%A@ %p\n' | sort -n | tail -20

На практике многие серверы монтируют файловые системы с noatime или relatime ради производительности — тогда atime не обновляется при каждом чтении и показывает только примерную картину, а иногда не показывает вообще ничего полезного. Проверьте опции монтирования (mount | grep <раздел>) прежде чем доверять этому способу.

Открытые файлы и активные подключения. Если процесс прямо сейчас держит файл или сокет открытым — это сильный сигнал, что данные живые:

lsof +D /data/suspicious_folder 2>/dev/null
lsof -i :5432   # кто подключён к Postgres прямо сейчас

Логи веб-сервера. Если данные отдаются наружу через HTTP (статика, файлы, экспорты), ищите обращения к соответствующим путям за последние недели:

grep '/exports/' /var/log/nginx/access.log* | tail -50
zgrep '/exports/' /var/log/nginx/access.log.*.gz | wc -l

Cron и systemd-таймеры. Прежде чем считать каталог мёртвым, проверьте, не пишет ли в него по расписанию какой-нибудь скрипт, который просто ничего не читает обратно:

crontab -l -u www-data
systemctl list-timers --all
grep -rl "suspicious_folder" /etc/cron.d /etc/systemd/system/ 2>/dev/null

Дата создания против даты изменения. Если ctime/mtime каталога не менялись год и старше — это тоже сигнал, хотя и косвенный: некоторые архивные наборы специально не трогают годами и это нормально (юридически обязательные хранения, например). Разница между «никто не пишет, потому что забыли» и «никто не пишет, потому что так и задумано» — как раз то, что должна прояснить инвентаризация, а не автоматика.

Ни один из этих сигналов сам по себе не доказательство. Комбинируйте два-три: нет открытых хендлов, нет обращений в логах за три месяца, atime (если он вообще информативен) старше полугода — тогда можно с уверенностью помечать набор как неактивный.

Кто отвечает и как это выяснить, если ответственный уже не работает

Найти происхождение проще, чем кажется, если знать, где искать следы.

  • Права и владелец файлов. ls -la и stat покажут UID/GID — если это не системный пользователь, а конкретный аккаунт, ищите его в /etc/passwd, в списке пользователей CI/CD или в тикет-системе.
  • История коммитов, если данные пришли с кодом. Если каталог соседствует с git-репозиторием или упоминается в docker-compose.yml, git log --all -- path/to/config и git blame часто прямо называют автора и дату.
  • Метаданные объектного хранилища. Если это бакет S3-совместимого хранилища, теги и x-amz-meta-* заголовки иногда хранят автора загрузки — проверьте, не забывали ли их проставлять при заливке.
  • Переписка и тикеты. Дата создания каталога (stat -c %w, если файловая система её хранит, иначе ориентируйтесь на mtime самого старого файла внутри) — зацепка для поиска по тикетам и переписке за этот период: часто находится задача, из которой всё выросло.
  • Название и структура сами по себе. Имя базы crm_export_2024_migration или файл backup_before_upgrade_do_not_delete.sql уже рассказывают историю — не игнорируйте такие подсказки, даже если автора найти не удалось.

Если ни один способ не дал ответа — не удаляйте, а переносите в категорию «расследовать»: заведите тикет, поставьте срок (например, две недели), в течение которого кто-либо может заявить права на данные, и только после этого принимайте решение. Такой процесс закрывает главный риск инвентаризации — удалить то, что на самом деле кому-то нужно, просто человек не видел вопрос вовремя.

Итоговая таблица и что делать с результатом

Инвентаризация без письменного результата бесполезна — через полгода вы окажетесь в той же точке. Формат простой: одна строка на крупный набор данных.

ЧтоОбъёмПроисхождениеПоследняя активностьСтатус
analytics_old (Postgres)60 ГБпонятно — старая аналитика до перехода на ClickHouseнет обращений 8+ месархивировать дамп, удалить базу
/data/legacy_export15 ГБнеясно, похоже на разовую выгрузкуatime не информативен (noatime)расследовать: спросить в чате команды
redis-sessions-test2 ГБпонятно — тестовый стенд авторизациинет TTL, нет чтений в логахудалить, стенд закрыт
crm_export_2024_migration.sql.gz8 ГБпонятно — бэкап перед миграцией CRMмиграция завершена год назадбезопасно удалить (есть в бэкапах)

По каждой строке в итоге остаётся один из трёх вердиктов:

Безопасно удалить сейчас. Происхождение понятно, активности нет, есть подтверждение, что это не единственная копия (данные либо не нужны вообще, либо дублируются в системе бэкапов). Сюда же — тестовые дампы боевых баз старше пары месяцев, кэши с TTL, которые можно пересоздать, и любые файлы с явным именем «temp», «test», «old_backup».

Архивировать, а не удалять. Происхождение понятно, но данные могут понадобиться по юридическим причинам (бухгалтерия, персональные данные с обязательным сроком хранения) или как историческая справка. Сожмите, перенесите в холодное хранилище, удалите с рабочего сервера.

Требует расследования. Происхождение неясно, или есть хоть какие-то признаки активности. Не трогать до выяснения — заведите тикет с дедлайном, как описано выше.

Отдельно стоит договориться, как не оказаться в той же ситуации через год. Помогает привычка документировать каждый крупный набор данных сразу при создании — не обязательно подробно, достаточно одной строки «что, зачем, до какой даты нужно» в общем файле или README рядом с данными. Смежная практика — держать на сервере паспорт сервера, где отдельным пунктом фиксируются крупные хранилища данных и их назначение, а не только сервисы и порты. Если вы уже проводили обход процессов и портов, но не данных, это разные задачи: инвентаризация всего, что крутится на сервере — про сервисы и автозапуски, а не про содержимое дисков и баз. Для того, что попадёт в категорию «удалить», заранее сверьтесь с регламентом удаления данных и копий в бэкапах, чтобы не снести единственную сохранившуюся копию. А если вечера на инвентаризацию данных мало и хочется закрыть сервер целиком — от портов и процессов до пользователей и cron — за один заход, посмотрите план аудита сервера на выходные.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

Частые вопросы

Сколько времени реально занимает такая инвентаризация?

Для сервера среднего размера (десятки гигабайт данных, две-три базы) первый проход — обзор каталогов, баз и составление списка — укладывается в один вечер, три-четыре часа. Расследование неясных пунктов растягивается на дни или недели, потому что зависит от ответов людей, а не от вашей скорости.

Что делать, если данные явно содержат персональные данные, а происхождение неясно?

Не удаляйте и не перемещайте до выяснения статуса — сначала разберитесь, подпадают ли они под обязательные сроки хранения и кто субъект данных. Это отдельная тема, шире, чем просто «занимает место».

Нужно ли останавливать сервисы на время инвентаризации?

Нет, весь описанный обход — чтение метаданных и статистики, без блокировок и без влияния на продакшен. Исключение — если вы решите снять pg_dump или аналог для архивации найденного, это стоит планировать как обычную операцию с бэкапом, с учётом нагрузки.

Как часто повторять инвентаризацию, чтобы не накапливалось заново?

Полный обход раз в полгода-год обычно достаточен, если параллельно ввели привычку документировать новые крупные наборы данных сразу при создании — тогда между обходами накапливается меньше неясного.

Что если набор данных используется, но раз в квартал (например, отчётность)?

Прежде чем удалять что-то с нечастой, но регулярной активностью, проверьте более длинное окно логов и спросите в команде напрямую — периодическое использование легко спутать с полным простоем, если смотреть на активность только за последний месяц.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →