Управление кешем

Валидация JSON-схем в Ajv основана на предварительной компиляции схем в исполняемые функции. Основная идея кеширования заключается в том, чтобы избежать повторной компиляции одной и той же схемы при многократной валидации данных. Это критически важно для производительности, особенно в серверных приложениях и высоконагруженных API.

Кеш в Ajv работает на нескольких уровнях:

  • кеширование скомпилированных валидаторов;
  • повторное использование схем по идентификаторам;
  • внутреннее хранение зависимостей между схемами;
  • переиспользование метасхем и подсхем.

Компиляция схемы является дорогой операцией, поэтому Ajv стремится выполнить её ровно один раз на каждую уникальную схему.


Кеш скомпилированных схем

Каждая JSON-схема при первом использовании проходит этап компиляции в JavaScript-функцию. Результат сохраняется внутри экземпляра Ajv.

Если одна и та же схема запрашивается повторно через методы compile или validate, возвращается уже существующая функция из кеша.

Ключевым элементом кеширования является идентификатор схемы:

  • $id (или id в старых версиях);
  • абсолютный URI схемы;
  • внутренний ключ, формируемый Ajv при отсутствии явного идентификатора.

При наличии $id схема становится доступной глобально внутри конкретного экземпляра Ajv и может переиспользоваться через getSchema.


Повторное использование валидаторов

Метод compile(schema) возвращает функцию-валидатор. При повторном вызове с той же схемой:

  • не создаётся новая функция;
  • возвращается ссылка на ранее скомпилированный валидатор;
  • повторно используются все вложенные зависимости схемы.

Метод validate(schemaKey, data) также опирается на кеш: если схема уже была зарегистрирована через addSchema, её валидатор не пересобирается.

Повторное использование особенно эффективно при частой валидации однотипных структур данных (например, DTO в API).


Кеширование через идентификаторы схем

Система идентификации схем играет ключевую роль в механизме кеширования.

$id как ключ кеша

Схемы с $id автоматически регистрируются внутри экземпляра Ajv:

const schema = {
  $id: "userSchema",
  type: "object",
  properties: {
    id: { type: "number" }
  }
};

После добавления:

  • схема доступна через getSchema("userSchema");
  • повторное добавление не приводит к новой компиляции;
  • зависимости, ссылающиеся на $ref, используют кешированный результат.

$ref и переиспользование

При использовании ссылок $ref Ajv не компилирует подсхемы заново. Вместо этого происходит обращение к уже сохранённым валидаторам в кеше.


Управление кешем через API схем

addSchema

Метод addSchema добавляет схему в кеш экземпляра Ajv:

ajv.addSchema(schema);

Поведение:

  • схема компилируется один раз;
  • сохраняется в кеше по $id;
  • становится доступной для $ref.

Если схема уже существует, повторное добавление не пересобирает валидатор, если $id совпадает.


getSchema

Метод getSchema извлекает скомпилированную функцию из кеша:

const validate = ajv.getSchema("userSchema");

Особенности:

  • возвращается именно кешированная функция;
  • повторная компиляция не происходит;
  • используется для прямого вызова без передачи данных через validate.

removeSchema

Удаление схемы из кеша выполняется через removeSchema:

ajv.removeSchema("userSchema");

Последствия удаления:

  • валидатор удаляется из внутреннего кеша;
  • связанные $ref перестают разрешаться;
  • освобождается память, занятая схемой и её зависимостями.

При этом уже полученные ссылки на валидатор продолжают существовать как обычные функции JavaScript.


Очистка кеша и управление памятью

В длительно работающих процессах кеш может накапливать большое количество схем. Для управления этим состоянием используются механизмы очистки.

Очистка неиспользуемых схем

В некоторых конфигурациях Ajv поддерживается удаление неиспользуемых схем:

  • анализируются зависимости между схемами;
  • удаляются схемы, не участвующие в активной валидации;
  • освобождается часть памяти.

Полная очистка кеша

Полная очистка экземпляра Ajv приводит к сбросу всех скомпилированных схем и валидаторов:

  • кеш функций валидаторов уничтожается;
  • $ref перестают работать до повторной регистрации схем;
  • экземпляр возвращается в состояние «пустого компилятора».

Такой подход используется в сценариях с динамической перезагрузкой схем.


Изоляция кеша между экземплярами Ajv

Каждый экземпляр Ajv имеет собственный кеш. Это означает:

  • схемы, добавленные в один экземпляр, недоступны в другом;
  • компиляция дублируется при создании нескольких экземпляров;
  • изоляция предотвращает конфликты между разными наборами схем.
const ajv1 = new Ajv();
const ajv2 = new Ajv();

В этом случае кеши полностью независимы, даже при одинаковых $id.


Влияние опций на кеширование

Некоторые опции Ajv влияют на поведение кеша:

  • schemas при инициализации позволяет предзагрузить кеш;
  • removeAdditional и другие флаги влияют на структуру компиляции;
  • code и source опции могут изменять способ генерации функций, но не принцип кеширования.

Важно учитывать, что изменение опций после компиляции схемы не приводит к пересборке уже закешированного валидатора.


Производительность и стратегическое использование кеша

Эффективность кеширования в Ajv напрямую влияет на производительность:

  • повторная валидация без перекомпиляции работает значительно быстрее;
  • кеш снижает нагрузку на CPU при обработке больших JSON;
  • предварительная регистрация схем уменьшает задержки первого запроса.

Оптимальная стратегия обычно включает:

  • централизованную регистрацию схем при инициализации приложения;
  • избегание динамической пересборки схем в runtime;
  • использование стабильных $id для всех ключевых структур данных.

Типичные проблемы, связанные с кешем

Утечка памяти

При динамическом добавлении большого количества уникальных схем без удаления кеш может расти бесконтрольно.

Конфликты $id

Повторное использование одинаковых $id для разных схем приводит к перезаписи кеша и потенциально некорректной валидации.

Несовместимость зависимостей

Изменение схемы без удаления старой версии из кеша не приводит к обновлению зависимых $ref, что создаёт рассинхронизацию логики.

Неожиданное переиспользование валидаторов

Повторное использование уже скомпилированных функций может приводить к тому, что изменения схемы не отражаются в валидации до очистки кеша или смены $id.