parallelStream с блокирующими вызовами тормозит соседние эндпоинты
Для ускорения выгрузки отчёта разработчик заменил обычный стрим на параллельный:
List<ClientReport> reports = clientIds.parallelStream()
.map(id -> externalClient.fetchProfile(id)) // блокирующий HTTP-вызов, 300-800 мс
.collect(Collectors.toList());
После выката отчёт стал быстрее, но выросло время ответа других эндпоинтов сервиса, где тоже используется parallelStream — при этом они с внешним API вообще не работают. Чем это объясняется?
- Все параллельные стримы делят один общий ForkJoinPool, и блокирующие вызовы надолго занимают его немногочисленные потоки
- parallelStream создаёт по потоку на каждый элемент коллекции, поэтому в приложении кончаются потоки операционной системы
- Проблема в том, что итоговый список не потокобезопасен: нужно обернуть вызов collect в synchronized-блок
- Параллельный стрим повышает нагрузку на сборщик мусора, из-за чего весь сервис встаёт на длинные паузы
