В предыдущей статье мы рассказали, как оптимизировали работу с изображениями в агрегаторе презентаций. Это помогло. Дискам стало легче, страницы сайта начали загружаться быстрее. Все радовались. После того, как контент разлетелся по разным дискам, мы снова запустили конвейер обработки презентаций. Контент попёр. И пёр. И пёр. Мы безумно радовались. Даже не замечая, что целимся в собственную ногу.

В какой-то момент изображения стали отдаваться медленно. Нет, не так: ОЧЕНЬ медленно. И не только отдаваться. Иногда не получалось установить соединение с nginx’ом. Iotop снова показывал нагрузку в 99.99%, только теперь на двух дисках. Как? Почему? Откуда такая нагрузка? Наверное, мы стали слишком популярными. И диски медленные. И вообще, это лабораторный проект, зачем нормально разбираться?
За такие мысли моя прошлая версия заслуженно получила бы по голове.
Проблемы со свободным местом на дисках
Конвейер с обработкой презентаций остановился. Раз — и новых презентаций больше не было. В логах висела грустная надпись, что не удалось сохранить файл на диск — место кончилось. Место. Кончилось. Мы съели восемь терабайт.
При этом вывод `df` показывал, что место еще есть. И не какие-то зарезервированные в ext4 проценты, а вполне адекватные значения. Но ничего на диске сделать не получалось.
Проблема в том, что люди бывают не только глупыми, но и невнимательными.
Маркетологи предложили удалить непосещаемые презентации, чтобы освободить место. За неимением других вариантов приняли это решение. Собрали презентации, которые приносили мало трафика, и спокойно закинули на удаление.

Удаление шло долго. Дискам и без того было тяжело, а тут требовалось удалить несколько миллионов мелких файлов, раскинутых по глубоким путям. Наконец, оно закончилось. Мы радостно запустили конвейер, увидели, что процесс пошёл, и мирно оставили его. Зря.
Поиск и решение проблемы
Через не очень продолжительное время контейнер с обработкой остановился. Снова. Ровно с той же проблемой — нет места на диске. А `df` снова показывает, что место есть и его много.
Небольшое техническое отступление, чтобы пояснить, что произошло. В ext4 всё — файл. И папка — это файл. Для организации файловой таблицы используются inode — специальные структуры данных, которые хранят различные метаданные о хранимых файлах. Количество этих самых inode конечно и задаётся при первоначальном создании файловой системы. Например, на нашем сервере со статикой, на разделе в 4 терабайта будет где-то 243 миллиона этих самых inode. Каждый файл при сохранении использует 1 inode.
Места не было. Я буквально ничего не мог сделать. Почистил всё, что можно, но существенно это ситуацию не поменяло. Тут я вспомнил про inode ы. Пишу `df -i` и… впадаю в ступор. IUse% — 100. На двух дисках. Как? Что могло съесть такое количество inode? И тут до меня начинает ме-е-едленно доходить.
Сколько всего inode? Примерно 243 миллиона. Насколько глубокий путь я делал для статики? 8 папок. Что там с распределением? Начиная где-то с третьей папки количество папок в подпапках будет в районе единицы. Используя очень грубую оценку, можно получить, что при сохранении одного файла на диск мы занимаем 9 inode — 1 для файла, 8 для папок.
Каждая картинка сохраняется как две — ещё в WebP. Отдельно лежат слайды, отдельно лежат изображения со слайдов. Ещё отдельно лежат сами презентации, но их количество на пару порядков меньше, поэтому пока что пренебрегаем ими. Используя методы для статистики, я получил что-то в районе 13–14 миллионов файлов в сервисе статики. Умножив это число на 9, а затем на 2, получил те самые 243 миллиона inode. Загадка разгадана.
Делать-то что? Конвейер с обработкой презентаций остановлен. Его нет смысла запускать, мы снова займем все inode’ы. На ум приходит хорошее и более разумное решение. Делаем, скажем, всего два уровня папок по тому же правилу с хэшом.
Об этом моя прошлая версия не догадалась, а решила броситься в крайность. Сначала мы все храним в одной папке — это плохо, поэтому будем хранить все в отдельных и максимально дробных папках.

Идем по проторенной дорожке. Вносим изменения в сервис для статики, чтобы все новое раскладывалось с учётом исправлений. Делаем небольшое приложение, которое будет рекурсивно поднимать всю старую статику наверх на несколько уровней. Настраиваем nginx для корректной обработки старых ссылок.
Параллельно решаем избавиться от изображений со слайдов — их много, а процент трафика с них небольшой. Таким образом, у нас снова пачка операций на дисках, только теперь уже на двух. Одна — удаление изображений, вторая — перенос старых изображений.
Оцениваем время, которое потребуется на удаление и перенос. Получаем неприятные 2–2,5 месяца, когда конвейер с обработкой презентаций запускать бессмысленно. Обидно, досадно, но ладно. ССЗБ. Пока происходят тяжелые операции на дисках, можно заняться менее детерминированными задачами, которые улучшат ситуацию. Например, сделать превентивное удаление дублей контента, о котором расскажем в следующий раз.