В предыдущей статье мы рассказали, как построили работу серверов и оптимизировали изображения в нашем агрегаторе презентаций. Это помогло. Дискам стало легче, страницы сайта начали загружаться быстрее. После того, как контент разлетелся по разным дискам, мы снова запустили конвейер обработки презентаций. Контент попёр. Мы радовались, даже не замечая, что целимся в собственную ногу. В какой‑то момент изображения стали отдаваться медленно. Точнее ОЧЕНЬ медленно. И не только отдаваться. Иногда не получалось установить соединение с 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 месяца, когда конвейер с обработкой презентаций запускать бессмысленно. Обидно, досадно, но ладно. Пока происходят тяжелые операции на дисках, можно заняться менее детерминированными задачами, которые улучшат ситуацию. Например, сделать превентивное удаление дублей контента, о котором расскажем в следующий раз.