Что делать при таймаутах PDF сервиса, если добавление инстансов не помогает
Что проверяют
Сделаете ли вы вывод из самой формулировки. Инстансы не помогают, значит узкое место не в их количестве: либо оно общее для всех, либо нагрузка вообще не параллелится. Смотрят, начнёте ли вы с измерения или продолжите докидывать ресурсы.
Как отвечать
Скажите вслух, что «добавили инстансы, не помогло» это диагностический факт, и переберите, что он оставляет:
- общий ресурс: база, сетевое хранилище, единый внешний сервис за рендером, лицензионный лимит;
- блокировка или очередь: запросы стоят в ожидании, а не считают;
- насыщение внутри инстанса: рендер упирается в процессор, а потоков на нём больше, чем ядер, и от этого каждый запрос только медленнее;
- память: документ собирается в куче целиком, отсюда долгие паузы сборщика мусора и отказы на больших отчётах.
Дальше измерения: разложить время одного запроса по этапам (ожидание в очереди, выборка данных, рендер, запись), посмотреть загрузку процессора на инстансе. Если он не загружен, добавление инстансов и не должно было помочь, и это сразу сужает поиск. Профиль снимается на работающем сервисе, например через async-profiler.
Решения по результату: вынести генерацию в асинхронный сценарий, когда запрос возвращает идентификатор задачи, а файл забирается по ссылке; ограничить число одновременных рендеров на инстанс; кэшировать готовые документы по ключу от содержимого; развести тяжёлые и лёгкие отчёты по разным очередям; стримить результат вместо сборки в памяти.
Где спотыкаются
Продолжают лечить симптом: поднять таймаут, докинуть инстансов, увеличить кучу. Вопрос ровно про то, почему это не сработало, и повтор того же действия читается как отсутствие гипотезы.
Кэшируют готовые файлы в Redis без оговорок. Мегабайтные значения бьют по сети и вытесняют из памяти всё полезное, для файлов уместнее объектное хранилище или диск, а ключ надо считать от данных документа, иначе попаданий не будет вовсе.
Предлагают многопоточность как ускорение. Сервлетный контейнер и так обрабатывает запросы параллельно, а на упирающемся в процессор рендере лишние потоки растягивают каждый запрос, и по таймауту начинают отваливаться сразу все, включая те, что раньше успевали.