Как построить отчет из тысячи страниц для ускорения его формирования
Что проверяют
Умеете ли вы искать узкое место, а не сразу хвататься за потоки. Отчёт на тысячу страниц обычно тормозит из-за запросов и памяти, и интервьюер ждёт, что вы сначала спросите, куда уходит время. Следом часто спрашивают, что делать, если отчёт падает с OutOfMemoryError.
Как отвечать
Начните с профилирования: замерьте отдельно запрос, обработку и рендеринг, посмотрите на GC через JFR или async-profiler. Дальше решения по слоям:
- база: агрегируйте в SQL, а не в Java. Читайте потоком: в драйвере PostgreSQL
setFetchSizeвключает серверный курсор только при выключенном autocommit. ВместоOFFSETиспользуйте keyset-пагинацию по индексу; - память: не собирайте все строки в
List, обрабатывайте их курсором или черезStreamв Spring Data, закрывая его вtry-with-resources; - Excel:
SXSSFWorkbookиз Apache POI держит в памяти только окно строк (по умолчанию 100), остальное сбрасывает на диск. ОбычныйXSSFWorkbookна сотнях тысяч строк съедает гигабайты; - PDF: JasperReports с виртуализатором (
JRSwapFileVirtualizer) выгружает готовые страницы из памяти, а при ручной сборке через OpenPDF страницы пишутся в поток по мере готовности; - архитектура: такой отчёт делают асинхронно. Пользователь получает id задачи, отчёт собирается в фоне, файл кладётся в хранилище, по готовности приходит ссылка. Долгий HTTP-запрос оборвёт прокси по таймауту;
- параллелизм: параллельно готовят независимые блоки данных, а запись в один документ остаётся последовательной.
Если данные за закрытые периоды не меняются, их заранее предагрегируют в витрину.
Где спотыкаются
Отправляют тысячу страниц в ExecutorService по задаче на страницу. Страницы зависят друг от друга (нумерация, промежуточные итоги, переносы таблиц), а объект документа не потокобезопасен.
Грузят весь результат в память и получают OOM. Проблема не в скорости генератора, а в том, что десятки мегабайт строк превращаются в гигабайты объектов.
Кешируют в Redis разовый отчёт. Кеш помогает при повторных запросах одних и тех же данных, а тысячестраничный отчёт с уникальными параметрами всё равно считается заново.