awesome-everything EN
↑ Обратно к восхождению

API

GraphQL N+1: сбатчь и закали API

Суть Практический проект — построй GraphQL API с N+1, докажи это счётчиками резолверов/SQL, сбатчь его DataLoader, закали против атак по форме запроса и подтверди числами до/после.
Высота — путь к senior
НольJuniorMiddleSenior
Ты на senior-высоте — в орбите
◷ 240 min

Читать про N+1 — не то же самое, что смотреть, как лог БД выстреливает 51 раз на один HTTP-запрос, а потом загнать его обратно к 2. Построй небольшой GraphQL API на намеренно вложенных данных, измерь шторм, сбатчь его DataLoader, затем закали против форм запроса, которых DataLoader не касается — с доказательством на каждом шаге.

Цель

Преврати ментальную модель юнита в воспроизводимый цикл: воспроизведи N+1 и докажи его счётчиками SQL/резолверов, почини корректным пер-запросным DataLoader, защити API от depth, complexity и alias-атак и подтверди всё числами до/после.

Проект
0 из 7
Цель

Построй (или возьми) GraphQL API над реляционной схемой с вложенными списками, воспроизведи его шторм N+1 под нагрузкой, схлопни его DataLoader и добавь защиты по форме запроса — доказывая каждый шаг измеренными счётчиками SQL, счётчиками резолверов и задержкой.

Требования
Критерии приёмки
  • Таблица до/после: суммарно SQL-запросов, счётчики вызовов резолверов и p99 задержка для одного и того же запроса на 50 постов под одинаковой нагрузкой — измеренные со стенда, а не оценённые.
  • DataLoader'ы инстанцируются на каждый запрос в context factory (продемонстрировано), а тест доказывает, что инстанс в module scope протёк бы между двумя симулированными tenant'ами или отдал бы устаревшую строку.
  • Тесты контракта batch проходят: dedup возвращает одно обращение к БД для дважды упомянутого автора, а тест строк не в порядке всё равно мапит каждого автора корректно.
  • Три собранных запроса-атаки (глубокий рекурсивный запрос, 5-уровневый запрос с first:100 и документ на 1000 алиасов) каждый отклонены на валидации с названной защитой, которая его поймала.
Senior-стретч
  • Раздели схему на два subgraph'а Apollo Federation (posts и users), подтверди, что router батчит кросс-субграфовые ссылки в один вызов _entities, и покажи, что __resolveReference всё равно нуждается в своём DataLoader, чтобы избежать внутрисубграфового N+1.
  • Реализуй resolver lookahead для одного глубокого пути (posts { author { profile } }), читая info AST и выдавая один JOIN; измерь его против трёх стопкой DataLoader-обращений и отметь компромисс по изоляции.
  • Добавь multi-tenant колонку и докажи, что изоляция tenant'ов принадлежит SQL-фильтру внутри batch-функции, а не только пер-запросному scope — напиши тест, падающий при изоляции только через scope и проходящий с фильтром tenant_id.
  • Подключи CI-гейт, который гоняет запрос на 50 постов против canary и валит сборку, если число вызовов любого type.field-резолвера выросло выше базы (ловя регресс N+1 до релиза).
Итог

Это цикл, который ты запускаешь в каждом реальном инциденте производительности GraphQL: сначала построй стенд доказательств (счётчики SQL и резолверов), воспроизведи и измерь N+1, почини пер-запросным DataLoader, написанным по контракту порядка-и-формы, докажи корректность тестами dedup и строк не в порядке, затем наслои защиты по форме запроса, которые DataLoader не заменяет — depth, мультипликативный complexity, алиас-капы. Подтверди числами до/после под идентичной нагрузкой. Сделав это раз на игрушечном API, ты доводишь production-диагностику до уровня мышечной памяти.

Продолжить восхождение ↑Rate limiting: алгоритмы, всплеск на границе и счётчик в Redis
хоткеи развернуть
поиск
K
пред. пьеса
k
след. пьеса
j
тиры
t
это меню
?
sources3
expand
  1. 01
  2. 02
  3. 03

Trademarks belong to their respective owners. Editorial reference only.