JavaRush /Курси /Модуль 5. Spring /Лекція 292: Групування запитів через Batch Loading

Лекція 292: Групування запитів через Batch Loading

Модуль 5. Spring
Рівень 16 , Лекція 1
Відкрита

Привіт, майбутні майстри GraphQL! Сьогодні зануримось у світ оптимізації GraphQL-запитів і розберемо концепцію Batch Loading. Як часто ви чули, що "GraphQL магічно вирішує всі проблеми"? На жаль, магії немає, зате є потужні інструменти й підходи, які дозволяють підняти продуктивність GraphQL API на новий рівень. І одним із таких інструментів є Batch Loading. Готові? Поїхали!


Що таке Batch Loading?

Коли фронтенд робить запит у GraphQL, він може просити величезну кількість пов'язаних даних. Приклад: ви запитуєте список користувачів, де для кожного користувача потрібен його список постів або інформація про підписників. Для стандартної реалізації це може обернутися десятками, а іноді й сотнями запитів до бази даних.

Batch Loading — це техніка групування всіх таких незалежних запитів в один, щоб зменшити кількість звернень до бази чи інших зовнішніх систем. Це фактично спосіб «завантажити все оптом», а не поштучно.


Чому Batch Loading важливий?

Без Batch Loading ваш GraphQL API може страждати від проблеми, відомої як N+1 Problem. Наприклад, уявімо, що ви запитуєте 10 користувачів, і для кожного потрібно отримати його 10 постів. У гіршому випадку це призведе до:

  • 1 запиту на отримання 10 користувачів.
  • 10 запитів на отримання їхніх постів (по 1 запиту для кожного користувача).

Всього 1 + 10 = 11 запитів, тоді як ми могли б зробити всього 2 великі запити.

Підвищуємо продуктивність

Batch Loading допомагає об'єднати ці 10 окремих запитів в один "батчований" запит до бази даних — результат: менше запитів і помітне підвищення продуктивності.


Інструменти для Batch Loading

У світі GraphQL є кілька популярних бібліотек для реалізації Batch Loading. Найвідоміша з них — DataLoader. Вона надає зручний API для групування й кешування запитів.

Spring GraphQL також підтримує DataLoader "з коробки", тож нам не доведеться винаходити велосипед!


Сценарії, де потрібен Batch Loading

Поглянемо на кілька типових випадків, де Batch Loading особливо корисний:

1. Дані зі спільних джерел

Якщо у вас є кілька запитів, які використовують одне й те саме зовнішнє API або базу даних, Batch Loading — ідеальне рішення. Наприклад:


query {
  users {
    id
    posts {
      id
      title
    }
  }
}

Тут users і їхні posts можна отримати з одного й того ж джерела, групуючи запити.

2. Залежності даних

Коли поля всередині схемы GraphQL взаємопов'язані або залежать одне від одного, використання Batch Loading дозволяє уникнути надмірних запитів.


Практика: Реалізація Batch Loading у Spring GraphQL

Крок 1: Налаштування DataLoader

Щоб почати роботу, спершу додамо залежність graphql-java-dataloader у pom.xml:


<dependency>
    <groupId>com.graphql-java</groupId>
    <artifactId>graphql-java-dataloader</artifactId>
    <version>1.4.0</version>
</dependency>

Крок 2: Створення BatchLoader'а

Створимо клас UserBatchLoader, який буде групувати запити користувачів для їхніх постів:


import org.dataloader.BatchLoader;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

public class UserBatchLoader implements BatchLoader<Long, List<Post>> {

    private final PostService postService; // Припустимо, у нас є PostService

    public UserBatchLoader(PostService postService) {
        this.postService = postService;
    }

    @Override
    public CompletableFuture<List<List<Post>>> load(List<Long> userIds) {
        // Групуємо запити на основі UserId
        return CompletableFuture.supplyAsync(() -<
            userIds.stream()
                   .map(postService::getPostsByUserId) // Отримуємо пости для кожного userId
                   .collect(Collectors.toList())
        );
    }
}

Крок 3: Реєстрація DataLoader

Тепер ми реєструємо наш BatchLoader через DataLoader:


import org.dataloader.DataLoaderRegistry;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

@Component
public class DataLoaderConfig {

    private final PostService postService;

    public DataLoaderConfig(PostService postService) {
        this.postService = postService;
    }

    @Bean
    public DataLoaderRegistry dataLoaderRegistry() {
        DataLoaderRegistry registry = new DataLoaderRegistry();
        // Реєструємо завантажувач
        registry.register("postBatchLoader", DataLoader.newMappedDataLoader(new UserBatchLoader(postService)));
        return registry;
    }
}

Крок 4: Підключення DataLoader до Data Fetcher

Тепер ми повинні підключити наш DataLoader у відповідний Data Fetcher:


import org.dataloader.DataLoader;
import org.springframework.stereotype.Component;

@Component
public class UserGraphQLDataFetcher {

    public CompletableFuture<List<Post>> getPosts(DataLoader<Long, List<Post>> postDataLoader, User user) {
        return postDataLoader.load(user.getId()); // Використовуємо DataLoader для завантаження
    }
}

Крок 5: Тестування

Щоб побачити, як працює Batch Loading, виконайте GraphQL-запит:


query {
  users {
    id
    name
    posts {
      id
      title
    }
  }
}

Тепер ви помітите, що замість N окремих запитів база даних отримує 1 згрупований запит для всіх користувачів.


Як уникнути типових помилок?

Початківці часто стикаються з проблемами, пов'язаними з некоректним налаштуванням BatchLoader'ів. Ось кілька порад:

  1. Не забувайте кешувати дані. DataLoader вміє це робити "з коробки", тому не пишіть власні кеші.
  2. Асинхронність — ваше все. Навіть якщо DataLoader працює в синхронному режимі, намагайтесь використовувати CompletableFuture.
  3. Не використовуйте Batch Loading для всього підряд. Якщо запит простий і не потребує групування, додавайте DataLoader лише там, де це виправдано.

Переваги Batch Loading

  • Скорочення кількості запитів: мінімізація звернень до бази даних або зовнішніх API.
  • Покращення продуктивності: зменшення часу затримок.
  • Простота управління залежностями даних: DataLoader піклується про групування даних за вас.
  • Підвищення масштабованості: зменшення навантаження на сервер у високонавантажених системах.

Ось і все на сьогодні! Тепер ви знаєте, як використовувати Batch Loading для оптимізації ваших GraphQL API. І найголовніше — ви зможете пояснити колегам, чому їхній додаток гальмує без DataLoader (і майстерно запропонувати свою допомогу). Удачі в оптимізації API, кодери!

Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ